<commit_before>/*global define, noty */

define(['jquery', 'underscore', 'backbone', 'templates', 'marionette'], function($, _, Backbone, JST) {
    'use strict';

    var AlertsView = Backbone.Marionette.ItemView.extend({
        serverErrorTemplate: _.template('Server Error (<%- status %>) <%- responseText %>. Please contact Administrator.'),
        unexpectedErrorTemplate: _.template('Unexpected Error (<%- status %>)<%- responseText %>. Please contact Administrator.'),
        parserErrorTemplate: _.template('Error decoding <%- source %> response from server. Please contact Administrator.'),
        template: JST['app/scripts/templates/alerts.ejs'],
        throttleMs: 10000,
        throttleCount: 3,
        krakenFailThreshold: 1000 * 60 * 15,
        initialize: function() {
            this.App = Backbone.Marionette.getOption(this, 'App');
            this.listenTo(this.App.vent, 'app:neterror', this.neterrorHandler);
            this.listenTo(this.App.vent, 'krakenHeartBeat:update', this.heartBeat);
            _.each(['timeout', 'serverError', 'unexpectedError', 'parserError'], function(fnName) {
                this[fnName] = _.throttle(this[fnName], this.throttleMs);
            }, this);
            this.sessionExpired = _.once(this.sessionExpired);
            this.timeout = _.after(this.throttleCount, this.timeout);
            _.bindAll(this, 'neterrorHandler', 'heartBeat');
        },
        heartBeat: function(model) {
            if (model) {
                var attrs = model.attributes;
                //jshint camelcase: false
                if (attrs) {
                    var now = Date.now();
                    var deltaAttemptMs = now - attrs.cluster_update_attempt_time_unix;
                    var deltaSuccessMs = now - attrs.cluster_update_time_unix;
                    // If time since last success exceeds threshold we
                    // have a problem with kraken
                    if (deltaSuccessMs > this.krakenFailThreshold) {
                        var msg = _.extend({}, this.notyDefaults);
                        if (deltaAttemptMs > deltaSuccessMs) {
                            // if last attempt is older than last success
                            // then it's likely kraken has failed
                            this.clusterUpdateTimeout(msg);
                        } else {
                            // kraken's still trying, we suspect cluster
                            // API communication issues
                            this.clusterAPITimeout(msg);
                        }
                    }
                }
            }
        },
        notyDefaults: {
            layout: 'top',
            type: 'error'
        },
        timeoutCount: 0,
        error: function(msg) {
            noty(msg);
        },
        warning: function(msg) {
            msg.type = 'warning';
            noty(msg);
        },
        timeout: function(msg) {
            msg.text = 'Dashboard Update Timed Out. Please check your connection.';
            this.timeoutCount++;
            this.error(msg);
            console.log('timeout count ' + this.timeoutCount);
        },
        clusterUpdateTimeout: function(msg) {
            msg.text = 'Cluster Updates Are Stale. ICE update process may have failed.';
            this.warning(msg);
        },
        clusterAPITimeout: function(msg) {
            msg.text = 'Cluster Updates Are Stale. Cluster isn\'t responding to ICE requests.';
            this.warning(msg);
        },
        sessionExpired: function(msg) {
            msg.text = 'Session Has Timed Out. Please Login again.';
            msg.buttons = [{
                addClass: 'btn btn-primary',
                text: 'Login',
                onClick: function($noty) {
                    $noty.close();
                    window.location = '/login/';
                }
            }];
            this.warning(msg);
        },
        serverError: function(msg, xhr) {
            msg.text = this.serverErrorTemplate(xhr);
            this.error(msg);
        },
        unexpectedError: function(msg, xhr) {
            msg.text = this.unexpectedErrorTemplate(xhr);
            this.error(msg);
        },
        parserError: function(msg, xhr) {
            msg.text = this.parserErrorTemplate(xhr);
            msg.timeout = 10000;
            this.error(msg);
        },
        neterrorHandler: function(source, xhr) {
            var errorType = xhr.statusText;
            if (!errorType) {
                return;
            }
            var msg = _.extend({}, this.notyDefaults);
            if (errorType === 'timeout') {
                return this.timeout(msg);
            }
            // parsererror doesn't seem to work consistently
            if (errorType === 'parsererror' || (xhr.status === 200 && errorType === 'OK')) {
                return this.parserError(msg, _.extend({
                    source: source
                }, xhr));
            }
            if (xhr.status === 403) {
                return this.sessionExpired(msg);
            }
            if (xhr.status >= 500) {
                return this.serverError(msg, xhr);
            }
            return this.unexpectedError(msg, xhr);
        }
    });

    return AlertsView;
});
<commit_msg>ICE is no more, long live Calamari<commit_after>/*global define, noty */

define(['jquery', 'underscore', 'backbone', 'templates', 'marionette'], function($, _, Backbone, JST) {
    'use strict';

    var AlertsView = Backbone.Marionette.ItemView.extend({
        serverErrorTemplate: _.template('Server Error (<%- status %>) <%- responseText %>. Please contact Administrator.'),
        unexpectedErrorTemplate: _.template('Unexpected Error (<%- status %>)<%- responseText %>. Please contact Administrator.'),
        parserErrorTemplate: _.template('Error decoding <%- source %> response from server. Please contact Administrator.'),
        template: JST['app/scripts/templates/alerts.ejs'],
        throttleMs: 10000,
        throttleCount: 3,
        krakenFailThreshold: 1000 * 60 * 15,
        initialize: function() {
            this.App = Backbone.Marionette.getOption(this, 'App');
            this.listenTo(this.App.vent, 'app:neterror', this.neterrorHandler);
            this.listenTo(this.App.vent, 'krakenHeartBeat:update', this.heartBeat);
            _.each(['timeout', 'serverError', 'unexpectedError', 'parserError'], function(fnName) {
                this[fnName] = _.throttle(this[fnName], this.throttleMs);
            }, this);
            this.sessionExpired = _.once(this.sessionExpired);
            this.timeout = _.after(this.throttleCount, this.timeout);
            _.bindAll(this, 'neterrorHandler', 'heartBeat');
        },
        heartBeat: function(model) {
            if (model) {
                var attrs = model.attributes;
                //jshint camelcase: false
                if (attrs) {
                    var now = Date.now();
                    var deltaAttemptMs = now - attrs.cluster_update_attempt_time_unix;
                    var deltaSuccessMs = now - attrs.cluster_update_time_unix;
                    // If time since last success exceeds threshold we
                    // have a problem with kraken
                    if (deltaSuccessMs > this.krakenFailThreshold) {
                        var msg = _.extend({}, this.notyDefaults);
                        if (deltaAttemptMs > deltaSuccessMs) {
                            // if last attempt is older than last success
                            // then it's likely kraken has failed
                            this.clusterUpdateTimeout(msg);
                        } else {
                            // kraken's still trying, we suspect cluster
                            // API communication issues
                            this.clusterAPITimeout(msg);
                        }
                    }
                }
            }
        },
        notyDefaults: {
            layout: 'top',
            type: 'error'
        },
        timeoutCount: 0,
        error: function(msg) {
            noty(msg);
        },
        warning: function(msg) {
            msg.type = 'warning';
            noty(msg);
        },
        timeout: function(msg) {
            msg.text = 'Dashboard Update Timed Out. Please check your connection.';
            this.timeoutCount++;
            this.error(msg);
            console.log('timeout count ' + this.timeoutCount);
        },
        clusterUpdateTimeout: function(msg) {
            msg.text = 'Cluster Updates Are Stale. Calamari update process may have failed.';
            this.warning(msg);
        },
        clusterAPITimeout: function(msg) {
            msg.text = 'Cluster Updates Are Stale. Cluster isn\'t responding to Calamari requests.';
            this.warning(msg);
        },
        sessionExpired: function(msg) {
            msg.text = 'Session Has Timed Out. Please Login again.';
            msg.buttons = [{
                addClass: 'btn btn-primary',
                text: 'Login',
                onClick: function($noty) {
                    $noty.close();
                    window.location = '/login/';
                }
            }];
            this.warning(msg);
        },
        serverError: function(msg, xhr) {
            msg.text = this.serverErrorTemplate(xhr);
            this.error(msg);
        },
        unexpectedError: function(msg, xhr) {
            msg.text = this.unexpectedErrorTemplate(xhr);
            this.error(msg);
        },
        parserError: function(msg, xhr) {
            msg.text = this.parserErrorTemplate(xhr);
            msg.timeout = 10000;
            this.error(msg);
        },
        neterrorHandler: function(source, xhr) {
            var errorType = xhr.statusText;
            if (!errorType) {
                return;
            }
            var msg = _.extend({}, this.notyDefaults);
            if (errorType === 'timeout') {
                return this.timeout(msg);
            }
            // parsererror doesn't seem to work consistently
            if (errorType === 'parsererror' || (xhr.status === 200 && errorType === 'OK')) {
                return this.parserError(msg, _.extend({
                    source: source
                }, xhr));
            }
            if (xhr.status === 403) {
                return this.sessionExpired(msg);
            }
            if (xhr.status >= 500) {
                return this.serverError(msg, xhr);
            }
            return this.unexpectedError(msg, xhr);
        }
    });

    return AlertsView;
});
<|endoftext|>


<commit_before>/**
 * @since 15-08-18 15:39
 * @author vivaxy
 */
'use strict';
var fs = require('fs'),
    path = require('path'),

    log = require('log-util'),
    images = require('images'),

    normalizePath = function (_path) {
        return path.normalize(_path).replace(/path.sep/g, '/');
    },

    imageBuilder = function (htmlFile, img, options, callback) {
        // attributes
        var src = img.attribs.src,
            dataPreloadOrigin = img.attribs['data-preload-origin'],
            originalSource = dataPreloadOrigin || src,
        // html
            htmlDirectory = path.dirname(htmlFile),
        // image
            imageFileName = path.basename(originalSource), // image file name
            originalImageAbsolutePath = path.join(htmlDirectory, originalSource), // original image absolute path
            preloadImageAbsoluteDirectory = path.join(path.dirname(originalImageAbsolutePath), 'preload'), // preload image absolute path
            preloadImageAbsolutePath = path.join(preloadImageAbsoluteDirectory, imageFileName); // preload image absolute path

        if (!fs.existsSync(preloadImageAbsoluteDirectory)) { // directory not found
            fs.mkdirSync(preloadImageAbsoluteDirectory);
        }
        if (!fs.existsSync(originalImageAbsolutePath)) {
            log.error('image not exists', htmlFile, originalSource);
        } else {
            images(originalImageAbsolutePath)
                .size(options.width)
                .save(preloadImageAbsolutePath, {
                    quality: options.quality
                });
            img.attribs['data-preload-origin'] = normalizePath(originalSource);
            img.attribs['data-preload'] = normalizePath(path.relative(htmlDirectory, originalImageAbsolutePath));
            img.attribs.src = normalizePath(path.relative(htmlDirectory, preloadImageAbsolutePath));
            log.debug('image compressed from', originalSource, 'to', img.attribs.src);
            callback && callback();
        }
    };

module.exports = imageBuilder;
<commit_msg>fix windows html path sep<commit_after>/**
 * @since 15-08-18 15:39
 * @author vivaxy
 */
'use strict';
var fs = require('fs'),
    path = require('path'),

    log = require('log-util'),
    images = require('images'),

    normalizePath = function (_path) {
        var __path = path.normalize(_path);
        if (path.sep === '\\') {
            __path = __path.replace(new RegExp(path.sep, 'g'), '/');
        }
        return __path;
    },

    imageBuilder = function (htmlFile, img, options, callback) {
        // attributes
        var src = img.attribs.src,
            dataPreloadOrigin = img.attribs['data-preload-origin'],
            originalSource = dataPreloadOrigin || src,
        // html
            htmlDirectory = path.dirname(htmlFile),
        // image
            imageFileName = path.basename(originalSource), // image file name
            originalImageAbsolutePath = path.join(htmlDirectory, originalSource), // original image absolute path
            preloadImageAbsoluteDirectory = path.join(path.dirname(originalImageAbsolutePath), 'preload'), // preload image absolute path
            preloadImageAbsolutePath = path.join(preloadImageAbsoluteDirectory, imageFileName); // preload image absolute path

        if (!fs.existsSync(preloadImageAbsoluteDirectory)) { // directory not found
            fs.mkdirSync(preloadImageAbsoluteDirectory);
        }
        if (!fs.existsSync(originalImageAbsolutePath)) {
            log.error('image not exists', htmlFile, originalSource);
        } else {
            images(originalImageAbsolutePath)
                .size(options.width)
                .save(preloadImageAbsolutePath, {
                    quality: options.quality
                });
            img.attribs['data-preload-origin'] = normalizePath(originalSource);
            img.attribs['data-preload'] = normalizePath(path.relative(htmlDirectory, originalImageAbsolutePath));
            img.attribs.src = normalizePath(path.relative(htmlDirectory, preloadImageAbsolutePath));
            log.debug('image compressed from', originalSource, 'to', img.attribs.src);
            callback && callback();
        }
    };

module.exports = imageBuilder;
<|endoftext|>


<commit_before>var control = require('./control');
var m = require('mithril');

module.exports = function(ctrl) {

  var timeout;

  this.delay = null;

  var move = function() {
    if (control.canGoForward(ctrl)) {
      control.next(ctrl);
      m.redraw();
      return true;
    }
    this.stop();
    m.redraw();
    return false;
  }.bind(this);

  var evalToCp = function(node) {
    if (!node.eval) return node.ply % 2 ? 990 : -990; // game over
    return node.eval.mate ? 990 * Math.sign(node.eval.mate) : node.eval.cp;
  };

  var nextDelay = function() {
    if (typeof(this.delay) === 'string') {
      // in a variation
      if (!ctrl.tree.pathIsMainline(ctrl.vm.path)) return 2000;
      if (this.delay === 'realtime') {
        return (ctrl.data.game.moveTimes[ctrl.vm.node.ply] * 100) || 2000;
      } else {
        var slowDown = this.delay === 'cpl_fast' ? 10 : 30;
        if (ctrl.vm.node.ply >= ctrl.vm.mainline.length - 1) return 0;
        var currPlyCp = evalToCp(ctrl.vm.node);
        var nextPlyCp = evalToCp(ctrl.vm.node.children[0]);
        return Math.max(500,
          Math.min(10000,
            Math.abs(currPlyCp - nextPlyCp) * slowDown));
      }
    }
    return this.delay;
  }.bind(this);

  var schedule = function() {
    timeout = setTimeout(function() {
      if (move()) schedule();
    }, nextDelay());
  }.bind(this);

  var start = function(delay) {
    this.delay = delay;
    this.stop();
    schedule();
  }.bind(this);

  this.stop = function() {
    if (timeout) {
      clearTimeout(timeout);
      timeout = null;
    }
  }.bind(this);

  this.toggle = function(delay) {
    if (this.active(delay)) this.stop();
    else {
      if (!this.active())
        if (!move()) ctrl.jump('');
      start(delay);
    }
  }.bind(this);

  this.active = function(delay) {
    return (!delay || delay === this.delay) && !!timeout;
  }.bind(this);
};
<commit_msg>fix realtime autoplay<commit_after>var control = require('./control');
var m = require('mithril');

module.exports = function(ctrl) {

  var timeout;

  this.delay = null;

  var move = function() {
    if (control.canGoForward(ctrl)) {
      control.next(ctrl);
      m.redraw();
      return true;
    }
    this.stop();
    m.redraw();
    return false;
  }.bind(this);

  var evalToCp = function(node) {
    if (!node.eval) return node.ply % 2 ? 990 : -990; // game over
    return node.eval.mate ? 990 * Math.sign(node.eval.mate) : node.eval.cp;
  };

  var nextDelay = function() {
    if (typeof(this.delay) === 'string') {
      // in a variation
      if (!ctrl.tree.pathIsMainline(ctrl.vm.path)) return 2000;
      if (this.delay === 'realtime') {
        if (ctrl.vm.node.ply < 2) return 2000;
        return Math.max(ctrl.data.game.moveTimes[ctrl.vm.node.ply], 1) * 100 || 2000;
      } else {
        var slowDown = this.delay === 'cpl_fast' ? 10 : 30;
        if (ctrl.vm.node.ply >= ctrl.vm.mainline.length - 1) return 0;
        var currPlyCp = evalToCp(ctrl.vm.node);
        var nextPlyCp = evalToCp(ctrl.vm.node.children[0]);
        return Math.max(500,
          Math.min(10000,
            Math.abs(currPlyCp - nextPlyCp) * slowDown));
      }
    }
    return this.delay;
  }.bind(this);

  var schedule = function() {
    timeout = setTimeout(function() {
      if (move()) schedule();
    }, nextDelay());
  }.bind(this);

  var start = function(delay) {
    this.delay = delay;
    this.stop();
    schedule();
  }.bind(this);

  this.stop = function() {
    if (timeout) {
      clearTimeout(timeout);
      timeout = null;
    }
  }.bind(this);

  this.toggle = function(delay) {
    if (this.active(delay)) this.stop();
    else {
      if (!this.active())
        if (!move()) ctrl.jump('');
      start(delay);
    }
  }.bind(this);

  this.active = function(delay) {
    return (!delay || delay === this.delay) && !!timeout;
  }.bind(this);
};
<|endoftext|>


<commit_before>/**
 * Copyright 2020 Google LLC
 *
 * 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.
 */

const { conversation } = require('@assistant/conversation');
const functions = require('firebase-functions');

const app = conversation({debug: true});

const optionsNeedA = new Set();
optionsNeedA.add('horse').add('phone');

app.handle('greeting', conv => {
  let message = 'A wondrous greeting, adventurer! Welcome to the mythical land of  Gryffinberg! Based on your clothes, you are not from around these lands. It looks like you\'re on your way to an epic journey.';
  if (conv.user.lastSeenTime) {
    message = 'A wondrous greeting, adventurer! Welcome back to the mythical land of Gryffinberg!';
  }
  conv.add(message);
});

app.handle('unavailable_options', conv => {
  const option = conv.intent.params.chosenUnavailableOption.original;
  const optionKey = conv.intent.params.chosenUnavailableOption.resolved;
  let message = 'I have seen the future and ';
  if(optionsNeedA.has(optionKey)){
    message = message + 'a';
  }
  message = message + ` ${option} will not aid you on your journey. `;
  conv.add(message);
});

exports.ActionsOnGoogleFulfillment = functions.https.onRequest(app);
<commit_msg>add undefined to lastSeenTime<commit_after>/**
 * Copyright 2020 Google LLC
 *
 * 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.
 */

const { conversation } = require('@assistant/conversation');
const functions = require('firebase-functions');

const app = conversation({debug: true});

const optionsNeedA = new Set();
optionsNeedA.add('horse').add('phone');

app.handle('greeting', conv => {
  let message = 'A wondrous greeting, adventurer! Welcome back to the mythical land of Gryffinberg!';
  if (!conv.user.lastSeenTime) {
    message = 'Welcome to the mythical land of  Gryffinberg! Based on your clothes, you are not from around these lands. It looks like you\'re on your way to an epic journey.';
  }
  conv.add(message);
});

app.handle('unavailable_options', conv => {
  const option = conv.intent.params.chosenUnavailableOption.original;
  const optionKey = conv.intent.params.chosenUnavailableOption.resolved;
  let message = 'I have seen the future and ';
  if(optionsNeedA.has(optionKey)){
    message = message + 'a';
  }
  message = message + ` ${option} will not aid you on your journey. `;
  conv.add(message);
});

exports.ActionsOnGoogleFulfillment = functions.https.onRequest(app);
<|endoftext|>


<commit_before>/**
 * Copyright 2016 The AMP HTML Authors. All Rights Reserved.
 *
 * 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.
 */

import {listen} from '../../../src/event-helper';
import {tryParseJson} from '../../../src/json';
import {dev} from '../../../src/log';

const TAG = 'amp-viewer-messaging';
const APP = '__AMPHTML__';

/**
 * @enum {string}
 */
const MessageType = {
  REQUEST: 'q',
  RESPONSE: 's',
};

/**
 * @typedef {{
 *   app: string,
 *   type: string,
 *   requestid: number,
 *   name: string,
 *   data: *,
 *   rsvp: (boolean|undefined),
 *   error: (string|undefined),
 * }}
 */
export let Message;

/**
 * @typedef {function(string, *, boolean):(!Promise<*>|undefined)}
 */
export let RequestHandler;

/**
  * @param {*} message
  * @return {?Message}
  */
export function parseMessage(message) {
  if (typeof message != 'string') {
    return /** @type {Message} */(message);
  }
  if (message.charAt(0) != '{') {
    return null;
  }
  return /** @type {?Message} */ (tryParseJson(message) || null);
}

/**
 * @fileoverview This class is a de-facto implementation of MessagePort
 * from Channel Messaging API:
 * https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API
 */
export class WindowPortEmulator {
  /**
   * @param {!Window} win
   * @param {string} origin
   */
  constructor(win, origin) {
    /** @const {!Window} */
    this.win = win;
    /** @private {string} */
    this.origin_ = origin;
  }

  /**
   * @param {string} eventType
   * @param {function(!Event):undefined} handler
   */
  addEventListener(eventType, handler) {
    listen(this.win, 'message', e => {
      if (e.origin == this.origin_ &&
          e.source == this.win.parent && e.data.app == APP) {
        handler(e);
      }
    });
  }

  /**
   * @param {Object} data
   */
  postMessage(data) {
    this.win.parent./*OK*/postMessage(data, this.origin_);
  }
  start() {
  }
}

/**
 * @fileoverview This is used in amp-viewer-integration.js for the
 * communication protocol between AMP and the viewer. In the comments, I will
 * refer to the communication as a conversation between me and Bob. The
 * messaging protocol should support both sides, but at this point I'm the
 * ampdoc and Bob is the viewer.
 */
export class Messaging {

  /**
   * Conversation (messaging protocol) between me and Bob.
   * @param {!Window} win
   * @param {!MessagePort|!WindowPortEmulator} port
   * @param {boolean} opt_isWebview
   */
  constructor(win, port, opt_isWebview) {
    /** @const {!Window} */
    this.win = win;
    /** @const @private {!MessagePort|!WindowPortEmulator} */
    this.port_ = port;
    /** @const @private */
    this.isWebview_ = !!opt_isWebview;
    /** @private {!number} */
    this.requestIdCounter_ = 0;
    /** @private {!Object<number, {resolve: function(*), reject: function(!Error)}>} */
    this.waitingForResponse_ = {};
    /**
     * A map from message names to request handlers.
     * @private {!Object<string, !RequestHandler>}
     */
    this.messageHandlers_ = {};

    /** @private {?RequestHandler} */
    this.defaultHandler_ = null;

    this.port_.addEventListener('message', this.handleMessage_.bind(this));
    this.port_.start();
  }

  /**
   * Registers a method that will handle requests sent to the specified
   * message name.
   * @param {string} messageName The name of the message to handle.
   * @param {!RequestHandler} requestHandler
   */
  registerHandler(messageName, requestHandler) {
    this.messageHandlers_[messageName] = requestHandler;
  }

  /**
   * Unregisters the handler for the specified message name.
   * @param {string} messageName The name of the message to unregister.
   */
  unregisterHandler(messageName) {
    delete this.messageHandlers_[messageName];
  }

  /**
   * @param {?RequestHandler} requestHandler
   */
  setDefaultHandler(requestHandler) {
    this.defaultHandler_ = requestHandler;
  }

  /**
   * Bob sent me a message. I need to decide if it's a new request or
   * a response to a previous 'conversation' we were having.
   * @param {!Event} event
   * @private
   */
  handleMessage_(event) {
    dev().fine(TAG, 'AMPDOC got a message:', event.type, event.data);
    const message = parseMessage(event.data);
    if (!message) {
      return;
    }
    if (message.type == MessageType.REQUEST) {
      this.handleRequest_(message);
    } else if (message.type == MessageType.RESPONSE) {
      this.handleResponse_(message);
    }
  }

  /**
   * I'm sending Bob a new outgoing request.
   * @param {string} messageName
   * @param {*} messageData
   * @param {boolean} awaitResponse
   * @return {!Promise<*>|undefined}
   */
  sendRequest(messageName, messageData, awaitResponse) {
    dev().fine(TAG, 'sendRequest, event name: ', messageName);
    const requestId = ++this.requestIdCounter_;
    let promise = undefined;
    if (awaitResponse) {
      promise = new Promise((resolve, reject) => {
        this.waitingForResponse_[requestId] = {resolve, reject};
      });
    }
    this.sendMessage_({
      app: APP,
      requestid: requestId,
      type: MessageType.REQUEST,
      name: messageName,
      data: messageData,
      rsvp: awaitResponse,
    });
    return promise;
  }

  /**
   * I'm responding to a request that Bob made earlier.
   * @param {number} requestId
   * @param {string} messageName
   * @param {*} messageData
   * @private
   */
  sendResponse_(requestId, messageName, messageData) {
    dev().fine(TAG, 'sendResponse_');
    this.sendMessage_({
      app: APP,
      requestid: requestId,
      type: MessageType.RESPONSE,
      name: messageName,
      data: messageData,
    });
  }

  /**
   * @param {number} requestId
   * @param {string} messageName
   * @param {*} reason !Error most of time, string sometimes, * rarely.
   * @private
   */
  sendResponseError_(requestId, messageName, reason) {
    const errString = this.errorToString_(reason);
    this.logError_(
      TAG + ': sendResponseError_, Message name: ' + messageName, errString);
    this.sendMessage_({
      app: APP,
      requestid: requestId,
      type: MessageType.RESPONSE,
      name: messageName,
      data: null,
      error: errString,
    });
  }

  /**
   * @param {Message} message
   * @private
   */
  sendMessage_(message) {
    this.port_./*OK*/postMessage(
      this.isWebview_ ? JSON.stringify(message) : message);
  }

  /**
   * I'm handing an incoming request from Bob. I'll either respond normally
   * (ex: "got it Bob!") or with an error (ex: "I didn't get a word of what
   * you said!").
   * @param {Message} message
   * @private
   */
  handleRequest_(message) {
    dev().fine(TAG, 'handleRequest_', message);

    let handler = this.messageHandlers_[message.name];
    if (!handler) {
      handler = this.defaultHandler_;
    }
    if (!handler) {
      throw new Error(
        'Cannot handle request because handshake is not yet confirmed!');
    }

    const promise = handler(message.name, message.data, !!message.rsvp);
    if (message.rsvp) {
      const requestId = message.requestid;
      if (!promise) {
        this.sendResponseError_(
          requestId, message.name, new Error('no response'));
        dev().assert(promise,
          'expected response but none given: ' + message.name);
      }
      promise.then(data => {
        this.sendResponse_(requestId, message.name, data);
      }, reason => {
        this.sendResponseError_(requestId, message.name, reason);
      });
    }
  }

  /**
   * I sent out a request to Bob. He responded. And now I'm handling that
   * response.
   * @param {Message} message
   * @private
   */
  handleResponse_(message) {
    dev().fine(TAG, 'handleResponse_');
    const requestId = message.requestid;
    const pending = this.waitingForResponse_[requestId];
    if (pending) {
      delete this.waitingForResponse_[requestId];
      if (message.error) {
        this.logError_(TAG + ': handleResponse_ error: ', message.error);
        pending.reject(
          new Error(`Request ${message.name} failed: ${message.error}`));
      } else {
        pending.resolve(message);
      }
    }
  }

  /**
   * @param {string} state
   * @param {!Error|string} opt_data
   * @private
   */
  logError_(state, opt_data) {
    let stateStr = 'amp-messaging-error-logger: ' + state;
    const dataStr = ' data: ' + this.errorToString_(opt_data);
    stateStr += dataStr;
    this.win['viewerState'] = stateStr;
  };

  /**
   * @param {*} err !Error most of time, string sometimes, * rarely.
   * @return {string}
   * @private
   */
  errorToString_(err) {
    return err ?
      (err.message ? err.message : String(err)) :
      'unknown error';
  }
}
<commit_msg>better error message (#8913)<commit_after>/**
 * Copyright 2016 The AMP HTML Authors. All Rights Reserved.
 *
 * 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.
 */

import {listen} from '../../../src/event-helper';
import {tryParseJson} from '../../../src/json';
import {dev} from '../../../src/log';

const TAG = 'amp-viewer-messaging';
const APP = '__AMPHTML__';

/**
 * @enum {string}
 */
const MessageType = {
  REQUEST: 'q',
  RESPONSE: 's',
};

/**
 * @typedef {{
 *   app: string,
 *   type: string,
 *   requestid: number,
 *   name: string,
 *   data: *,
 *   rsvp: (boolean|undefined),
 *   error: (string|undefined),
 * }}
 */
export let Message;

/**
 * @typedef {function(string, *, boolean):(!Promise<*>|undefined)}
 */
export let RequestHandler;

/**
  * @param {*} message
  * @return {?Message}
  */
export function parseMessage(message) {
  if (typeof message != 'string') {
    return /** @type {Message} */(message);
  }
  if (message.charAt(0) != '{') {
    return null;
  }
  return /** @type {?Message} */ (tryParseJson(message) || null);
}

/**
 * @fileoverview This class is a de-facto implementation of MessagePort
 * from Channel Messaging API:
 * https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API
 */
export class WindowPortEmulator {
  /**
   * @param {!Window} win
   * @param {string} origin
   */
  constructor(win, origin) {
    /** @const {!Window} */
    this.win = win;
    /** @private {string} */
    this.origin_ = origin;
  }

  /**
   * @param {string} eventType
   * @param {function(!Event):undefined} handler
   */
  addEventListener(eventType, handler) {
    listen(this.win, 'message', e => {
      if (e.origin == this.origin_ &&
          e.source == this.win.parent && e.data.app == APP) {
        handler(e);
      }
    });
  }

  /**
   * @param {Object} data
   */
  postMessage(data) {
    this.win.parent./*OK*/postMessage(data, this.origin_);
  }
  start() {
  }
}

/**
 * @fileoverview This is used in amp-viewer-integration.js for the
 * communication protocol between AMP and the viewer. In the comments, I will
 * refer to the communication as a conversation between me and Bob. The
 * messaging protocol should support both sides, but at this point I'm the
 * ampdoc and Bob is the viewer.
 */
export class Messaging {

  /**
   * Conversation (messaging protocol) between me and Bob.
   * @param {!Window} win
   * @param {!MessagePort|!WindowPortEmulator} port
   * @param {boolean} opt_isWebview
   */
  constructor(win, port, opt_isWebview) {
    /** @const {!Window} */
    this.win = win;
    /** @const @private {!MessagePort|!WindowPortEmulator} */
    this.port_ = port;
    /** @const @private */
    this.isWebview_ = !!opt_isWebview;
    /** @private {!number} */
    this.requestIdCounter_ = 0;
    /** @private {!Object<number, {resolve: function(*), reject: function(!Error)}>} */
    this.waitingForResponse_ = {};
    /**
     * A map from message names to request handlers.
     * @private {!Object<string, !RequestHandler>}
     */
    this.messageHandlers_ = {};

    /** @private {?RequestHandler} */
    this.defaultHandler_ = null;

    this.port_.addEventListener('message', this.handleMessage_.bind(this));
    this.port_.start();
  }

  /**
   * Registers a method that will handle requests sent to the specified
   * message name.
   * @param {string} messageName The name of the message to handle.
   * @param {!RequestHandler} requestHandler
   */
  registerHandler(messageName, requestHandler) {
    this.messageHandlers_[messageName] = requestHandler;
  }

  /**
   * Unregisters the handler for the specified message name.
   * @param {string} messageName The name of the message to unregister.
   */
  unregisterHandler(messageName) {
    delete this.messageHandlers_[messageName];
  }

  /**
   * @param {?RequestHandler} requestHandler
   */
  setDefaultHandler(requestHandler) {
    this.defaultHandler_ = requestHandler;
  }

  /**
   * Bob sent me a message. I need to decide if it's a new request or
   * a response to a previous 'conversation' we were having.
   * @param {!Event} event
   * @private
   */
  handleMessage_(event) {
    dev().fine(TAG, 'AMPDOC got a message:', event.type, event.data);
    const message = parseMessage(event.data);
    if (!message) {
      return;
    }
    if (message.type == MessageType.REQUEST) {
      this.handleRequest_(message);
    } else if (message.type == MessageType.RESPONSE) {
      this.handleResponse_(message);
    }
  }

  /**
   * I'm sending Bob a new outgoing request.
   * @param {string} messageName
   * @param {*} messageData
   * @param {boolean} awaitResponse
   * @return {!Promise<*>|undefined}
   */
  sendRequest(messageName, messageData, awaitResponse) {
    dev().fine(TAG, 'sendRequest, event name: ', messageName);
    const requestId = ++this.requestIdCounter_;
    let promise = undefined;
    if (awaitResponse) {
      promise = new Promise((resolve, reject) => {
        this.waitingForResponse_[requestId] = {resolve, reject};
      });
    }
    this.sendMessage_({
      app: APP,
      requestid: requestId,
      type: MessageType.REQUEST,
      name: messageName,
      data: messageData,
      rsvp: awaitResponse,
    });
    return promise;
  }

  /**
   * I'm responding to a request that Bob made earlier.
   * @param {number} requestId
   * @param {string} messageName
   * @param {*} messageData
   * @private
   */
  sendResponse_(requestId, messageName, messageData) {
    dev().fine(TAG, 'sendResponse_');
    this.sendMessage_({
      app: APP,
      requestid: requestId,
      type: MessageType.RESPONSE,
      name: messageName,
      data: messageData,
    });
  }

  /**
   * @param {number} requestId
   * @param {string} messageName
   * @param {*} reason !Error most of time, string sometimes, * rarely.
   * @private
   */
  sendResponseError_(requestId, messageName, reason) {
    const errString = this.errorToString_(reason);
    this.logError_(
      TAG + ': sendResponseError_, Message name: ' + messageName, errString);
    this.sendMessage_({
      app: APP,
      requestid: requestId,
      type: MessageType.RESPONSE,
      name: messageName,
      data: null,
      error: errString,
    });
  }

  /**
   * @param {Message} message
   * @private
   */
  sendMessage_(message) {
    this.port_./*OK*/postMessage(
      this.isWebview_ ? JSON.stringify(message) : message);
  }

  /**
   * I'm handing an incoming request from Bob. I'll either respond normally
   * (ex: "got it Bob!") or with an error (ex: "I didn't get a word of what
   * you said!").
   * @param {Message} message
   * @private
   */
  handleRequest_(message) {
    dev().fine(TAG, 'handleRequest_', message);

    let handler = this.messageHandlers_[message.name];
    if (!handler) {
      handler = this.defaultHandler_;
    }
    if (!handler) {
      const error = new Error(
        'Cannot handle request because handshake is not yet confirmed!');
      error.args = message.name;
      throw error;
    }

    const promise = handler(message.name, message.data, !!message.rsvp);
    if (message.rsvp) {
      const requestId = message.requestid;
      if (!promise) {
        this.sendResponseError_(
          requestId, message.name, new Error('no response'));
        dev().assert(promise,
          'expected response but none given: ' + message.name);
      }
      promise.then(data => {
        this.sendResponse_(requestId, message.name, data);
      }, reason => {
        this.sendResponseError_(requestId, message.name, reason);
      });
    }
  }

  /**
   * I sent out a request to Bob. He responded. And now I'm handling that
   * response.
   * @param {Message} message
   * @private
   */
  handleResponse_(message) {
    dev().fine(TAG, 'handleResponse_');
    const requestId = message.requestid;
    const pending = this.waitingForResponse_[requestId];
    if (pending) {
      delete this.waitingForResponse_[requestId];
      if (message.error) {
        this.logError_(TAG + ': handleResponse_ error: ', message.error);
        pending.reject(
          new Error(`Request ${message.name} failed: ${message.error}`));
      } else {
        pending.resolve(message);
      }
    }
  }

  /**
   * @param {string} state
   * @param {!Error|string} opt_data
   * @private
   */
  logError_(state, opt_data) {
    let stateStr = 'amp-messaging-error-logger: ' + state;
    const dataStr = ' data: ' + this.errorToString_(opt_data);
    stateStr += dataStr;
    this.win['viewerState'] = stateStr;
  };

  /**
   * @param {*} err !Error most of time, string sometimes, * rarely.
   * @return {string}
   * @private
   */
  errorToString_(err) {
    return err ?
      (err.message ? err.message : String(err)) :
      'unknown error';
  }
}
<|endoftext|>


<commit_before>/* eslint-disable import/no-extraneous-dependencies */
import 'jquery-ui/ui/widgets/dialog';
import 'notifyjs-browser';
import View from './View';
import '../../common/binary-ui/dropdown';
import Elevio from '../../common/elevio';
import GTM from '../../common/gtm';
import { isProduction } from '../../common/utils/tools';

$.ajaxSetup({
    cache: false,
});

// eslint-disable-next-line no-underscore-dangle
window._trackJs = {
    token      : process.env.TRACKJS_TOKEN,
    application: 'binary-bot',
    enabled    : isProduction(),
    console    : {
        display: false,
    },
};

// Should stay below the window._trackJs config
require('trackjs');

const view = new View();

view.initPromise.then(() => {
    $('.show-on-load').show();
    $('.barspinner').hide();
    window.dispatchEvent(new Event('resize'));
    Elevio.init();
    GTM.init();
    trackJs.configure({
        userId: $('.account-id')
            .first()
            .text(),
    });
});
<commit_msg>added check on trackjs<commit_after>/* eslint-disable import/no-extraneous-dependencies */
import 'jquery-ui/ui/widgets/dialog';
import 'notifyjs-browser';
import View from './View';
import '../../common/binary-ui/dropdown';
import Elevio from '../../common/elevio';
import GTM from '../../common/gtm';
import { isProduction } from '../../common/utils/tools';

$.ajaxSetup({
    cache: false,
});

// eslint-disable-next-line no-underscore-dangle
window._trackJs = {
    token      : process.env.TRACKJS_TOKEN,
    application: 'binary-bot',
    enabled    : isProduction(),
    console    : {
        display: false,
    },
};

// Should stay below the window._trackJs config
require('trackjs');

const view = new View();

view.initPromise.then(() => {
    $('.show-on-load').show();
    $('.barspinner').hide();
    window.dispatchEvent(new Event('resize'));
    Elevio.init();
    GTM.init();
    trackJs?.configure({
        userId: $('.account-id')
            .first()
            .text(),
    });
});
<|endoftext|>


<commit_before>import $ from '$';
import _ from 'lodash';
import loginModal from './login';
import changePasswordModal from './change-password';
export default class user{
  constructor($http,$localStorage,$window,$q,$uibModal, api){
    this.api = api;
    this.$http = $http;
    this.$storage = $localStorage;
    this.$q = $q;
    this.$window = $window;
    this.$uibModal = $uibModal;
    this.username = $('body').attr('username');
    this.data = null;
    this.init();
  }
  check(value){
    const config = {
      method: 'HEAD',
      url: 'api/users',
      params: {}
    };
    config.params[this.username] = value;
    return this.$http(config);
  }
  get authenticated(){
    return this.$storage._id && this.$storage.token ? true : false;
  }
  set authenticated(data){
    this.$storage.token = data.token;
    this.$storage._id = data._id;
    this.$storage.role = data.role;
    this.api.setToken(data.token);
  }
  get _id(){
    return this.$storage._id;
  }
  get token(){
    return this.$storage.token;
  }
  get role(){
    if(!this.authenticated){return 'anonymous';}
    return this.$storage.role;
  }
  init(){
    if(!this.authenticated){
      return this.inauthenticate();
    }
    return this.$http.get('api/users/'+this.$storage._id)
    .then(
      (res) => {
        this.data = res.data;
        this.$storage.role = res.data.role;
        return res;
      },
      (e) => {
        this.inauthenticate();
        return e;
      }
    );
  }
  basicAuth(form){
    const name = form[this.username];
    const pass = form.password;
    if(!name || !pass){
      throw Error('missing credentials');
    }
    const str = this.$window.btoa(`${name}:${pass}`);
    return `basic ${str}`;
  }
  authenticate(form,init){
    const authorization = this.basicAuth(form);
    const config = {
      method: 'GET',
      url: 'api/tokens/new',
      headers: {authorization}
    };
    return this.$http(config)
    .then((res) => {
      this.authenticated = res.data;
      if(!init){
        return res.data;
      }
      return this.init();
    });
  }
  inauthenticate(){
    this.$storage.$reset();
    this.data = null;
    this.api.token.value = null;
  }
  create(form){
    return this.$http.post('api/users', form)
    .then((res) => {
      this.data = res.data;
      return res;
    });
  }
  addUnit(id){
    if(_.some(this.data.done,{unit: id})){
      return;
    }
    const item = {
      unit: id
    };
    const config = {
      method: 'POST',
      url: `api/users/${this.data._id}/done`,
      data: item
    };
    this.$http(config)
    .then((res) => {
      this.data.done.push(res.data);
    });
  }
  complete(unit){
    if(!this.authenticated){
      return false;
    }
    return _.some(this.data.done,{unit: unit});
  }
  requiresComplete(requires){
    if(!this.authenticated){
      return false;
    }
    return _.every(requires, _.bind(function(val){
      return _.some(this.data.done,{unit: val});
    },this));
  }
  remove(){
    return this.$http.delete('api/users/'+this.data._id)
    .then(() => this.inauthenticate());
  }
  login(){
    return this.$uibModal.open(loginModal);
  }
  changePassword(){
    return this.$uibModal.open(changePasswordModal);
  }
}
user.$inject = ['$http', '$localStorage', '$window', '$q', '$uibModal', 'api'];
<commit_msg>Convert basic auth string tu utf-8 before sending request<commit_after>import $ from '$';
import _ from 'lodash';
import utf8 from 'utf8';
import loginModal from './login';
import changePasswordModal from './change-password';
export default class user{
  constructor($http,$localStorage,$window,$q,$uibModal, api){
    this.api = api;
    this.$http = $http;
    this.$storage = $localStorage;
    this.$q = $q;
    this.$window = $window;
    this.$uibModal = $uibModal;
    this.username = $('body').attr('username');
    this.data = null;
    this.init();
  }
  check(value){
    const config = {
      method: 'HEAD',
      url: 'api/users',
      params: {}
    };
    config.params[this.username] = value;
    return this.$http(config);
  }
  get authenticated(){
    return this.$storage._id && this.$storage.token ? true : false;
  }
  set authenticated(data){
    this.$storage.token = data.token;
    this.$storage._id = data._id;
    this.$storage.role = data.role;
    this.api.setToken(data.token);
  }
  get _id(){
    return this.$storage._id;
  }
  get token(){
    return this.$storage.token;
  }
  get role(){
    if(!this.authenticated){return 'anonymous';}
    return this.$storage.role;
  }
  init(){
    if(!this.authenticated){
      return this.inauthenticate();
    }
    return this.$http.get('api/users/'+this.$storage._id)
    .then(
      (res) => {
        this.data = res.data;
        this.$storage.role = res.data.role;
        return res;
      },
      (e) => {
        this.inauthenticate();
        return e;
      }
    );
  }
  basicAuth(form){
    const name = form[this.username];
    const pass = form.password;
    if(!name || !pass){
      throw Error('missing credentials');
    }
    const bytes = utf8.encode(`${name}:${pass}`);
    const str = this.$window.btoa(bytes);
    console.log(str);
    return `basic ${str}`;
  }
  authenticate(form,init){
    const authorization = this.basicAuth(form);
    const config = {
      method: 'GET',
      url: 'api/tokens/new',
      headers: {authorization}
    };
    return this.$http(config)
    .then((res) => {
      this.authenticated = res.data;
      if(!init){
        return res.data;
      }
      return this.init();
    });
  }
  inauthenticate(){
    this.$storage.$reset();
    this.data = null;
    this.api.token.value = null;
  }
  create(form){
    return this.$http.post('api/users', form)
    .then((res) => {
      this.data = res.data;
      return res;
    });
  }
  addUnit(id){
    if(_.some(this.data.done,{unit: id})){
      return;
    }
    const item = {
      unit: id
    };
    const config = {
      method: 'POST',
      url: `api/users/${this.data._id}/done`,
      data: item
    };
    this.$http(config)
    .then((res) => {
      this.data.done.push(res.data);
    });
  }
  complete(unit){
    if(!this.authenticated){
      return false;
    }
    return _.some(this.data.done,{unit: unit});
  }
  requiresComplete(requires){
    if(!this.authenticated){
      return false;
    }
    return _.every(requires, _.bind(function(val){
      return _.some(this.data.done,{unit: val});
    },this));
  }
  remove(){
    return this.$http.delete('api/users/'+this.data._id)
    .then(() => this.inauthenticate());
  }
  login(){
    return this.$uibModal.open(loginModal);
  }
  changePassword(){
    return this.$uibModal.open(changePasswordModal);
  }
}
user.$inject = ['$http', '$localStorage', '$window', '$q', '$uibModal', 'api'];
<|endoftext|>


<commit_before>var active_form, showForm, updateImageName, cloneMore, mapNavLink, getLastTextNode, formIsClean;

active_form = 0;

showForm = function(id) {
  var name;
  $('.image-form').hide();
  active_form = id;
  $('.image-form#image-' + active_form).show();
  name = $("input#id_image_set-" + active_form + "-name").val();
  if (!name) {
    name = '[untitled image]';
  }
  updateImageName(name);

  if($('#empty_collection_msg').is(":visible")) {
    $('#empty_collection_msg').hide();
  }
  $('#id_image_set-' + active_form + '-cognitive_paradigm_cogatlas').css("width", "400px");
  $('#id_image_set-' + active_form + '-cognitive_paradigm_cogatlas').select2({ dropdownAutoWidth : true});

  return $("input#id_image_set-" + active_form + "-name").keyup(function(e) {
    var val;
    val = $(e.target).val();
    return updateImageName(val);
  });
};

getLastTextNode = function(selector) {
  return $(selector).contents().filter(function() {
    return this.nodeType == 3;
  }).last();
};

updateImageName = function(name) {
  $('#current-image').text(name);
  return getLastTextNode('#image-select li#showform-image-' + active_form + ' a').replaceWith(' ' + name);
};

cloneMore = function (selector, type, imgtype) {
  var newElement = $(selector).clone(true);
  var total = $('#id_' + type + '_set-TOTAL_FORMS').val();
  newElement.children().each(function(n,ele) {
    if($(this).attr('type') == 'hidden') return true;
    $(this).remove();
  });

  newElement.find(':input').each(function() {
    if ($(this).attr('name') == 'csrfmiddlewaretoken') return true;
    var name = $(this).attr('name').replace('-' + (total-1) + '-','-' + total + '-');
    var id = 'id_' + name;
    $(this).attr({'name': name, 'id': id}).removeAttr('checked');
    if($(this).attr('name').search('collection') > -1) return true;
    $(this).val('')
  });

  $('#blank_'+imgtype).children().each(function() {
    if($(this).attr('id').search('collection') > -1) return true;
    newElement.append($(this).clone(true));
  });

  newElement.find('div.control-group').each(function(n,n_ele) {
    rname = $(this).attr('id').replace('div_id_','');
    name = type + '_set-' + (total) + '-' + rname;
    $(n_ele).attr('id', $(this).attr('id').replace(rname,name));
    $(n_ele).find('label').each(function(n,ele) {
      $(ele).attr('for', $(ele).attr('for').replace(rname,name));
    });
    $.each(['input','select','textarea'], function(i, etype) {
      $(n_ele).find(etype).each(function(n,ele) {
        $(ele).attr('id', $(ele).attr('id').replace(rname,name));
        $(ele).attr('name', $(ele).attr('name').replace(rname,name));
      });
    });
  });

  total++;
  $('#id_' + type + '_set-TOTAL_FORMS').val(total);

  if(total === 1) {
    $(selector).replaceWith(newElement);
  } else {
    $(selector).after(newElement);
  }
};

mapNavLink = function(ele) {
  $(ele).siblings().removeClass('active');
  $(ele).addClass('active');
  id = $(ele).attr('id').replace('showform-image-','');
  return showForm(id);
};

formIsClean = function(sele) {
  if(typeof sele === "undefined") {
    sele = '.image-form';
  }
  if($(sele).find('div.errors').length === 0 &&
        $(sele).find('div.error').length === 0 &&
        $(sele).find('div.alert-error').length === 0) {
    return true;
  } else {
    return false;
  }
};

$(document).ready(function() {

  $('#image-select li').click(function(e) {
    e.preventDefault();
    mapNavLink(this);
  });

  $('#submit-form').click(function(e) {
    e.preventDefault();
    ret = $('#formset').submit();

    $('.image-form').each(function(ele) {
	    if(!formIsClean('.image-form#' + $(this).attr('id'))) {
	    	$($('#showform-' + $(this).attr('id')).children()[0]).css('color', '#b94a48')
	    }
    });
    return ret;
  });

  $('#add-image-form').click(function(e) {
    e.preventDefault();
    var nextIndex;
    var newType = e.target.href.split('#')[1];

    if(newType == 'zip') return uploadZip();
    cloneMore('div.image-form:last', 'image', newType);
    nextIndex = $('.image-form').length - 1;
    $('#image-select').append($('
 [new image]
'));
    $('.image-form:last').attr('id', 'image-' + nextIndex);
    $('#image-select li:last').siblings().removeClass('active');
    $('#image-select li:last').addClass('active');
    $('#image-select li:last').click(function(e) {
      e.preventDefault();
      mapNavLink(this);
    });

    return showForm(nextIndex);
  });

  var num_forms = $('.image-form').length;

  // extra blank form isn't sent when there are errors

  if (num_forms > 1 && formIsClean()) {
    $('.image-form').last().remove();
    $('#id_image_set-TOTAL_FORMS').val(num_forms - 1);
    $('#image-select li').last().remove()
  }

  if(num_forms === 1 && formIsClean()) {
    $("#id_image_set-" + (num_forms - 1) + "-id").val('');
  }

  //paint invalid forms red
  $('.image-form').each(function(ele) {
	    if(!formIsClean('.image-form#' + $(this).attr('id'))) {
	    	$($('#showform-' + $(this).attr('id')).children()[0]).css('color', '#b94a48')
	    }
  });

  // focus first error on any form
  $('.image-form').each(function(ele) {
    if(!formIsClean('.image-form#' + $(this).attr('id'))) {
      return mapNavLink($('#showform-' + $(this).attr('id')));
    }
  });

  showForm(active_form);

  // populate 'no images' view for completely empty collection

  if( !$('input#id_image_set-0-id').val() && num_forms === 1 && formIsClean()) {
    $('.image-form').last().hide();
    $('#id_image_set-TOTAL_FORMS').val(num_forms - 1);
    $('#image-select li').last().remove();
    $('#current-image').text('no images');
    $('#empty_collection_msg').show();
  }

  return $("input[id$='image_ptr']").each(function() {
    if ($(this).val() === "None") {
      return $(this).val("");
    }
  });

});

<commit_msg>fixed form js copy when cache keys are used<commit_after>var active_form, showForm, updateImageName, cloneMore, mapNavLink, getLastTextNode, formIsClean;

active_form = 0;

showForm = function(id) {
  var name;
  $('.image-form').hide();
  active_form = id;
  $('.image-form#image-' + active_form).show();
  name = $("input#id_image_set-" + active_form + "-name").val();
  if (!name) {
    name = '[untitled image]';
  }
  updateImageName(name);

  if($('#empty_collection_msg').is(":visible")) {
    $('#empty_collection_msg').hide();
  }
  $('#id_image_set-' + active_form + '-cognitive_paradigm_cogatlas').css("width", "400px");
  $('#id_image_set-' + active_form + '-cognitive_paradigm_cogatlas').select2({ dropdownAutoWidth : true});

  return $("input#id_image_set-" + active_form + "-name").keyup(function(e) {
    var val;
    val = $(e.target).val();
    return updateImageName(val);
  });
};

getLastTextNode = function(selector) {
  return $(selector).contents().filter(function() {
    return this.nodeType == 3;
  }).last();
};

updateImageName = function(name) {
  $('#current-image').text(name);
  return getLastTextNode('#image-select li#showform-image-' + active_form + ' a').replaceWith(' ' + name);
};

cloneMore = function (selector, type, imgtype) {
  var newElement = $(selector).clone(true);
  var total = $('#id_' + type + '_set-TOTAL_FORMS').val();
  newElement.children().each(function(n,ele) {
    if($(this).attr('type') == 'hidden') return true;
    $(this).remove();
  });

  newElement.find(':input').each(function() {
    if ($(this).attr('name') == 'csrfmiddlewaretoken') return true;
    var name = $(this).attr('name').replace('-' + (total-1) + '-','-' + total + '-');
    var id = 'id_' + name;
    $(this).attr({'name': name, 'id': id}).removeAttr('checked');
    if($(this).attr('name').search('collection') > -1) return true;
    $(this).val('')
  });

  $('#blank_'+imgtype).children().each(function() {
    if($(this).attr('id').search('collection') > -1) return true;
    newElement.append($(this).clone(true));
  });

  newElement.find('div.control-group').each(function(n,n_ele) {
    rname = $(this).attr('id').replace('div_id_','');
    name = type + '_set-' + (total) + '-' + rname;
    $(n_ele).attr('id', $(this).attr('id').replace(rname,name));
    $(n_ele).find('label').each(function(n,ele) {
      $(ele).attr('for', $(ele).attr('for').replace(rname,name));
    });
    $.each(['input','select','textarea'], function(i, etype) {
      $(n_ele).find(etype).each(function(n,ele) {
      	if ($(ele).attr('id')){
          $(ele).attr('id', $(ele).attr('id').replace(rname,name));
          $(ele).attr('name', $(ele).attr('name').replace(rname,name));
      	}
      });
    });
  });

  total++;
  $('#id_' + type + '_set-TOTAL_FORMS').val(total);

  if(total === 1) {
    $(selector).replaceWith(newElement);
  } else {
    $(selector).after(newElement);
  }
};

mapNavLink = function(ele) {
  $(ele).siblings().removeClass('active');
  $(ele).addClass('active');
  id = $(ele).attr('id').replace('showform-image-','');
  return showForm(id);
};

formIsClean = function(sele) {
  if(typeof sele === "undefined") {
    sele = '.image-form';
  }
  if($(sele).find('div.errors').length === 0 &&
        $(sele).find('div.error').length === 0 &&
        $(sele).find('div.alert-error').length === 0) {
    return true;
  } else {
    return false;
  }
};

$(document).ready(function() {

  $('#image-select li').click(function(e) {
    e.preventDefault();
    mapNavLink(this);
  });

  $('#submit-form').click(function(e) {
    e.preventDefault();
    ret = $('#formset').submit();

    $('.image-form').each(function(ele) {
	    if(!formIsClean('.image-form#' + $(this).attr('id'))) {
	    	$($('#showform-' + $(this).attr('id')).children()[0]).css('color', '#b94a48')
	    }
    });
    return ret;
  });

  $('#add-image-form').click(function(e) {
    e.preventDefault();
    var nextIndex;
    var newType = e.target.href.split('#')[1];

    if(newType == 'zip') return uploadZip();
    cloneMore('div.image-form:last', 'image', newType);
    nextIndex = $('.image-form').length - 1;
    $('#image-select').append($('
 [new image]
'));
    $('.image-form:last').attr('id', 'image-' + nextIndex);
    $('#image-select li:last').siblings().removeClass('active');
    $('#image-select li:last').addClass('active');
    $('#image-select li:last').click(function(e) {
      e.preventDefault();
      mapNavLink(this);
    });

    return showForm(nextIndex);
  });

  var num_forms = $('.image-form').length;

  // extra blank form isn't sent when there are errors

  if (num_forms > 1 && formIsClean()) {
    $('.image-form').last().remove();
    $('#id_image_set-TOTAL_FORMS').val(num_forms - 1);
    $('#image-select li').last().remove()
  }

  if(num_forms === 1 && formIsClean()) {
    $("#id_image_set-" + (num_forms - 1) + "-id").val('');
  }

  //paint invalid forms red
  $('.image-form').each(function(ele) {
	    if(!formIsClean('.image-form#' + $(this).attr('id'))) {
	    	$($('#showform-' + $(this).attr('id')).children()[0]).css('color', '#b94a48')
	    }
  });

  // focus first error on any form
  $('.image-form').each(function(ele) {
    if(!formIsClean('.image-form#' + $(this).attr('id'))) {
      return mapNavLink($('#showform-' + $(this).attr('id')));
    }
  });

  showForm(active_form);

  // populate 'no images' view for completely empty collection

  if( !$('input#id_image_set-0-id').val() && num_forms === 1 && formIsClean()) {
    $('.image-form').last().hide();
    $('#id_image_set-TOTAL_FORMS').val(num_forms - 1);
    $('#image-select li').last().remove();
    $('#current-image').text('no images');
    $('#empty_collection_msg').show();
  }

  return $("input[id$='image_ptr']").each(function() {
    if ($(this).val() === "None") {
      return $(this).val("");
    }
  });

});

<|endoftext|>


<commit_before>const webpack = require('webpack')
const { environment } = require('@rails/webpacker')

environment.loaders.delete('file')
environment.loaders.set('svg', {
  test: /\.svg$/,
  loader: 'raw-loader',
})
environment.loaders.set('yaml', {
  test: /\.yaml$|\.yml$/,
  use: [{ loader: 'json-loader' }, { loader: 'yaml-loader' }],
})

environment.plugins.set(
  'CommonsChunkVendor',
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor',
    minChunks: module => {
      // this assumes your vendor imports exist in the node_modules directory
      return module.context && module.context.indexOf('node_modules') !== -1
    },
  })
)

environment.plugins.set(
  'CommonsChunkManifest',
  new webpack.optimize.CommonsChunkPlugin({
    name: 'manifest',
    minChunks: Infinity,
  })
)

module.exports = environment
<commit_msg>chore: enable file-loader for all but svg, rather than just deleting it<commit_after>const webpack = require('webpack')
const { environment } = require('@rails/webpacker')

environment.loaders.get(
  'file'
).test = /\.(jpg|jpeg|png|gif|eot|otf|ttf|woff|woff2)$/i

environment.loaders.set('svg', {
  test: /\.svg$/,
  loader: 'raw-loader',
})
environment.loaders.set('yaml', {
  test: /\.yaml$|\.yml$/,
  use: [{ loader: 'json-loader' }, { loader: 'yaml-loader' }],
})

environment.plugins.set(
  'CommonsChunkVendor',
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor',
    minChunks: module => {
      // this assumes your vendor imports exist in the node_modules directory
      return module.context && module.context.indexOf('node_modules') !== -1
    },
  })
)

environment.plugins.set(
  'CommonsChunkManifest',
  new webpack.optimize.CommonsChunkPlugin({
    name: 'manifest',
    minChunks: Infinity,
  })
)

module.exports = environment
<|endoftext|>


<commit_before>import usersReducer from '../static/js/reducers/users';
import userInformationReducer from '../static/js/reducers/userDetailInformation';
import * as types from '../static/js/constants';

describe('Test all the reducers', () => {
  let USER_DETAIL_INFO,
    EMPTY_USER_INFO,
    DEFAULT = '';
  beforeAll(() => {
    USER_DETAIL_INFO = types.USER_DETAIL_INFO;
    EMPTY_USER_INFO = types.EMPTY_USER_INFO;
  });

  describe('Test the users reducer', () => {
    it('should return the initial state', () => {
      expect(usersReducer(undefined, {})).toEqual([]);
    });
  });

  describe('Test the userInformation reducer', () => {
    it('should return default state when passed EMPTY string for default action', () => {
      expect(
          userInformationReducer(
            [
                  { email: 'handersonj@about.com', first_name: 'Harry', gender: 'Male', id: 20, last_name: 'Anderson' }
            ],
            {
              type: DEFAULT
            },
          ),
        )
        .toEqual(
        [
          { email: 'handersonj@about.com', first_name: 'Harry', gender: 'Male', id: 20, last_name: 'Anderson' }
        ],
      );
    });

    it('should return EMPTY object when passed EMPTY_USER_INFO action', () => {
      expect(
          userInformationReducer(
            [
                  { email: 'handersonj@about.com', first_name: 'Harry', gender: 'Male', id: 20, last_name: 'Anderson' }
            ],
            {
              type: EMPTY_USER_INFO
            },
          ),
      ).toEqual({});
    });

    it('should add newer object properties when passed USER_DETAIL_INFO action', () => {
      expect(
        userInformationReducer(
            [],
          {
            type: USER_DETAIL_INFO,
            email: 'handersonj@about.com',
            firstName: 'Harry',
            gender: 'Male',
            id: 20,
            lastName: 'Anderson'
          },
      )).toEqual(
        { email: 'handersonj@about.com', firstName: 'Harry', gender: 'Male', id: 20, lastName: 'Anderson' },
      );
    });
  });
});
<commit_msg>Add reducer ADD_NEW_USER test.<commit_after>import usersReducer from '../static/js/reducers/users';
import userInformationReducer from '../static/js/reducers/userDetailInformation';
import * as types from '../static/js/constants';

describe('Test all the reducers', () => {
  let USER_DETAIL_INFO,
    EMPTY_USER_INFO,
    ADD_NEW_USER,
    DEFAULT = '';
  beforeAll(() => {
    USER_DETAIL_INFO = types.USER_DETAIL_INFO;
    EMPTY_USER_INFO = types.EMPTY_USER_INFO;
    ADD_NEW_USER = types.ADD_NEW_USER;
  });

  describe('Test the users reducer', () => {
    it('should return the initial state', () => {
      expect(usersReducer(undefined, {})).toEqual([]);
    });
  });

  describe('Test the userInformation reducer', () => {
    it('should return default state when passed EMPTY string for default action', () => {
      expect(
          userInformationReducer(
            [
              { email: 'handersonj@about.com', first_name: 'Harry', gender: 'Male', id: 20, last_name: 'Anderson' }
            ],
            {
              type: DEFAULT
            }
          )
        )
        .toEqual(
        [
          { email: 'handersonj@about.com', first_name: 'Harry', gender: 'Male', id: 20, last_name: 'Anderson' }
        ],
      );
    });

    it('should return EMPTY object when passed EMPTY_USER_INFO action', () => {
      expect(
          userInformationReducer(
            [
              { email: 'handersonj@about.com', first_name: 'Harry', gender: 'Male', id: 20, last_name: 'Anderson' }
            ],
            {
              type: EMPTY_USER_INFO
            },
          )
      ).toEqual({});
    });

    it('should return object properties when passed ADD_NEW_USER action', () => {
      expect(
        userInformationReducer(
          [],
          {
            type: USER_DETAIL_INFO,
            email: 'handersonj@about.com',
            firstName: 'Harry',
            gender: 'Male',
            id: 20,
            lastName: 'Anderson'
          },
          {
            type: USER_DETAIL_INFO
          }
      )).toEqual(
        { email: 'handersonj@about.com', firstName: 'Harry', gender: 'Male', id: 20, lastName: 'Anderson' },
      );
    });

    it('should add newer object properties when passed USER_DETAIL_INFO action', () => {
      const expected = [{ email: 'johnrambo@badass.net', first_name: 'John', last_name: 'Rambo', gender: 'Male', id: 1}];
      expect(
        userInformationReducer(
          [],
          {
            type: ADD_NEW_USER,
            email: 'johnrambo@badass.net',
            firstName: 'John',
            lastName: 'Rambo',
            gender: 'Male',
            id: 1
          },
          {
            type: ADD_NEW_USER
          }
      )).toEqual(expect.arrayContaining(expected)['sample']);
    });
  });
});
<|endoftext|>