<commit_before>/*
 * loquat-monad / monad.js
 * copyright (c) 2016 Susisu
 */

/**
 * @module monad
 */

"use strict";

module.exports = _core => {
    function end() {
        return Object.freeze({
            forever,
            voidM,
            join,
            when,
            unless,
            liftM,
            liftM2,
            liftM3,
            liftM4,
            liftM5,
            ltor,
            rtol,
            sequence,
            sequence_,
            mapM,
            mapM_
        });
    }

    const ParseError = _core.ParseError;
    const Result     = _core.Result;
    const Parser     = _core.Parser;
    const lazy       = _core.lazy;

    const _prim = require("loquat-prim")(_core);
    const map  = _prim.map;
    const pure = _prim.pure;
    const bind = _prim.bind;
    const then = _prim.then;

    /**
     * @function module:monad.forever
     * @static
     * @param {AbstractParser} parser
     * @returns {AbstractParser}
     */
    function forever(parser) {
        const rec = lazy(() => then(parser, rec));
        return rec;
    }

    /**
     * @function module:monad.voidM
     * @static
     * @param {AbstractParser} parser
     * @returns {AbstractParser}
     */
    function voidM(parser) {
        return map(parser, () => undefined);
    }

    /**
     * @function module:monad.join
     * @static
     * @param {AbstractParser} parser
     * @returns {AbstractParser}
     */
    function join(parser) {
        return bind(parser, val => val);
    }

    /**
     * @function module:monad.when
     * @static
     * @param {boolean} flag
     * @param {AbstractParser} parser
     * @returns {AbstractParser}
     */
    function when(flag, parser) {
        return flag ? parser : pure(undefined);
    }

    /**
     * @function module:monad.unless
     * @static
     * @param {boolean} flag
     * @param {AbstractParser} parser
     * @returns {AbstractParser}
     */
    function unless(flag, parser) {
        return flag ? pure(undefined) : parser;
    }

    /**
     * @function module:monad.liftM
     * @static
     * @param {function} func
     * @returns {function}
     */
    function liftM(func) {
        return parser => bind(parser, val => pure(func(val)));
    }

    /**
     * @function module:monad.liftM2
     * @static
     * @param {function} func
     * @returns {function}
     */
    function liftM2(func) {
        return (parserA, parserB) =>
            bind(parserA, valA =>
                bind(parserB, valB =>
                    pure(func(valA, valB))
                )
            );
    }

    /**
     * @function module:monad.liftM3
     * @static
     * @param {function} func
     * @returns {function}
     */
    function liftM3(func) {
        return (parserA, parserB, parserC) =>
            bind(parserA, valA =>
                bind(parserB, valB =>
                    bind(parserC, valC =>
                        pure(func(valA, valB, valC))
                    )
                )
            );
    }

    /**
     * @function module:monad.liftM4
     * @static
     * @param {function} func
     * @returns {function}
     */
    function liftM4(func) {
        return (parserA, parserB, parserC, parserD) =>
            bind(parserA, valA =>
                bind(parserB, valB =>
                    bind(parserC, valC =>
                        bind(parserD, valD =>
                            pure(func(valA, valB, valC, valD))
                        )
                    )
                )
            );
    }

    /**
     * @function module:monad.liftM5
     * @static
     * @param {function} func
     * @returns {function}
     */
    function liftM5(func) {
        return (parserA, parserB, parserC, parserD, parserE) =>
            bind(parserA, valA =>
                bind(parserB, valB =>
                    bind(parserC, valC =>
                        bind(parserD, valD =>
                            bind(parserE, valE =>
                                pure(func(valA, valB, valC, valD, valE))
                            )
                        )
                    )
                )
            );
    }

    /**
     * @function module:monad.ltor
     * @static
     * @param {function} funcA
     * @param {function} funcB
     * @returns {function}
     */
    function ltor(funcA, funcB) {
        return val => bind(funcA(val), funcB);
    }

    /**
     * @function module:monad.rtol
     * @static
     * @param {function} funcA
     * @param {function} funcB
     * @returns {function}
     */
    function rtol(funcA, funcB) {
        return val => bind(funcB(val), funcA);
    }

    /**
     * @function module:monad.sequence
     * @static
     * @param {Array.<AbstractParser>} parsers
     * @returns {AbstractParser}
     */
    function sequence(parsers) {
        return new Parser(state => {
            const accum = [];
            let currentState = state;
            let currentErr = ParseError.unknown(state.pos);
            let consumed = false;
            for (const parser of parsers) {
                const res = parser.run(currentState);
                if (res.succeeded) {
                    if (res.consumed) {
                        consumed = true;
                        accum.push(res.val);
                        currentState = res.state;
                        currentErr = res.err;
                    }
                    else {
                        accum.push(res.val);
                        currentState = res.state;
                        currentErr = ParseError.merge(currentErr, res.err);
                    }
                }
                else {
                    return res.consumed
                        ? res
                        : Result.eerr(ParseError.merge(currentErr, res.err));
                }
            }
            return consumed
                ? Result.csuc(currentErr, accum, currentState)
                : Result.esuc(currentErr, accum, currentState);
        });
    }

    /**
     * @function module:monad.sequence
     * @static
     * @param {Array.<AbstractParser>} parsers
     * @returns {AbstractParser}
     */
    function sequence_(parsers) {
        return parsers.reduceRight((accum, parser) => then(parser, accum), pure(undefined));
    }

    /**
     * @function module:monad.mapM
     * @static
     * @param {function} func
     * @param {Array.<AbstractParser>} parsers
     * @returns {AbstractParser}
     */
    function mapM(func, parsers) {
        return sequence(parsers.map(parser => func(parser)));
    }

    /**
     * @function module:monad.mapM_
     * @static
     * @param {function} func
     * @param {Array.<AbstractParser>} parsers
     * @returns {AbstractParser}
     */
    function mapM_(func, parsers) {
        return sequence_(parsers.map(parser => func(parser)));
    }

    return end();
};
<commit_msg>[monad] Add `forM()`<commit_after>/*
 * loquat-monad / monad.js
 * copyright (c) 2016 Susisu
 */

/**
 * @module monad
 */

"use strict";

module.exports = _core => {
    function end() {
        return Object.freeze({
            forever,
            voidM,
            join,
            when,
            unless,
            liftM,
            liftM2,
            liftM3,
            liftM4,
            liftM5,
            ltor,
            rtol,
            sequence,
            sequence_,
            mapM,
            mapM_,
            forM
        });
    }

    const ParseError = _core.ParseError;
    const Result     = _core.Result;
    const Parser     = _core.Parser;
    const lazy       = _core.lazy;

    const _prim = require("loquat-prim")(_core);
    const map  = _prim.map;
    const pure = _prim.pure;
    const bind = _prim.bind;
    const then = _prim.then;

    /**
     * @function module:monad.forever
     * @static
     * @param {AbstractParser} parser
     * @returns {AbstractParser}
     */
    function forever(parser) {
        const rec = lazy(() => then(parser, rec));
        return rec;
    }

    /**
     * @function module:monad.voidM
     * @static
     * @param {AbstractParser} parser
     * @returns {AbstractParser}
     */
    function voidM(parser) {
        return map(parser, () => undefined);
    }

    /**
     * @function module:monad.join
     * @static
     * @param {AbstractParser} parser
     * @returns {AbstractParser}
     */
    function join(parser) {
        return bind(parser, val => val);
    }

    /**
     * @function module:monad.when
     * @static
     * @param {boolean} flag
     * @param {AbstractParser} parser
     * @returns {AbstractParser}
     */
    function when(flag, parser) {
        return flag ? parser : pure(undefined);
    }

    /**
     * @function module:monad.unless
     * @static
     * @param {boolean} flag
     * @param {AbstractParser} parser
     * @returns {AbstractParser}
     */
    function unless(flag, parser) {
        return flag ? pure(undefined) : parser;
    }

    /**
     * @function module:monad.liftM
     * @static
     * @param {function} func
     * @returns {function}
     */
    function liftM(func) {
        return parser => bind(parser, val => pure(func(val)));
    }

    /**
     * @function module:monad.liftM2
     * @static
     * @param {function} func
     * @returns {function}
     */
    function liftM2(func) {
        return (parserA, parserB) =>
            bind(parserA, valA =>
                bind(parserB, valB =>
                    pure(func(valA, valB))
                )
            );
    }

    /**
     * @function module:monad.liftM3
     * @static
     * @param {function} func
     * @returns {function}
     */
    function liftM3(func) {
        return (parserA, parserB, parserC) =>
            bind(parserA, valA =>
                bind(parserB, valB =>
                    bind(parserC, valC =>
                        pure(func(valA, valB, valC))
                    )
                )
            );
    }

    /**
     * @function module:monad.liftM4
     * @static
     * @param {function} func
     * @returns {function}
     */
    function liftM4(func) {
        return (parserA, parserB, parserC, parserD) =>
            bind(parserA, valA =>
                bind(parserB, valB =>
                    bind(parserC, valC =>
                        bind(parserD, valD =>
                            pure(func(valA, valB, valC, valD))
                        )
                    )
                )
            );
    }

    /**
     * @function module:monad.liftM5
     * @static
     * @param {function} func
     * @returns {function}
     */
    function liftM5(func) {
        return (parserA, parserB, parserC, parserD, parserE) =>
            bind(parserA, valA =>
                bind(parserB, valB =>
                    bind(parserC, valC =>
                        bind(parserD, valD =>
                            bind(parserE, valE =>
                                pure(func(valA, valB, valC, valD, valE))
                            )
                        )
                    )
                )
            );
    }

    /**
     * @function module:monad.ltor
     * @static
     * @param {function} funcA
     * @param {function} funcB
     * @returns {function}
     */
    function ltor(funcA, funcB) {
        return val => bind(funcA(val), funcB);
    }

    /**
     * @function module:monad.rtol
     * @static
     * @param {function} funcA
     * @param {function} funcB
     * @returns {function}
     */
    function rtol(funcA, funcB) {
        return val => bind(funcB(val), funcA);
    }

    /**
     * @function module:monad.sequence
     * @static
     * @param {Array.<AbstractParser>} parsers
     * @returns {AbstractParser}
     */
    function sequence(parsers) {
        return new Parser(state => {
            const accum = [];
            let currentState = state;
            let currentErr = ParseError.unknown(state.pos);
            let consumed = false;
            for (const parser of parsers) {
                const res = parser.run(currentState);
                if (res.succeeded) {
                    if (res.consumed) {
                        consumed = true;
                        accum.push(res.val);
                        currentState = res.state;
                        currentErr = res.err;
                    }
                    else {
                        accum.push(res.val);
                        currentState = res.state;
                        currentErr = ParseError.merge(currentErr, res.err);
                    }
                }
                else {
                    return res.consumed
                        ? res
                        : Result.eerr(ParseError.merge(currentErr, res.err));
                }
            }
            return consumed
                ? Result.csuc(currentErr, accum, currentState)
                : Result.esuc(currentErr, accum, currentState);
        });
    }

    /**
     * @function module:monad.sequence
     * @static
     * @param {Array.<AbstractParser>} parsers
     * @returns {AbstractParser}
     */
    function sequence_(parsers) {
        return parsers.reduceRight((accum, parser) => then(parser, accum), pure(undefined));
    }

    /**
     * @function module:monad.mapM
     * @static
     * @param {function} func
     * @param {Array.<AbstractParser>} parsers
     * @returns {AbstractParser}
     */
    function mapM(func, parsers) {
        return sequence(parsers.map(parser => func(parser)));
    }

    /**
     * @function module:monad.mapM_
     * @static
     * @param {function} func
     * @param {Array.<AbstractParser>} parsers
     * @returns {AbstractParser}
     */
    function mapM_(func, parsers) {
        return sequence_(parsers.map(parser => func(parser)));
    }

    /**
     * @function module:monad.forM
     * @static
     * @param {Array.<AbstractParser>} parsers
     * @param {function} func
     * @returns {AbstractParser}
     */
    function forM(parsers, func) {
        return mapM(func, parsers);
    }

    return end();
};
<|endoftext|>


<commit_before>var recipes = null;
var recipe_images = null;
var favs = [];

Storage.prototype.setObj = function(key, obj) {
  return this.setItem(key, JSON.stringify(obj))
}
Storage.prototype.getObj = function(key) {
  return JSON.parse(this.getItem(key))
}
<commit_msg>Add deviceready var <commit_after>var recipes = null;
var recipe_images = null;
var favs = [];
var intervalReadyID = null;

Storage.prototype.setObj = function(key, obj) {
  return this.setItem(key, JSON.stringify(obj))
}
Storage.prototype.getObj = function(key) {
  return JSON.parse(this.getItem(key))
}
<|endoftext|>


<commit_before>importScripts('js/serviceworker-cache-polyfill.js');

var CACHE_NAME = 'moz-gdc';
var CACHE_VERSION = 2;
var CACHE_KEY = CACHE_NAME + '-v' + CACHE_VERSION;

self.onactivate = function (event) {
  caches.keys().then(function (cacheNames) {
    return Promise.all(
      cacheNames.map(function (cacheName) {
        if (cacheName.indexOf(CACHE_NAME) === -1) {
          return;
        }

        // If this cache name isn't the expected cache name, delete it.
        if (cacheName !== CACHE_KEY) {
          console.log('Deleting out of cache:', cacheName);
          return caches.delete(cacheName);
        }
      })
    );
  });
};

self.onfetch = function (event) {
  var request = event.request;

  event.respondWith(

    // Check the cache for a hit.
    caches.match(request).then(function (response) {

      if (response) {
        // If there is an entry in the cache for `event.request`, then response
        // will be defined and we can just return it. Notice we are caching
        // *all* resources here.
        console.log('  Found response in cache:', response);
        return response;
      }

      // Otherwise, if there is no entry in the cache for `event.request`,
      // response will be `undefined`, and we need to `fetch()` the resource.
      console.log('  No response for %s found in cache. Fetching from network:',
                  event.request.url);

      // We call .clone() on the request since we might use it in a call to
      // `cache.put()` later on. Both `fetch() and `cache.put()` "consume"
      // the request, so we need to make a copy.
      // (See https://fetch.spec.whatwg.org/#dom-request-clone)
      return fetch(event.request).then(function (response) {
        console.log('    Response for %s from network: %O',
                    event.request.url, response);

        if (event.request.url.substr(-6) !== '/sw.js' && response.status < 400) {
          // This avoids caching responses that we know are errors (i.e.,
          // HTTP status codes of 4xx or 5xx). Note that for opaque filtered
          // responses (https://fetch.spec.whatwg.org/#concept-filtered-response-opaque)
          // we can't access to the response headers, so this check will
          // always fail and the font won't be cached. We call .clone() on
          // the response to save a copy of it to the cache. By doing so, we
          // get to keep the original response object which we will return
          // back to the controlled page.
          // (See https://fetch.spec.whatwg.org/#dom-response-clone)
          caches.open(CACHE_KEY).then(function (cache) {
            console.log('    Caching the response to', event.request.url);
            return cache.put(event.request, response.clone());
          }).catch(function (err) {
            // Likely we got an opaque response which the polyfill can't deal
            // with, so show a warning.
            console.warn('    Could not cache ' + requestURL + ': ' +
                         err.message);
          });
        } else {
          console.log('    Not caching the response to', event.request.url);
        }

        // Return the original response object, which will be used to fulfill
        // the resource request.
        return response;
      });

    })
  );
};
<commit_msg>bump ServiceWorker<commit_after>importScripts('js/serviceworker-cache-polyfill.js');

var CACHE_NAME = 'moz-gdc';
var CACHE_VERSION = 3;
var CACHE_KEY = CACHE_NAME + '-v' + CACHE_VERSION;

self.onactivate = function (event) {
  caches.keys().then(function (cacheNames) {
    return Promise.all(
      cacheNames.map(function (cacheName) {
        if (cacheName.indexOf(CACHE_NAME) === -1) {
          return;
        }

        // If this cache name isn't the expected cache name, delete it.
        if (cacheName !== CACHE_KEY) {
          console.log('Deleting out of cache:', cacheName);
          return caches.delete(cacheName);
        }
      })
    );
  });
};

self.onfetch = function (event) {
  var request = event.request;

  event.respondWith(

    // Check the cache for a hit.
    caches.match(request).then(function (response) {

      if (response) {
        // If there is an entry in the cache for `event.request`, then response
        // will be defined and we can just return it. Notice we are caching
        // *all* resources here.
        console.log('  Found response in cache:', response);
        return response;
      }

      // Otherwise, if there is no entry in the cache for `event.request`,
      // response will be `undefined`, and we need to `fetch()` the resource.
      console.log('  No response for %s found in cache. Fetching from network:',
                  event.request.url);

      // We call .clone() on the request since we might use it in a call to
      // `cache.put()` later on. Both `fetch() and `cache.put()` "consume"
      // the request, so we need to make a copy.
      // (See https://fetch.spec.whatwg.org/#dom-request-clone)
      return fetch(event.request).then(function (response) {
        console.log('    Response for %s from network: %O',
                    event.request.url, response);

        if (event.request.url.substr(-6) !== '/sw.js' && response.status < 400) {
          // This avoids caching responses that we know are errors (i.e.,
          // HTTP status codes of 4xx or 5xx). Note that for opaque filtered
          // responses (https://fetch.spec.whatwg.org/#concept-filtered-response-opaque)
          // we can't access to the response headers, so this check will
          // always fail and the font won't be cached. We call .clone() on
          // the response to save a copy of it to the cache. By doing so, we
          // get to keep the original response object which we will return
          // back to the controlled page.
          // (See https://fetch.spec.whatwg.org/#dom-response-clone)
          caches.open(CACHE_KEY).then(function (cache) {
            console.log('    Caching the response to', event.request.url);
            return cache.put(event.request, response.clone());
          }).catch(function (err) {
            // Likely we got an opaque response which the polyfill can't deal
            // with, so show a warning.
            console.warn('    Could not cache ' + requestURL + ': ' +
                         err.message);
          });
        } else {
          console.log('    Not caching the response to', event.request.url);
        }

        // Return the original response object, which will be used to fulfill
        // the resource request.
        return response;
      });

    })
  );
};
<|endoftext|>


<commit_before>import { BodyComponent } from 'mjml-core'
import { flow, identity, join, filter } from 'lodash/fp'

import widthParser from 'mjml-core/lib/helpers/widthParser'

const makeBackgroundString = flow(filter(identity), join(' '))
export default class MjSection extends BodyComponent {
  static allowedAttributes = {
    'background-color': 'color',
    'background-url': 'string',
    'background-repeat': 'enum(repeat/no-repeat)',
    'background-size': 'string',
    border: 'string',
    'border-bottom': 'string',
    'border-left': 'string',
    'border-radius': 'string',
    'border-right': 'string',
    'border-top': 'string',
    direction: 'enum(ltr,rtl)',
    'full-width': 'enum(full-width)',
    padding: 'unit(px,%){1,4}',
    'padding-top': 'unit(px,%)',
    'padding-bottom': 'unit(px,%)',
    'padding-left': 'unit(px,%)',
    'padding-right': 'unit(px,%)',
    'text-align': 'enum(left,center,right)',
    'text-padding': 'unit(px,%){1,4}',
    'vertical-align': 'enum(bottom,middle,top)',
  }

  static defaultAttributes = {
    'background-repeat': 'repeat',
    'background-size': 'auto',
    direction: 'ltr',
    padding: '20px 0',
    'text-align': 'center',
    'text-padding': '4px 4px 4px 0',
    'vertical-align': 'top',
  }

  getChildContext() {
    const { containerWidth } = this.context

    const paddingSize =
      this.getShorthandAttrValue('padding', 'left') +
      this.getShorthandAttrValue('padding', 'right')

    const { parsedWidth } = widthParser(containerWidth, {
      parseFloatToInt: false,
    })

    return {
      ...this.context,
      containerWidth: `${parsedWidth - paddingSize}px`,
    }
  }

  getStyles() {
    const { containerWidth } = this.context

    const fullWidth = this.isFullWidth()

    const background = this.getAttribute('background-url')
      ? { background: this.getBackground() }
      : {
          background: this.getAttribute('background-color'),
          'background-color': this.getAttribute('background-color'),
        }

    return {
      tableFullwidth: {
        ...(fullWidth ? background : {}),
        width: '100%',
        'border-radius': this.getAttribute('border-radius'),
      },
      table: {
        ...(fullWidth ? {} : background ),
        width: '100%',
        'border-radius': this.getAttribute('border-radius'),
      },
      td: {
        border: this.getAttribute('border'),
        'border-bottom': this.getAttribute('border-bottom'),
        'border-left': this.getAttribute('border-left'),
        'border-right': this.getAttribute('border-right'),
        'border-top': this.getAttribute('border-top'),
        direction: this.getAttribute('direction'),
        'font-size': '0px',
        padding: this.getAttribute('padding'),
        'padding-bottom': this.getAttribute('padding-bottom'),
        'padding-left': this.getAttribute('padding-left'),
        'padding-right': this.getAttribute('padding-right'),
        'padding-top': this.getAttribute('padding-top'),
        'text-align': this.getAttribute('text-align'),
        'vertical-align': this.getAttribute('vertical-align'),
      },
      div: {
        ...(fullWidth ? {} : background),
        Margin: '0px auto',
        'border-radius': this.getAttribute('border-radius'),
        'max-width': containerWidth,
      },
      innerDiv: {
        'line-height': '0',
        'font-size': '0',
      },
    }
  }

  getBackground = () =>
    makeBackgroundString([
      this.getAttribute('background-color'),
      ...(this.hasBackground()
        ? [
            `url(${this.getAttribute('background-url')})`,
            `top center / ${this.getAttribute('background-size')}`,
            this.getAttribute('background-repeat'),
          ]
        : []),
    ])

  hasBackground() {
    return this.getAttribute('background-url') != null
  }

  isFullWidth() {
    return this.getAttribute('full-width') === 'full-width'
  }

  renderBefore() {
    const { containerWidth } = this.context

    return `

    `
  }

  renderAfter() {
    // eslint-disable-line class-methods-use-this
    return `

    `
  }

  renderWrappedChildren() {
    const { children } = this.props

    return `

      ${this.renderChildren(children, {
        renderer: component =>
          component.rawElement
            ? component.render()
            : `

            ${component.render()}

    `,
      })}

    `
  }

  renderWithBackground(content) {
    const fullWidth = this.isFullWidth()

    const { containerWidth } = this.context

    return `

          ${content}

    `
  }

  renderSection() {
    const hasBackground = this.hasBackground()

    return `

        ${hasBackground
          ? `<div ${this.htmlAttributes({ style: 'innerDiv' })}>`
          : ''}

                  ${this.renderWrappedChildren()}

        ${hasBackground ? '
' : ''}

    `
  }

  renderFullWidth() {
    const content = this.hasBackground()
      ? this.renderWithBackground(`
        ${this.renderBefore()}
        ${this.renderSection()}
        ${this.renderAfter()}
      `)
      : `
        ${this.renderBefore()}
        ${this.renderSection()}
        ${this.renderAfter()}
      `

    return `

              ${content}

    `
  }

  renderSimple() {
    const section = this.renderSection()

    return `
      ${this.renderBefore()}
      ${this.hasBackground() ? this.renderWithBackground(section) : section}
      ${this.renderAfter()}
    `
  }

  render() {
    return this.isFullWidth() ? this.renderFullWidth() : this.renderSimple()
  }
}
<commit_msg>remove trailing space<commit_after>import { BodyComponent } from 'mjml-core'
import { flow, identity, join, filter } from 'lodash/fp'

import widthParser from 'mjml-core/lib/helpers/widthParser'

const makeBackgroundString = flow(filter(identity), join(' '))
export default class MjSection extends BodyComponent {
  static allowedAttributes = {
    'background-color': 'color',
    'background-url': 'string',
    'background-repeat': 'enum(repeat/no-repeat)',
    'background-size': 'string',
    border: 'string',
    'border-bottom': 'string',
    'border-left': 'string',
    'border-radius': 'string',
    'border-right': 'string',
    'border-top': 'string',
    direction: 'enum(ltr,rtl)',
    'full-width': 'enum(full-width)',
    padding: 'unit(px,%){1,4}',
    'padding-top': 'unit(px,%)',
    'padding-bottom': 'unit(px,%)',
    'padding-left': 'unit(px,%)',
    'padding-right': 'unit(px,%)',
    'text-align': 'enum(left,center,right)',
    'text-padding': 'unit(px,%){1,4}',
    'vertical-align': 'enum(bottom,middle,top)',
  }

  static defaultAttributes = {
    'background-repeat': 'repeat',
    'background-size': 'auto',
    direction: 'ltr',
    padding: '20px 0',
    'text-align': 'center',
    'text-padding': '4px 4px 4px 0',
    'vertical-align': 'top',
  }

  getChildContext() {
    const { containerWidth } = this.context

    const paddingSize =
      this.getShorthandAttrValue('padding', 'left') +
      this.getShorthandAttrValue('padding', 'right')

    const { parsedWidth } = widthParser(containerWidth, {
      parseFloatToInt: false,
    })

    return {
      ...this.context,
      containerWidth: `${parsedWidth - paddingSize}px`,
    }
  }

  getStyles() {
    const { containerWidth } = this.context

    const fullWidth = this.isFullWidth()

    const background = this.getAttribute('background-url')
      ? { background: this.getBackground() }
      : {
          background: this.getAttribute('background-color'),
          'background-color': this.getAttribute('background-color'),
        }

    return {
      tableFullwidth: {
        ...(fullWidth ? background : {}),
        width: '100%',
        'border-radius': this.getAttribute('border-radius'),
      },
      table: {
        ...(fullWidth ? {} : background),
        width: '100%',
        'border-radius': this.getAttribute('border-radius'),
      },
      td: {
        border: this.getAttribute('border'),
        'border-bottom': this.getAttribute('border-bottom'),
        'border-left': this.getAttribute('border-left'),
        'border-right': this.getAttribute('border-right'),
        'border-top': this.getAttribute('border-top'),
        direction: this.getAttribute('direction'),
        'font-size': '0px',
        padding: this.getAttribute('padding'),
        'padding-bottom': this.getAttribute('padding-bottom'),
        'padding-left': this.getAttribute('padding-left'),
        'padding-right': this.getAttribute('padding-right'),
        'padding-top': this.getAttribute('padding-top'),
        'text-align': this.getAttribute('text-align'),
        'vertical-align': this.getAttribute('vertical-align'),
      },
      div: {
        ...(fullWidth ? {} : background),
        Margin: '0px auto',
        'border-radius': this.getAttribute('border-radius'),
        'max-width': containerWidth,
      },
      innerDiv: {
        'line-height': '0',
        'font-size': '0',
      },
    }
  }

  getBackground = () =>
    makeBackgroundString([
      this.getAttribute('background-color'),
      ...(this.hasBackground()
        ? [
            `url(${this.getAttribute('background-url')})`,
            `top center / ${this.getAttribute('background-size')}`,
            this.getAttribute('background-repeat'),
          ]
        : []),
    ])

  hasBackground() {
    return this.getAttribute('background-url') != null
  }

  isFullWidth() {
    return this.getAttribute('full-width') === 'full-width'
  }

  renderBefore() {
    const { containerWidth } = this.context

    return `

    `
  }

  renderAfter() {
    // eslint-disable-line class-methods-use-this
    return `

    `
  }

  renderWrappedChildren() {
    const { children } = this.props

    return `

      ${this.renderChildren(children, {
        renderer: component =>
          component.rawElement
            ? component.render()
            : `

            ${component.render()}

    `,
      })}

    `
  }

  renderWithBackground(content) {
    const fullWidth = this.isFullWidth()

    const { containerWidth } = this.context

    return `

          ${content}

    `
  }

  renderSection() {
    const hasBackground = this.hasBackground()

    return `

        ${hasBackground
          ? `<div ${this.htmlAttributes({ style: 'innerDiv' })}>`
          : ''}

                  ${this.renderWrappedChildren()}

        ${hasBackground ? '
' : ''}

    `
  }

  renderFullWidth() {
    const content = this.hasBackground()
      ? this.renderWithBackground(`
        ${this.renderBefore()}
        ${this.renderSection()}
        ${this.renderAfter()}
      `)
      : `
        ${this.renderBefore()}
        ${this.renderSection()}
        ${this.renderAfter()}
      `

    return `

              ${content}

    `
  }

  renderSimple() {
    const section = this.renderSection()

    return `
      ${this.renderBefore()}
      ${this.hasBackground() ? this.renderWithBackground(section) : section}
      ${this.renderAfter()}
    `
  }

  render() {
    return this.isFullWidth() ? this.renderFullWidth() : this.renderSimple()
  }
}
<|endoftext|>


<commit_before>import { BodyComponent } from 'mjml-core'

export default class MjSocial extends BodyComponent {
  // static allowedAttributes = {
  //   align: 'enum(left,right,center)',
  //   'border-radius': 'unit(px)',
  //   'container-background-color': 'color',
  //   color: 'color',
  //   'font-family': 'string',
  //   'font-size': 'unit(px,%)',
  //   'font-style': 'string',
  //   'font-weight': 'string',
  //   'inner-padding': 'unit(px,%)',
  //   'line-height': 'unit(px,%)',
  //   mode: 'enum(horizontal,vertical)',
  //   'padding-bottom': 'unit(px,%)',
  //   'padding-left': 'unit(px,%)',
  //   'padding-right': 'unit(px,%)',
  //   'padding-top': 'unit(px,%)',
  //   padding: 'unit(px,%){1,4}',
  //   'table-layout': 'enum(auto,fixed)',
  //   'vertical-align': 'enum(top,bottom,middle)',
  // }

  static defaultAttributes = {
    align: 'center',
    'border-radius': '3px',
    color: '#333333',
    'font-family': 'Ubuntu, Helvetica, Arial, sans-serif',
    'font-size': '13px',
    'icon-size': '20px',
    'inner-padding': null,
    'line-height': '22px',
    mode: 'horizontal',
    padding: '10px 25px',
    'text-decoration': 'none',
  }

  getStyles() {
    return {
      tableVertical: {
        'line-height': this.getAttribute('line-height'),
        margin: '0px',
      },
    }
  }

  getSocialElementAttributes() {
    return [
      'border-radius',
      'color',
      'font-family',
      'font-size',
      'font-weight',
      'icon-size',
      'inner-padding',
      'line-height',
    ].reduce((res, attr) => {
      res[attr] = this.getAttribute(attr)
      return res
    }, {})
  }

  renderHorizontal() {
    const { children } = this.props

    return `

      ${this.renderChildren(children, {
        attributes: this.getSocialElementAttributes(),
        renderer: component => `

                ${component.render()}

          `,
      })}

    `
  }

  renderVertical() {
    const { children } = this.props

    return `

        ${this.renderChildren(children, {
          attributes: this.getSocialElementAttributes(),
        })}

    `
  }

  render() {
    return `
      ${this.getAttribute('mode') === 'horizontal'
        ? this.renderHorizontal()
        : this.renderVertical()}
    `
  }
}
<commit_msg>Final fix<commit_after>import { BodyComponent } from 'mjml-core'

export default class MjSocial extends BodyComponent {
  // static allowedAttributes = {
  //   align: 'enum(left,right,center)',
  //   'border-radius': 'unit(px)',
  //   'container-background-color': 'color',
  //   color: 'color',
  //   'font-family': 'string',
  //   'font-size': 'unit(px,%)',
  //   'font-style': 'string',
  //   'font-weight': 'string',
  //   'inner-padding': 'unit(px,%)',
  //   'line-height': 'unit(px,%)',
  //   mode: 'enum(horizontal,vertical)',
  //   'padding-bottom': 'unit(px,%)',
  //   'padding-left': 'unit(px,%)',
  //   'padding-right': 'unit(px,%)',
  //   'padding-top': 'unit(px,%)',
  //   padding: 'unit(px,%){1,4}',
  //   'table-layout': 'enum(auto,fixed)',
  //   'vertical-align': 'enum(top,bottom,middle)',
  // }

  static defaultAttributes = {
    align: 'center',
    'border-radius': '3px',
    color: '#333333',
    'font-family': 'Ubuntu, Helvetica, Arial, sans-serif',
    'font-size': '13px',
    'icon-size': '20px',
    'inner-padding': null,
    'line-height': '22px',
    mode: 'horizontal',
    padding: '10px 25px',
    'text-decoration': 'none',
  }

  getStyles() {
    return {
      tableVertical: {
        margin: '0px',
      },
    }
  }

  getSocialElementAttributes() {
    return [
      'border-radius',
      'color',
      'font-family',
      'font-size',
      'font-weight',
      'icon-size',
      'inner-padding',
      'line-height',
    ].reduce((res, attr) => {
      res[attr] = this.getAttribute(attr)
      return res
    }, {})
  }

  renderHorizontal() {
    const { children } = this.props

    return `

      ${this.renderChildren(children, {
        attributes: this.getSocialElementAttributes(),
        renderer: component => `

                ${component.render()}

          `,
      })}

    `
  }

  renderVertical() {
    const { children } = this.props

    return `

        ${this.renderChildren(children, {
          attributes: this.getSocialElementAttributes(),
        })}

    `
  }

  render() {
    return `
      ${this.getAttribute('mode') === 'horizontal'
        ? this.renderHorizontal()
        : this.renderVertical()}
    `
  }
}
<|endoftext|>


<commit_before>const { getSource } = require('./helpers/source');

const bindNodeModulesPrefix = (name) => getSource(`node_modules/${name}`);

const OPENPGP_FILES = Object.fromEntries(
    Object.entries({
        main: 'openpgp/dist/lightweight/openpgp.min.js',
        elliptic: 'openpgp/dist/lightweight/elliptic.min.js',
        worker: 'openpgp/dist/lightweight/openpgp.worker.min.js',
        compat: 'openpgp/dist/compat/openpgp.min.js'
    }).map(([k, v]) => [k, bindNodeModulesPrefix(v)])
);

const BABEL_INCLUDE_NODE_MODULES = [
    'asmcrypto.js',
    'pmcrypto',
    'proton-pack',
    'proton-shared',
    'sieve.js',
    'pm-srp',
    'react-components'
];
const BABEL_EXCLUDE_FILES = ['mailparser.js'];

module.exports = {
    OPENPGP_FILES,
    BABEL_EXCLUDE_FILES,
    BABEL_INCLUDE_NODE_MODULES
};
<commit_msg>Babelify more modules (#57)<commit_after>const { getSource } = require('./helpers/source');

const bindNodeModulesPrefix = (name) => getSource(`node_modules/${name}`);

const OPENPGP_FILES = Object.fromEntries(
    Object.entries({
        main: 'openpgp/dist/lightweight/openpgp.min.js',
        elliptic: 'openpgp/dist/lightweight/elliptic.min.js',
        worker: 'openpgp/dist/lightweight/openpgp.worker.min.js',
        compat: 'openpgp/dist/compat/openpgp.min.js'
    }).map(([k, v]) => [k, bindNodeModulesPrefix(v)])
);

const BABEL_INCLUDE_NODE_MODULES = [
    'asmcrypto.js',
    'pmcrypto',
    'proton-pack',
    'proton-shared',
    'mutex-browser',
    'interval-tree',
    'get-random-values',
    'sieve.js',
    'pm-srp',
    'react-components'
];
const BABEL_EXCLUDE_FILES = ['mailparser.js'];

module.exports = {
    OPENPGP_FILES,
    BABEL_EXCLUDE_FILES,
    BABEL_INCLUDE_NODE_MODULES
};
<|endoftext|>


<commit_before>import path from 'path'
import fs from 'fs'
import connect from 'connect'
import serve from 'serve-static'
import hsr from './hsr'
import { log } from './emit'

export default function (argv) {
  const app = connect()

  const root = path.resolve(process.cwd(), 'dist')

  app.use((req, res, next) => {
    // if (req.url === '/hsr.js') {
    //   const dir = path.resolve(__dirname, '../../assets')
    //   return serve(dir)(req, res, next)
    // }

    if (!path.extname(req.url)) {
      req.url = '/index.html'
    }

    next()
  })

  // app.use((req, res, next) => {
  //   if (req.url.match(/index\.html$/)) {
  //     const indx = fs.readFileSync(path.resolve(process.cwd(), 'dist/index.html'), 'utf8')
  //     // res.write(`${indx}<script src="/hsr.js"></script>`)
  //     res.write(indx)
  //     res.end()
  //   } else {
  //     return serve(root)(req, res, next)
  //   }
  //
  //   next()
  // })
  app.use(serve(root))

  const port = argv.port || argv.p || 8080
  const host = argv.host || argv.h || 'localhost'

  return new Promise((resolve, reject) => {
    app.listen(port, host, () => {
      log(`running at http://${host}:${port}`)
      resolve(hsr())
    })
  })
}
<commit_msg>server fix<commit_after>import path from 'path'
import fs from 'fs'
import connect from 'connect'
import serve from 'serve-static'
import hsr from './hsr'
import { log } from './emit'

export default function (argv = {}) {
  const app = connect()

  const root = path.resolve(process.cwd(), 'dist')

  app.use((req, res, next) => {
    // if (req.url === '/hsr.js') {
    //   const dir = path.resolve(__dirname, '../../assets')
    //   return serve(dir)(req, res, next)
    // }

    if (!path.extname(req.url)) {
      req.url = '/index.html'
    }

    next()
  })

  // app.use((req, res, next) => {
  //   if (req.url.match(/index\.html$/)) {
  //     const indx = fs.readFileSync(path.resolve(process.cwd(), 'dist/index.html'), 'utf8')
  //     // res.write(`${indx}<script src="/hsr.js"></script>`)
  //     res.write(indx)
  //     res.end()
  //   } else {
  //     return serve(root)(req, res, next)
  //   }
  //
  //   next()
  // })
  app.use(serve(root))

  const port = argv.port || argv.p || 8080
  const host = argv.host || argv.h || 'localhost'

  return new Promise((resolve, reject) => {
    app.listen(port, host, () => {
      log(`running at http://${host}:${port}`)
      resolve(hsr())
    })
  })
}
<|endoftext|>


<commit_before>/**
 * Object to manage the communication with the backend
 */
const API = {
  // for dev environment
  Apibase: location.hostname !== "localhost" ? 'http://api.meirim.org/' : 'http://localhost:3000/',
  get_promise: function (path) {
    return new Promise((resolve, reject) => {
      this.get(path)
        .done(response => resolve(response))
        .catch(error => reject(error));

    })
  },
  get: function (path) {
    return this.request({
      type: 'GET',
      url: this.Apibase + path
    });
  },
  post: function (path, data) {
    return this.request({
      type: 'POST',
      url: this.Apibase + path,
      data: JSON.stringify(data)
    });
  },
  delete: function (path) {
    return this.request({
      type: 'DELETE',
      url: this.Apibase + path
    });
  },
  request: function (params) {
    const settings = Object.assign({
      dataType: 'json',
      async: true,
      xhrFields: {
        withCredentials: true
      },
      contentType: 'application/json'
    }, params);
    return $.ajax(settings);
  }
}

function redirectTo(path) {
  window.location = path;
}

function errorHandler(xhr, status, errorThrown) {
  var goToLoginText = "תרצו להכנס למערכת או להרשם?";
  switch (xhr.status) {
    case 403:
      if (confirm(xhr.responseJSON.data + "\n" + goToLoginText)) {
        redirectTo("/#login");
      }
      break;
    default:
      errorMessage("Sorry, there was a problem!\n" + xhr.status);
      console.log("Error: " + errorThrown);
      console.log("Status: " + status);
      console.dir(xhr);
      break;
  }
};

function loadTemplate(path) {
  const settings = {
    type: 'GET',
    url: path,
    dataType: 'text',
    async: true,
    contentType: 'text/plain',
  };

  return new Promise((resolve, reject) =>
    $.ajax(settings)
      .done(response => resolve(response))
      .catch(error => reject(error)));
}

function errorMessage(message) {
  alert(message);
}

function getParams() {
  return window.location.search.slice(1)
    .split('&')
    .reduce(function _reduce( /*Object*/ a, /*String*/ b) {
      b = b.split('=');
      a[b[0]] = decodeURIComponent(b[1]);
      return a;
    }, {});
}

<commit_msg>change js base api url to https<commit_after>/**
 * Object to manage the communication with the backend
 */
const API = {
  // for dev environment
  Apibase: location.hostname !== "localhost" ? 'https://api.meirim.org/' : 'http://localhost:3000/',
  get_promise: function (path) {
    return new Promise((resolve, reject) => {
      this.get(path)
        .done(response => resolve(response))
        .catch(error => reject(error));

    })
  },
  get: function (path) {
    return this.request({
      type: 'GET',
      url: this.Apibase + path
    });
  },
  post: function (path, data) {
    return this.request({
      type: 'POST',
      url: this.Apibase + path,
      data: JSON.stringify(data)
    });
  },
  delete: function (path) {
    return this.request({
      type: 'DELETE',
      url: this.Apibase + path
    });
  },
  request: function (params) {
    const settings = Object.assign({
      dataType: 'json',
      async: true,
      xhrFields: {
        withCredentials: true
      },
      contentType: 'application/json'
    }, params);
    return $.ajax(settings);
  }
}

function redirectTo(path) {
  window.location = path;
}

function errorHandler(xhr, status, errorThrown) {
  var goToLoginText = "תרצו להכנס למערכת או להרשם?";
  switch (xhr.status) {
    case 403:
      if (confirm(xhr.responseJSON.data + "\n" + goToLoginText)) {
        redirectTo("/#login");
      }
      break;
    default:
      errorMessage("Sorry, there was a problem!\n" + xhr.status);
      console.log("Error: " + errorThrown);
      console.log("Status: " + status);
      console.dir(xhr);
      break;
  }
};

function loadTemplate(path) {
  const settings = {
    type: 'GET',
    url: path,
    dataType: 'text',
    async: true,
    contentType: 'text/plain',
  };

  return new Promise((resolve, reject) =>
    $.ajax(settings)
      .done(response => resolve(response))
      .catch(error => reject(error)));
}

function errorMessage(message) {
  alert(message);
}

function getParams() {
  return window.location.search.slice(1)
    .split('&')
    .reduce(function _reduce( /*Object*/ a, /*String*/ b) {
      b = b.split('=');
      a[b[0]] = decodeURIComponent(b[1]);
      return a;
    }, {});
}

<|endoftext|>


<commit_before>var sock;

var curEvent, users, messages;

var app;

var curSession = null;

// handle IE not having console.log
if (typeof console === "undefined" || typeof console.log === "undefined") {
     console = {};
     console.log = function() {};
}

$(document).ready(function() {
	if($("#main").length!=1) {
		console.log("Code running on a page that does not have an #app div.");
		return;
	}

	console.log("Starting app!");

	curEvent = new models.ClientEvent(EVENT_ATTRS);

	users = new models.UserList(EVENT_ATTRS.connectedUsers);

	curEvent.get("sessions").add(EVENT_ATTRS.sessions);

	if(SINGLE_SESSION_RSVP) {
		curEvent.get("sessions").each(function(session) {
			if(session.isAttending(USER_ID)) {
				console.log("SETTING CUR SESSION: " + session.id);
				curSession = session.id;
			}
		})
	}

	$("#sessions-nav").find("a").text("Sessions (" + curEvent.get("sessions").length + ")");

	messages = new models.ChatMessageList();

	console.log("Inflated models.");

	app = new Backbone.Marionette.Application();

	app.addRegions({
		// top: '#top',
		right: '#main-right',
		main: '#main-left',
		top: '#top-left',
		global: '#global',
		dialogs: '#dialogs',
		admin: '#admin-region',
		bar:'#bar'
	});

	app.addInitializer(function(options) {

		// include the youtube JS api per docs:
	    // https://developers.google.com/youtube/iframe_api_reference
	    var tag = document.createElement('script');
	    tag.src = "//www.youtube.com/iframe_api";
	    var firstScriptTag = document.getElementsByTagName('script')[0];
	    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

	    window.onYouTubeIframeAPIReady = _.bind(function(playerId) {
			this.vent.trigger("youtube-ready");
	    }, this);

	    this.paginatedSessions = new models.PaginatedSessionList(curEvent.get("sessions").models);
	    this.paginatedSessions.bootstrap();

		this.sessionListView = new SessionListView({collection: this.paginatedSessions});
		this.chatView = new ChatLayout({messages:messages, users:users});
		this.youtubeEmbedView = new VideoEmbedView({model:curEvent});
		this.dialogView = new DialogView();

		// this.top.show(this.sessionListView);
		this.right.show(this.chatView);
		this.main.show(this.sessionListView);
		this.dialogs.show(this.dialogView);

		// this is a little unorthodox, but not sure how else
		// to do it.
		$(this.bar.el).hide();

		if(IS_ADMIN) {
			this.adminButtonView = new AdminButtonView();
			this.admin.show(this.adminButtonView);
		}

		console.log("Initialized app.");
	});

	var isIntervalRunning = false;
	var interval = 0;

	app.vent.on("new-chat-message", _.bind(function() {
		isIntervalRunning = true;

		if(isIntervalRunning)
			interval = window.setTimeout(showFlashTitle, 1000);
	}, app));

	function showFlashTitle() {
		if(window.document.title == 'Unhangout')
			window.document.title = 'New Message ...';
		else
			window.document.title = 'Unhangout';

		interval = window.setTimeout(showFlashTitle, 1000);
	}

	app.vent.on("sessions-nav", _.bind(function() {
		this.main.show(this.sessionListView);
	}, app));

	var videoShown = false;
	app.vent.on("video-nav", _.bind(function() {
		console.log("handling video-nav event");

		// regardless of whether there's a current embed, hide the video if
		// it's currently showon.
		if(videoShown) {
			this.top.$el.css("z-index", -10);

			this.top.reset();
			videoShown = false;

			this.main.$el.css("top", 0);
			this.sessionListView.updateDisplay();
			$("#video-nav").removeClass("active");
		} else if(curEvent.hasEmbed()) {
			$(".nav .active").removeClass("active");

			if(!videoShown) {
				this.top.show(this.youtubeEmbedView);
				videoShown = true;

				var mainHeight = this.youtubeEmbedView.$el.outerHeight()-5;

				if(this.main.$el.hasClass("bar")) {
					mainHeight += 40;
				}

				this.main.$el.css("top", mainHeight);
				this.sessionListView.updateDisplay();
				this.top.$el.css("z-index", 50);
				$("#video-nav").addClass("active");
			}
		} else {
			console.log("Ignoring video click; no video available.");
		}

	}, app));

	app.vent.on("youtube-ready", _.bind(function() {
		console.log("YOUTUBE READY");

		if(curEvent.hasEmbed()) {
			app.vent.trigger("video-nav");
		}
	}, app));

	app.vent.on("video-live", _.bind(function() {
		$("#video-nav .label").removeClass("hide");
	}, app));

	app.vent.on("video-off", _.bind(function() {
		$("#video-nav .label").addClass("hide");
	}, app));

	app.vent.on("show-bar", _.bind(function(sessionKey) {

		this.bar.show(new SessionLiveView());
		$(this.bar.el).show();

		$("#top-left, #main-right, #main-left").addClass("bar");

		// set the hangout link.
		this.bar.$el.find("a").attr("href", "/session/" + sessionKey);

		// 30 minutes later hide the bar(?)
		setTimeout(function() {
			app.vent.trigger("hide-bar");
		}, 60*1000*30);
	}, app));

	app.vent.on("hide-bar", _.bind(function() {
		this.bar.close();
		this.bar.$el.hide();

		$("#top-left, #main-right, #main-left").removeClass("bar");

		// we need to do a special check for main-left, which has custom
		// style adjustement on it.
		if(videoShown) {
			this.main.$el.css("top", this.youtubeEmbedView.$el.outerHeight()-5);
		} else {
			this.main.$el.css("top", "");
		}

	}, app));

	var queuedAttend = false;

	app.vent.on("attend", _.bind(function(sessionId) {
		console.log("VENT ATTEND: " + sessionId);
		// we have to manage attend logic here in the single_session_rsvp case so
		// we can send unattend messages first, and then attend messages.

		// if they're the same, just ignore it.
		if(curSession && curSession!=sessionId) {

			queuedAttend = function() {
				var message = {type:"attend", args:{id:sessionId}};
				sock.send(JSON.stringify(message));
			}

			var message = {type:"unattend", args:{id:curSession}};
			sock.send(JSON.stringify(message));
		} else if(!curSession) {
			var message = {type:"attend", args:{id:sessionId}};
			sock.send(JSON.stringify(message));
		}
	}));

	app.start();

	if(curSession) {
		var curSessionObj = curEvent.get("sessions").get(curSession);

		if(curSessionObj.isLive()) {
			app.vent.trigger("show-bar", curSessionObj.get("session-key"));
		}
	}

	if(curEvent.hasEmbed()) {
		app.vent.trigger("video-live");
		// app.vent.trigger("video-nav");
	}

	$("#video-nav").click(function() {
		app.vent.trigger($(this).attr("id"));
	})

	console.log("Setup regions.");

	sock = new SockJS(document.location.protocol + "//" + document.location.hostname + ":" + document.location.port + "/sock");
	sock.onopen = function() {
		console.log('open');

		var AUTH = {type:"auth", args:{key:SOCK_KEY, id:USER_ID}};

		sock.send(JSON.stringify(AUTH));
	};
	sock.onmessage = function(message) {
		console.log(message);
		var msg = JSON.parse(message.data);

		if(msg.type.indexOf("-err")!=-1) {
			console.log("Got an error from the server!");
		}

		switch(msg.type) {
			case "attend":
				curEvent.get("sessions").get(msg.args.id).addAttendee(msg.args.user);
				console.log("added attendee to a session");

				if(SINGLE_SESSION_RSVP && msg.args.user.id==USER_ID) {

					if(!_.isNull(curSession)) {
						var message = {type:"unattend", args:{id:curSession}};
						sock.send(JSON.stringify(message));
					}

					curSession = msg.args.id;
				}
				break;

			case "first-attendee":
				curEvent.get("sessions").get(msg.args.id).setFirstAttendee(msg.args.user);
				console.log("set first attendee");
				break;

			case "unattend"	:
				curEvent.get("sessions").get(msg.args.id).removeAttendee(msg.args.user);
				console.log("removed attendee from a session");

				curSession = null;

				if(queuedAttend) {
					queuedAttend.call();
					queuedAttend = false;
				}

				break;

			case "join":
				console.log("join: " + JSON.stringify(msg.args));
				users.add(new models.User(msg.args.user));
				break;

			case "leave":
				users.remove(users.get(msg.args.user.ytId));
				break;

			case "chat":
				messages.add(new models.ChatMessage(msg.args));
				app.vent.trigger("new-chat-message");
				break;

			case "embed":
				var originalYoutubeId = curEvent.get("youtubeEmbed") || "";

				curEvent.setEmbed(msg.args.ytId);
				console.log("added yt embed id: " + JSON.stringify(msg.args));

				if(msg.args.ytId.length > 0) {
					// if it's a non-empty yt embed, show the live tag.
					app.vent.trigger("video-live");

					if(originalYoutubeId.length==0) {
						app.vent.trigger("video-nav");
					}
				} else {
					// if it's empty, hide the live tag.
					app.vent.trigger("video-off");
					app.vent.trigger("video-nav");
				}

				break;

			case "start":
				// this is a little wacky, but we want to give people who RSVP'd a chance to join first.
				// so we're going to do two things here:
				// 1) if not rsvp, delay triggering start and setting the session key.
				// 2) if not rsvp, supress the dialog popup
				var session = curEvent.get("sessions").get(msg.args.id);

				var timeout = 0;

				if(!(session.isAttending(USER_ID))) {
					timeout = 60*1000;
				}

				setTimeout(function() {
					session.set("session-key", msg.args.key);
					session.start();
				}, timeout);

				app.vent.trigger("show-bar", msg.args.key);

				break;
			case "stop":
				var session = curEvent.get("sessions").get(msg.args.id);
				session.stop();

				if(session.id==curSession) {
					app.vent.trigger("hide-bar");
				}

				break;
			case "auth-ack":
				sock.send(JSON.stringify({type:"join", args:{id:curEvent.id}}));
				break;

			case "embed-ack":
				$("#embed-modal").modal('hide');
				break;

			case "join-ack":
				console.log("joined!");
				break;

			case "attend-ack":
				console.log("attend-ack");
				break;
		}
	};

	sock.onclose = function() {
		$('#disconnected-modal').modal('show');
		messages.add(new models.ChatMessage({text:"You have been disconnected from the server. Please reload the page to reconnect!", user:{displayName:"SERVER"}}));
		console.log('close');
	};
});
<commit_msg>minor typo in the previous commit<commit_after>var sock;

var curEvent, users, messages;

var app;

var curSession = null;

// handle IE not having console.log
if (typeof console === "undefined" || typeof console.log === "undefined") {
     console = {};
     console.log = function() {};
}

$(document).ready(function() {
	if($("#main").length!=1) {
		console.log("Code running on a page that does not have an #app div.");
		return;
	}

	console.log("Starting app!");

	curEvent = new models.ClientEvent(EVENT_ATTRS);

	users = new models.UserList(EVENT_ATTRS.connectedUsers);

	curEvent.get("sessions").add(EVENT_ATTRS.sessions);

	if(SINGLE_SESSION_RSVP) {
		curEvent.get("sessions").each(function(session) {
			if(session.isAttending(USER_ID)) {
				console.log("SETTING CUR SESSION: " + session.id);
				curSession = session.id;
			}
		})
	}

	$("#sessions-nav").find("a").text("Sessions (" + curEvent.get("sessions").length + ")");

	messages = new models.ChatMessageList();

	console.log("Inflated models.");

	app = new Backbone.Marionette.Application();

	app.addRegions({
		// top: '#top',
		right: '#main-right',
		main: '#main-left',
		top: '#top-left',
		global: '#global',
		dialogs: '#dialogs',
		admin: '#admin-region',
		bar:'#bar'
	});

	app.addInitializer(function(options) {

		// include the youtube JS api per docs:
	    // https://developers.google.com/youtube/iframe_api_reference
	    var tag = document.createElement('script');
	    tag.src = "//www.youtube.com/iframe_api";
	    var firstScriptTag = document.getElementsByTagName('script')[0];
	    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

	    window.onYouTubeIframeAPIReady = _.bind(function(playerId) {
			this.vent.trigger("youtube-ready");
	    }, this);

	    this.paginatedSessions = new models.PaginatedSessionList(curEvent.get("sessions").models);
	    this.paginatedSessions.bootstrap();

		this.sessionListView = new SessionListView({collection: this.paginatedSessions});
		this.chatView = new ChatLayout({messages:messages, users:users});
		this.youtubeEmbedView = new VideoEmbedView({model:curEvent});
		this.dialogView = new DialogView();

		// this.top.show(this.sessionListView);
		this.right.show(this.chatView);
		this.main.show(this.sessionListView);
		this.dialogs.show(this.dialogView);

		// this is a little unorthodox, but not sure how else
		// to do it.
		$(this.bar.el).hide();

		if(IS_ADMIN) {
			this.adminButtonView = new AdminButtonView();
			this.admin.show(this.adminButtonView);
		}

		console.log("Initialized app.");
	});

	var isIntervalRunning = false;
	var interval = 0;

	app.vent.on("new-chat-message", _.bind(function() {
		isIntervalRunning = true;

		if(isIntervalRunning)
			interval = window.setTimeout(showFlashTitle, 1000);
	}, app));

	function showFlashTitle() {
		if(window.document.title == 'Unhangout')
			window.document.title = 'New Message ...';
		else
			window.document.title = 'Unhangout';

		interval = window.setTimeout(showFlashTitle, 1000);
	}

	app.vent.on("sessions-nav", _.bind(function() {
		this.main.show(this.sessionListView);
	}, app));

	var videoShown = false;
	app.vent.on("video-nav", _.bind(function() {
		console.log("handling video-nav event");

		// regardless of whether there's a current embed, hide the video if
		// it's currently showon.
		if(videoShown) {
			this.top.$el.css("z-index", -10);

			this.top.reset();
			videoShown = false;

			this.main.$el.css("top", 0);
			this.sessionListView.updateDisplay();
			$("#video-nav").removeClass("active");
		} else if(curEvent.hasEmbed()) {
			$(".nav .active").removeClass("active");

			if(!videoShown) {
				this.top.show(this.youtubeEmbedView);
				videoShown = true;

				var mainHeight = this.youtubeEmbedView.$el.outerHeight()-5;

				if(this.main.$el.hasClass("bar")) {
					mainHeight += 40;
				}

				this.main.$el.css("top", mainHeight);
				this.sessionListView.updateDisplay();
				this.top.$el.css("z-index", 50);
				$("#video-nav").addClass("active");
			}
		} else {
			console.log("Ignoring video click; no video available.");
		}

	}, app));

	app.vent.on("youtube-ready", _.bind(function() {
		console.log("YOUTUBE READY");

		if(curEvent.hasEmbed()) {
			app.vent.trigger("video-nav");
		}
	}, app));

	app.vent.on("video-live", _.bind(function() {
		$("#video-nav .label").removeClass("hide");
	}, app));

	app.vent.on("video-off", _.bind(function() {
		$("#video-nav .label").addClass("hide");
	}, app));

	app.vent.on("show-bar", _.bind(function(sessionKey) {

		this.bar.show(new SessionLiveView());
		$(this.bar.el).show();

		$("#top-left, #main-right, #main-left").addClass("bar");

		// set the hangout link.
		this.bar.$el.find("a").attr("href", "/session/" + sessionKey);

		// 30 minutes later hide the bar(?)
		setTimeout(function() {
			app.vent.trigger("hide-bar");
		}, 60*1000*30);
	}, app));

	app.vent.on("hide-bar", _.bind(function() {
		this.bar.close();
		this.bar.$el.hide();

		$("#top-left, #main-right, #main-left").removeClass("bar");

		// we need to do a special check for main-left, which has custom
		// style adjustement on it.
		if(videoShown) {
			this.main.$el.css("top", this.youtubeEmbedView.$el.outerHeight()-5);
		} else {
			this.main.$el.css("top", "");
		}

	}, app));

	var queuedAttend = false;

	app.vent.on("attend", _.bind(function(sessionId) {
		console.log("VENT ATTEND: " + sessionId);
		// we have to manage attend logic here in the single_session_rsvp case so
		// we can send unattend messages first, and then attend messages.

		// if they're the same, just ignore it.
		if(curSession && curSession!=sessionId) {

			queuedAttend = function() {
				var message = {type:"attend", args:{id:sessionId}};
				sock.send(JSON.stringify(message));
			}

			var message = {type:"unattend", args:{id:curSession}};
			sock.send(JSON.stringify(message));
		} else if(!curSession) {
			var message = {type:"attend", args:{id:sessionId}};
			sock.send(JSON.stringify(message));
		}
	}));

	app.start();

	if(curSession) {
		var curSessionObj = curEvent.get("sessions").get(curSession);

		if(curSessionObj.isLive()) {
			app.vent.trigger("show-bar", curSessionObj.get("session-key"));
		}
	}

	if(curEvent.hasEmbed()) {
		app.vent.trigger("video-live");
		// app.vent.trigger("video-nav");
	}

	$("#video-nav").click(function() {
		app.vent.trigger($(this).attr("id"));
	})

	console.log("Setup regions.");

	sock = new SockJS(document.location.protocol + "//" + document.location.hostname + ":" + document.location.port + "/sock");
	sock.onopen = function() {
		console.log('open');

		var AUTH = {type:"auth", args:{key:SOCK_KEY, id:USER_ID}};

		sock.send(JSON.stringify(AUTH));
	};
	sock.onmessage = function(message) {
		console.log(message);
		var msg = JSON.parse(message.data);

		if(msg.type.indexOf("-err")!=-1) {
			console.log("Got an error from the server!");
		}

		switch(msg.type) {
			case "attend":
				curEvent.get("sessions").get(msg.args.id).addAttendee(msg.args.user);
				console.log("added attendee to a session");

				if(SINGLE_SESSION_RSVP && msg.args.user.id==USER_ID) {

					if(!_.isNull(curSession)) {
						var message = {type:"unattend", args:{id:curSession}};
						sock.send(JSON.stringify(message));
					}

					curSession = msg.args.id;
				}
				break;

			case "first-attendee":
				curEvent.get("sessions").get(msg.args.id).setFirstAttendee(msg.args.user);
				console.log("set first attendee");
				break;

			case "unattend"	:
				curEvent.get("sessions").get(msg.args.id).removeAttendee(msg.args.user);
				console.log("removed attendee from a session");

				curSession = null;

				if(queuedAttend) {
					queuedAttend.call();
					queuedAttend = false;
				}

				break;

			case "join":
				console.log("join: " + JSON.stringify(msg.args));
				users.add(new models.User(msg.args.user));
				break;

			case "leave":
				users.remove(users.get(msg.args.user.id));
				break;

			case "chat":
				messages.add(new models.ChatMessage(msg.args));
				app.vent.trigger("new-chat-message");
				break;

			case "embed":
				var originalYoutubeId = curEvent.get("youtubeEmbed") || "";

				curEvent.setEmbed(msg.args.ytId);
				console.log("added yt embed id: " + JSON.stringify(msg.args));

				if(msg.args.ytId.length > 0) {
					// if it's a non-empty yt embed, show the live tag.
					app.vent.trigger("video-live");

					if(originalYoutubeId.length==0) {
						app.vent.trigger("video-nav");
					}
				} else {
					// if it's empty, hide the live tag.
					app.vent.trigger("video-off");
					app.vent.trigger("video-nav");
				}

				break;

			case "start":
				// this is a little wacky, but we want to give people who RSVP'd a chance to join first.
				// so we're going to do two things here:
				// 1) if not rsvp, delay triggering start and setting the session key.
				// 2) if not rsvp, supress the dialog popup
				var session = curEvent.get("sessions").get(msg.args.id);

				var timeout = 0;

				if(!(session.isAttending(USER_ID))) {
					timeout = 60*1000;
				}

				setTimeout(function() {
					session.set("session-key", msg.args.key);
					session.start();
				}, timeout);

				app.vent.trigger("show-bar", msg.args.key);

				break;
			case "stop":
				var session = curEvent.get("sessions").get(msg.args.id);
				session.stop();

				if(session.id==curSession) {
					app.vent.trigger("hide-bar");
				}

				break;
			case "auth-ack":
				sock.send(JSON.stringify({type:"join", args:{id:curEvent.id}}));
				break;

			case "embed-ack":
				$("#embed-modal").modal('hide');
				break;

			case "join-ack":
				console.log("joined!");
				break;

			case "attend-ack":
				console.log("attend-ack");
				break;
		}
	};

	sock.onclose = function() {
		$('#disconnected-modal').modal('show');
		messages.add(new models.ChatMessage({text:"You have been disconnected from the server. Please reload the page to reconnect!", user:{displayName:"SERVER"}}));
		console.log('close');
	};
});
<|endoftext|>


<commit_before>var ds_user = '';
var ds_key = '';

//init
$(function() {

    // cookies
    if($.cookie('un') && $.cookie('key')){
        $('#un').val($.cookie('un')) === $.cookie('un');
        $('#key').val($.cookie('key')) === $.cookie('key');
    }

    $('#jcsdl-edit').jcsdlGui({
        save : function(code) {
            log('DEBUG: CSDL generated: ' + code);
            // validate the DS creds
            if(validateCreds() === true){
                doCompile(code);
            }
        },
        hideTargets : ['twitter.status', 'twitter.place', 'twitter.retweet', 'twitter.mention_ids', 'twitter.domains', 'twitter.in_reply_to_screen_name', 'twitter.links', 'twitter.user', 'twitter.retweeted',   'interaction', '2ch', 'lexisnexis', 'intensedebate', 'sinaweibo', 'tencentweibo', 'tumblr', 'facebook_page', 'googleplus','instagram', 'wordpress', 'wikipedia', 'yammer',  'imdb','facebook', '2channel', 'myspace', 'digg', 'amazon', 'blog', 'board', 'bitly', 'dailymotion', 'flickr', 'newscred', 'reddit', 'topix', 'video', 'youtube', 'imdb.author', 'imdb.type', 'imdb.contenttype', 'imdb.thread']
    });
});

/*
 * validateCreds - validate the user has entered
 *                 DS creds, and set cookies.
 *
 * @return boolean
 *
 */
function validateCreds(){

    ds_user = $.trim($('#un').val());
    ds_key  = $.trim($('#key').val());

    if(ds_user ==='' || ds_key === ''){
        alert('Please enter a DataSift username and API key.');
        return false;
    }

    // set cookie
    $.cookie('un', ds_user, { expires: 60 });
    $.cookie('key', ds_key, { expires: 60 });
    return true;
};

/*
 * initPreview - build params and calls
 * historic preview
 *
 */
function initPreview (hash){
    var params  = {};
    params.start = Math.floor((Date.now() / 1000) - (60 * 60 * 3)); // start is 3 hours ago
    params.end = Math.floor((Date.now() / 1000) - (60 * 60 * 2)); // end is 2 hours ago
    params.hash = hash;
    params.sources = 'twitter';
    params.parameters = 'language.tag,freqDist,10';

    doCreate(serialize(params));
}

/*
 * doCompile
 *
 * @return void
 *
 */
function doCompile (csdl) {

    log('DEBUG: Compiling CSDL...');

    jQuery.ajax({
        type: "POST",
        url: "http://localhost:3000/api/compile",
        contentType: "application/json; charset=utf-8",
        data: 'csdl='+encodeURIComponent(csdl),
        dataType: "json",
        headers: {
            "Authorization": ds_user + ':' + ds_key
        },
        success: function (data, status, jqXHR) {
            log('DEBUG: Compile success - ' + JSON.stringify(jqXHR.responseJSON));
            if(jqXHR.responseJSON.hash && jqXHR.responseJSON.hash !== undefined){
                // start historic preview
                initPreview(jqXHR.responseJSON.hash);
            } else {
                log('ERROR: Compile failed - no hash received: ' + JSON.stringify(jqXHR.responseJSON));
            }
        },
        error: function (jqXHR, status) {
            log('ERROR: Compile failed: ' + JSON.stringify(jqXHR.responseJSON));
        }
    });
}

/*
 * doCreate
 *
 * @return void
 *
 */
function doCreate (params) {

    log('DEBUG: Staring preview...');

    jQuery.ajax({
        type: "POST",
        url: "http://localhost:3000/api/create",
        contentType: "application/json; charset=utf-8",
        data: params,
        dataType: "json",
        headers: {
            "Authorization": ds_user + ':' + ds_key
        },
        success: function (data, status, jqXHR) {
            log('DEBUG: Historic preview create success: ' + JSON.stringify(jqXHR.responseJSON));
            getPreview(jqXHR.responseJSON.id);
        },
        error: function (jqXHR, status) {
            log('ERROR: historic preview create failed: ' + JSON.stringify(jqXHR.responseJSON));
        }
    });
}

/*
 * log
 *
 * @return void
 *
 */
function log(update){
    $('#debug').val($('#debug').val() + "\n\n" + update);
}

/*
 * serialize - obj to URI encoded string
 *
 * @param - obj - {foo: "hi there", bar: "100%" }
 * @return - string - foo=hi%20there&bar=100%25
 */
function serialize(obj) {
    var str = [];
    for(var p in obj) {
        if (obj.hasOwnProperty(p)) {
            str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
        }
    }
    return str.join("&");
}

/*
 * getPreview - poll historic preview
 * until a 200 is received.
 *
 */
function getPreview (id) {
    var intervalID = setInterval(function() {
        jQuery.ajax({
            type: "GET",
            url: "http://localhost:3000/api/preview/"+id,
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            headers: {
                "Authorization": ds_user + ':' + ds_key
            },
            success: function (data, status, jqXHR) {
                log('DEBUG: Preview status: ' + JSON.stringify(jqXHR.responseJSON.progress));

                if(jqXHR.status === 200) {
                    log('DEBUG: Preview complete: '+ JSON.stringify(jqXHR.responseJSON));
                    clearInterval(intervalID);
                }
            },
            error: function (jqXHR, status) {
                log('ERROR: historic preview create failed.');
            }
        });
    }, 5000);
}
<commit_msg>Calculate final stats.<commit_after>var ds_user = '';
var ds_key = '';

//init
$(function() {

    NProgress.configure({
        trickle: false
    });

    // cookies
    if($.cookie('un') && $.cookie('key')){
        $('#un').val($.cookie('un')) === $.cookie('un');
        $('#key').val($.cookie('key')) === $.cookie('key');
    }

    $('#jcsdl-edit').jcsdlGui({
        save : function(code) {
            $('#intro').text('Estimating data volume...');
            log('DEBUG: CSDL generated: ' + code);
            // validate the DS creds
            if(validateCreds() === true){
                doCompile(code);
            }
            $('#jcsdl-edit').slideUp(300);
        },
        hideTargets : ['twitter.status', 'twitter.place', 'twitter.retweet', 'twitter.mention_ids', 'twitter.domains', 'twitter.in_reply_to_screen_name', 'twitter.links', 'twitter.user', 'twitter.retweeted',   'interaction', '2ch', 'lexisnexis', 'intensedebate', 'sinaweibo', 'tencentweibo', 'tumblr', 'facebook_page', 'googleplus','instagram', 'wordpress', 'wikipedia', 'yammer',  'imdb','facebook', '2channel', 'myspace', 'digg', 'amazon', 'blog', 'board', 'bitly', 'dailymotion', 'flickr', 'newscred', 'reddit', 'topix', 'video', 'youtube', 'imdb.author', 'imdb.type', 'imdb.contenttype', 'imdb.thread']
    });
});

/*
 * validateCreds - validate the user has entered
 *                 DS creds, and set cookies.
 *
 * @return boolean
 *
 */
function validateCreds(){

    ds_user = $.trim($('#un').val());
    ds_key  = $.trim($('#key').val());

    if(ds_user ==='' || ds_key === ''){
        alert('Please enter a DataSift username and API key.');
        return false;
    }

    // set cookie
    $.cookie('un', ds_user, { expires: 60 });
    $.cookie('key', ds_key, { expires: 60 });
    return true;
};

/*
 * initPreview - build params and calls
 * historic preview
 *
 */
function initPreview (hash){
    var params  = {};
    params.start = Math.floor((Date.now() / 1000) - (60 * 60 * 2)); // start is 2 hours ago
    params.end = Math.floor((Date.now() / 1000) - (60 * 60 * 2)); // end is 2 hours ago
    params.hash = hash;
    params.sources = 'twitter';
    params.parameters = 'interaction.id,targetVol';

    doCreate(serialize(params));
}

/*
 * doCompile
 *
 * @return void
 *
 */
function doCompile (csdl) {

    log('DEBUG: Compiling CSDL...');

    jQuery.ajax({
        type: "POST",
        url: "http://localhost:3000/api/compile",
        contentType: "application/json; charset=utf-8",
        data: 'csdl='+encodeURIComponent(csdl),
        dataType: "json",
        headers: {
            "Authorization": ds_user + ':' + ds_key
        },
        success: function (data, status, jqXHR) {
            log('DEBUG: Compile success - ' + JSON.stringify(jqXHR.responseJSON));
            if(jqXHR.responseJSON.hash && jqXHR.responseJSON.hash !== undefined){
                // start historic preview
                initPreview(jqXHR.responseJSON.hash);
            } else {
                log('ERROR: Compile failed - no hash received: ' + JSON.stringify(jqXHR.responseJSON));
            }
        },
        error: function (jqXHR, status) {
            log('ERROR: Compile failed: ' + JSON.stringify(jqXHR.responseJSON));
        }
    });
}

/*
 * doCreate
 *
 * @return void
 *
 */
function doCreate (params) {

    log('DEBUG: Staring preview...');

    jQuery.ajax({
        type: "POST",
        url: "http://localhost:3000/api/create",
        contentType: "application/json; charset=utf-8",
        data: params,
        dataType: "json",
        headers: {
            "Authorization": ds_user + ':' + ds_key
        },
        success: function (data, status, jqXHR) {
            log('DEBUG: Historic preview create success: ' + JSON.stringify(jqXHR.responseJSON));
            NProgress.start();
            log('DEBUG: Waiting for preview to complete...');
            getPreview(jqXHR.responseJSON.id);
        },
        error: function (jqXHR, status) {
            log('ERROR: historic preview create failed: ' + JSON.stringify(jqXHR.responseJSON));
        }
    });
}

/*
 * log
 *
 * @return void
 *
 */
function log(update){
    $('#debug').val($('#debug').val() + "\n" + update);
}

/*
 * serialize - obj to URI encoded string
 *
 * @param - obj - {foo: "hi there", bar: "100%" }
 * @return - string - foo=hi%20there&bar=100%25
 */
function serialize(obj) {
    var str = [];
    for(var p in obj) {
        if (obj.hasOwnProperty(p)) {
            str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
        }
    }
    return str.join("&");
}

/*
 * getPreview - poll historic preview
 * until a 200 is received.
 *
 * @param - string
 *
 */
function getPreview (id) {
    var intervalID = setInterval(function() {
        jQuery.ajax({
            type: "GET",
            url: "http://localhost:3000/api/preview/"+id,
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            headers: {
                "Authorization": ds_user + ':' + ds_key
            },
            success: function (data, status, jqXHR) {
                //log('DEBUG: Preview status: ' + JSON.stringify(jqXHR.responseJSON.progress));
                NProgress.set(jqXHR.responseJSON.progress / 100);
                if(jqXHR.status === 200) {
                    log('DEBUG: Preview complete: '+ JSON.stringify(jqXHR.responseJSON));
                    clearInterval(intervalID);
                    NProgress.done();
                    calcStats(jqXHR.responseJSON);
                }
            },
            error: function (jqXHR, status) {
                log('ERROR: failed to get preview status.');
            }
        });
    }, 4000);
}

/*
 * calcStats - calc and display results from
 * historic preview output.
 *
 * @param obj
 * @return void
 *
 */
function calcStats(obj){
    var hour = JSON.parse(obj.data[0].summary.count);
    var minute = ((hour / 60) * 100).toFixed(0);
    $('#intro').text('Estimated volume: ' + minute + ' per minute.');
}
<|endoftext|>


<commit_before>
/************************************

              app.js

  Global Variables & Utility Functions

 ************************************/

// Available Keys, and their index in
// the .csv array.
var keyMapping =
{
	area      : 0, // (string) *
	playerID  : 1, // (int)    *
	timestamp : 2, // (double) *
	posX      : 3, // (double) *
	posY      : 4, // (double) *
	cameraX   : 6, // (double)
	cameraY   : 7, // (double)

	// * required
}

var environment = document.URL;

var API = {

  // Target API. Set depending on environment
  url : (window.location.href.indexOf("herokuapp.com") > -1) ? "http://g-player.herokuapp.com/api/" : "http://localhost:5000/api/",
};

var loading = {};

// UI Feedback Indicator
loading.start = function(){
	$("#loading").text("Loading...");
};

// UI Feedback Indicator
loading.end = function(){
	$("#loading").text("");
};

DOM = {};

// Provide User Feedback in the Document
DOM.log = function(msg){
	$("#log").prepend("
" + msg + "
");
}

$(function() {
	QueryBuilder.open();
});<commit_msg>Don't open query builder on load<commit_after>
/************************************

              app.js

  Global Variables & Utility Functions

 ************************************/

// Available Keys, and their index in
// the .csv array.
var keyMapping =
{
	area      : 0, // (string) *
	playerID  : 1, // (int)    *
	timestamp : 2, // (double) *
	posX      : 3, // (double) *
	posY      : 4, // (double) *
	cameraX   : 6, // (double)
	cameraY   : 7, // (double)

	// * required
}

var environment = document.URL;

var API = {

  // Target API. Set depending on environment
  url : (window.location.href.indexOf("herokuapp.com") > -1) ? "http://g-player.herokuapp.com/api/" : "http://localhost:5000/api/",
};

var loading = {};

// UI Feedback Indicator
loading.start = function(){
	$("#loading").text("Loading...");
};

// UI Feedback Indicator
loading.end = function(){
	$("#loading").text("");
};

DOM = {};

// Provide User Feedback in the Document
DOM.log = function(msg){
	$("#log").prepend("
" + msg + "
");
}

/*
$(function() {
	QueryBuilder.open();
}); */<|endoftext|>


<commit_before>/**
 * returns business days [past, upcoming]
 * @returns {*[]}
 */
function businessDays() {
	"use strict";

	var date = new Date();

	// Copy date
	var t = new Date(date);
	// Remember the month number
	var m = date.getMonth();
	var d = date.getDate();
	var daysPast = 0, daysToGo = 0;
	var day;

	// Count past days
	while (t.getMonth() == m) {
		day = t.getDay();
		daysPast += (day == 0 || day == 6) ? 0 : 1;
		t.setDate(--d);
	}

	// Reset and count days to come
	t = new Date(date);
	t.setDate(t.getDate() + 1);
	d = t.getDate();

	while (t.getMonth() == m) {
		day = t.getDay();
		daysToGo += (day == 0 || day == 6) ? 0 : 1;
		t.setDate(++d);
	}
	return [daysPast, daysToGo];
}

/**
 * encode base64 encoded string
 * @param str
 * @returns {string}
 */
function b64EncodeUnicode(str) {
	"use strict";

	return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
		return String.fromCharCode('0x' + p1);
	}));
}

var projectStore = store.get('projects', []);
var userStore = store.get('users', []);

Vue.filter('fixed', function (value) {
	"use strict";

	return value != undefined
		? new Intl.NumberFormat("de-DE", {minimumFractionDigits: 2}).format(value)
		: null;
});

Vue.filter('sum', function (value) {
	"use strict";

	var project = value.name;
	var sum = 0;

	if (this.workload[project] !== undefined) {
		for (var user in this.workload[project]) {
			if (this.workload[project].hasOwnProperty(user)) {
				sum += parseFloat(this.workload[project][user]);
			}
		}
	}

	return sum;
});

Vue.filter('filterForProjectUser', function (value, p, u) {
	"use strict";

	var projectName = p.name;
	var userName = u.nickname;

	if (this.workload[projectName] === undefined)
		return;

	if (this.workload[projectName][userName] === undefined)
		return;

	return this.workload[projectName][userName];
});

var vm = new Vue({
	el: '#app',

	data: function () {
		return {
			projects: projectStore,
			newProject: {
				name: '',
				image: '',
				source: 'trac',
				url: '',
				auth: {
					type: 'basic',
					user: '',
					pass: ''
				},
				hourly_rate: 0,
				hours: 0
			},

			workload: {},
			start: moment().startOf('month'),
			end: moment().endOf('month'),

			users: userStore,
			newUser: {
				nickname: '',
				name: '',
				avatar: null,
				monthly_presence: 1,
				hours: 0
			},

			total: {
				hours: 0,
				sales: 0
			},

			fetching: [],
			showSalesValues: false,
			refresh: {
				active: true,
				pauseBeforeRefresh: 5000,
				lastRun: null
			}
		}
	},

	ready: function () {
		this.fetchAllProjects();
	},

	created: function () {
	},

	methods: {
		resetValues: function () {
			"use strict";

			this.total.hours = 0;
			this.total.sales = 0;

			for (var u in this.users) {
				var user = this.users[u];
				user.hours = 0;
			}
		},

		fetchAllProjects: function () {
			"use strict";

			this.resetValues();

			for (var i in this.projects) {
				var project = this.projects[i];

				this.fetchProject(project);
			}

			this.refresh.lastRun = Date.now();
		},

		/**
		 * fetches data for one project
		 *
		 * @param project
		 */
		fetchProject: function (project) {
			"use strict";

			var proxyUrl = '/proxy.php?source=' + project.source
				+ '&auth.type=' + project.auth.type
				+ '&auth.credentials=' + b64EncodeUnicode(project.auth.user + ':' + project.auth.pass)
				+ '&url=' + encodeURIComponent(project.url);

			if (this.start !== null) {
				proxyUrl += '&start=' + this.start;
			}
			if (this.end !== null) {
				proxyUrl += '&end=' + this.end;
			}

			this.fetching.push(project.name);

			$.getJSON(proxyUrl, function (result) {

				var workingHours = {};

				for (var username in result) {
					if (!result.hasOwnProperty(username)) continue;

					var hours = parseFloat(result[username]);

					this.users.some(function (user) {
						if (user.nickname === username) {
							user.hours += hours;
						}
					});

					workingHours[username] = hours;

					this.total.hours += hours;
					this.total.sales += hours * project.hourly_rate;
				}

				Vue.set(this.workload, project.name, workingHours);

				this.fetching.$remove(project.name);
			}.bind(this));
		},

		/**
		 * add a project
		 */
		addProject: function () {
			"use strict";

			var p = {
				name: '',
				image: '',
				source: 'trac',
				url: '',
				auth: {
					type: 'basic',
					user: '',
					pass: ''
				},
				hourly_rate: 0,
				hours: 0
			};

			for (var k in this.newProject) {
				if (this.newProject.hasOwnProperty(k) && p.hasOwnProperty(k))
					p[k] = this.newProject[k];
			}

			this.projects.push(p);

			this.newProject.name = '';
			this.newProject.image = '';
			this.newProject.source = 'trac';
			this.newProject.url = '';
			this.newProject.auth = {type: 'basic', user: '', pass: ''};
			this.newProject.hourly_rate = 0;
			this.newProject.hours = 0;

			store.set('projects', this.projects);
			$('#addProject').modal('hide');
			this.fetchProject(p);
		},

		addUser: function () {
			"use strict";

			var u = {
				nickname: '',
				name: '',
				avatar: '',
				monthly_presence: 1,
				hours: 0
			};

			for (var k in this.newUser) {
				if (this.newUser.hasOwnProperty(k) && u.hasOwnProperty(k))
					u[k] = this.newUser[k];
			}

			if (u.avatar == '') {
				u.avatar = false;
			}

			this.users.push(u);

			this.newUser.nickname = '';
			this.newUser.name = '';
			this.newUser.avatar = false;
			this.newUser.monthly_presence = 1;

			$('#addUser').modal('hide');
			store.set('users', this.users);
		},

		autoRefresh: function () {
			"use strict";

			if (this.canRefresh()) {
				this.fetchAllProjects();
			}
		},

		canRefresh: function () {
			"use strict";

			if (!this.refresh.active) {
				return false;
			}

			var timeGap = Date.now() - this.refresh.lastRun;

			return timeGap > this.refresh.pauseBeforeRefresh;
		}
	},

	computed: {
		businessDays: function () {
			return businessDays();
		}
	}
});

window.onfocus = vm.autoRefresh;
<commit_msg>fixed currency value representation<commit_after>/**
 * returns business days [past, upcoming]
 * @returns {*[]}
 */
function businessDays() {
	"use strict";

	var date = new Date();

	// Copy date
	var t = new Date(date);
	// Remember the month number
	var m = date.getMonth();
	var d = date.getDate();
	var daysPast = 0, daysToGo = 0;
	var day;

	// Count past days
	while (t.getMonth() == m) {
		day = t.getDay();
		daysPast += (day == 0 || day == 6) ? 0 : 1;
		t.setDate(--d);
	}

	// Reset and count days to come
	t = new Date(date);
	t.setDate(t.getDate() + 1);
	d = t.getDate();

	while (t.getMonth() == m) {
		day = t.getDay();
		daysToGo += (day == 0 || day == 6) ? 0 : 1;
		t.setDate(++d);
	}
	return [daysPast, daysToGo];
}

/**
 * encode base64 encoded string
 * @param str
 * @returns {string}
 */
function b64EncodeUnicode(str) {
	"use strict";

	return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
		return String.fromCharCode('0x' + p1);
	}));
}

var projectStore = store.get('projects', []);
var userStore = store.get('users', []);

Vue.filter('fixed', function (value) {
	"use strict";

	return value != undefined
		? new Intl.NumberFormat("de-DE", {minimumFractionDigits: 2, maximumFractionDigits: 2}).format(value)
		: null;
});

Vue.filter('sum', function (value) {
	"use strict";

	var project = value.name;
	var sum = 0;

	if (this.workload[project] !== undefined) {
		for (var user in this.workload[project]) {
			if (this.workload[project].hasOwnProperty(user)) {
				sum += parseFloat(this.workload[project][user]);
			}
		}
	}

	return sum;
});

Vue.filter('filterForProjectUser', function (value, p, u) {
	"use strict";

	var projectName = p.name;
	var userName = u.nickname;

	if (this.workload[projectName] === undefined)
		return;

	if (this.workload[projectName][userName] === undefined)
		return;

	return this.workload[projectName][userName];
});

var vm = new Vue({
	el: '#app',

	data: function () {
		return {
			projects: projectStore,
			newProject: {
				name: '',
				image: '',
				source: 'trac',
				url: '',
				auth: {
					type: 'basic',
					user: '',
					pass: ''
				},
				hourly_rate: 0,
				hours: 0
			},

			workload: {},
			start: moment().startOf('month'),
			end: moment().endOf('month'),

			users: userStore,
			newUser: {
				nickname: '',
				name: '',
				avatar: null,
				monthly_presence: 1,
				hours: 0
			},

			total: {
				hours: 0,
				sales: 0
			},

			fetching: [],
			showSalesValues: false,
			refresh: {
				active: true,
				pauseBeforeRefresh: 5000,
				lastRun: null
			}
		}
	},

	ready: function () {
		this.fetchAllProjects();
	},

	created: function () {
	},

	methods: {
		resetValues: function () {
			"use strict";

			this.total.hours = 0;
			this.total.sales = 0;

			for (var u in this.users) {
				var user = this.users[u];
				user.hours = 0;
			}
		},

		fetchAllProjects: function () {
			"use strict";

			this.resetValues();

			for (var i in this.projects) {
				var project = this.projects[i];

				this.fetchProject(project);
			}

			this.refresh.lastRun = Date.now();
		},

		/**
		 * fetches data for one project
		 *
		 * @param project
		 */
		fetchProject: function (project) {
			"use strict";

			var proxyUrl = '/proxy.php?source=' + project.source
				+ '&auth.type=' + project.auth.type
				+ '&auth.credentials=' + b64EncodeUnicode(project.auth.user + ':' + project.auth.pass)
				+ '&url=' + encodeURIComponent(project.url);

			if (this.start !== null) {
				proxyUrl += '&start=' + this.start;
			}
			if (this.end !== null) {
				proxyUrl += '&end=' + this.end;
			}

			this.fetching.push(project.name);

			$.getJSON(proxyUrl, function (result) {

				var workingHours = {};

				for (var username in result) {
					if (!result.hasOwnProperty(username)) continue;

					var hours = parseFloat(result[username]);

					this.users.some(function (user) {
						if (user.nickname === username) {
							user.hours += hours;
						}
					});

					workingHours[username] = hours;

					this.total.hours += hours;
					this.total.sales += hours * project.hourly_rate;
				}

				Vue.set(this.workload, project.name, workingHours);

				this.fetching.$remove(project.name);
			}.bind(this));
		},

		/**
		 * add a project
		 */
		addProject: function () {
			"use strict";

			var p = {
				name: '',
				image: '',
				source: 'trac',
				url: '',
				auth: {
					type: 'basic',
					user: '',
					pass: ''
				},
				hourly_rate: 0,
				hours: 0
			};

			for (var k in this.newProject) {
				if (this.newProject.hasOwnProperty(k) && p.hasOwnProperty(k))
					p[k] = this.newProject[k];
			}

			this.projects.push(p);

			this.newProject.name = '';
			this.newProject.image = '';
			this.newProject.source = 'trac';
			this.newProject.url = '';
			this.newProject.auth = {type: 'basic', user: '', pass: ''};
			this.newProject.hourly_rate = 0;
			this.newProject.hours = 0;

			store.set('projects', this.projects);
			$('#addProject').modal('hide');
			this.fetchProject(p);
		},

		addUser: function () {
			"use strict";

			var u = {
				nickname: '',
				name: '',
				avatar: '',
				monthly_presence: 1,
				hours: 0
			};

			for (var k in this.newUser) {
				if (this.newUser.hasOwnProperty(k) && u.hasOwnProperty(k))
					u[k] = this.newUser[k];
			}

			if (u.avatar == '') {
				u.avatar = false;
			}

			this.users.push(u);

			this.newUser.nickname = '';
			this.newUser.name = '';
			this.newUser.avatar = false;
			this.newUser.monthly_presence = 1;

			$('#addUser').modal('hide');
			store.set('users', this.users);
		},

		autoRefresh: function () {
			"use strict";

			if (this.canRefresh()) {
				this.fetchAllProjects();
			}
		},

		canRefresh: function () {
			"use strict";

			if (!this.refresh.active) {
				return false;
			}

			var timeGap = Date.now() - this.refresh.lastRun;

			return timeGap > this.refresh.pauseBeforeRefresh;
		}
	},

	computed: {
		businessDays: function () {
			return businessDays();
		}
	}
});

window.onfocus = vm.autoRefresh;
<|endoftext|>