<commit_before>import util from 'util';
import { Transform } from 'stream';

/**
 * "Init" state
 * @description :: State which indicates that StreamReader is initializing
 * @type {Number}
 * @private
 */
const INIT_STATE = 1;

/**
 * "Buffering" state
 * @description :: State which indicates that StreamReader is grabbing data to buffer
 * @type {Number}
 * @private
 */
const BUFFERING_STATE = 2;

/**
 * "Pass through" state
 * @description :: State which indicates that StreamReader is just sends data without caching
 * @type {Number}
 * @private
 */
const PASSTHROUGH_STATE = 3;

/**
 * Block size of metadata
 * @description :: How many bytes need to multiply to number from response.headers['icy-metaint']
 * @type {Number}
 * @private
 */
const METADATA_BLOCK_SIZE = 16;

/**
 * Parse metadata to object
 * @param {Buffer|String} metadata Buffer or string with metadata information
 * @returns {Object}
 * @private
 */
const _parseMetadata = metadata => {
  const data = Buffer.isBuffer(metadata) ? metadata.toString('utf8') : metadata || '';
  const result = {};

  data.replace(/\0*$/, '').split(';').forEach(item => {
    item = item.split(/\=['"]/);
    result[item[0]] = String(item[1]).replace(/['"]$/, '');
  });

  return result;
};

/**
 * Helper method that returns trampolined function
 * @param {Function} fn Function that need to trampoline
 * @returns {Function} Returns trampolined function
 * @private
 */
const _trampoline = fn => {
  return () => {
    let result = fn.apply(this, arguments);
    while (typeof result === 'function') result = result();
    return result;
  };
};

/**
 * Process one chunk of data
 * @param {StreamReader} stream StreamReader instance
 * @param {Buffer} chunk Chunk of data
 * @param {Function} done Triggers when processing is done
 * @returns {Function}
 * @private
 */
const _processData = (stream, chunk, done) => {
  stream._bytesLeft -= chunk.length;

  if (stream._currentState === BUFFERING_STATE) {
    stream._buffers.push(chunk);
    stream._buffersLength += chunk.length;
  } else if (stream._currentState === PASSTHROUGH_STATE) {
    stream.push(chunk);
  }

  if (stream._bytesLeft === 0) {
    const cb = stream._callback;

    if (cb && stream._currentState === BUFFERING_STATE && stream._buffers.length > 1) {
      chunk = Buffer.concat(stream._buffers, stream._buffersLength);
    } else if (stream._currentState !== BUFFERING_STATE) {
      chunk = null;
    }

    stream._currentState = INIT_STATE;
    stream._callback = null;
    stream._buffers.splice(0);
    stream._buffersLength = 0;

    cb.call(stream, chunk);
  }

  return done;
};

/**
 * Function to which sends all data from `_transform` function
 * @param {StreamReader} stream StreamReader instance
 * @param {Buffer} chunk Chunk of data
 * @param {Function} done Function that triggers when processing is done
 * @type {Function}
 * @private
 */
const _onData = _trampoline((stream, chunk, done) => {
  if (chunk.length <= stream._bytesLeft) {
    return () => _processData(stream, chunk, done);
  } else {
    return () => {
      const buffer = chunk.slice(0, stream._bytesLeft);

      return _processData(stream, buffer, error => {
        if (error) return done(error);
        if (chunk.length > buffer.length) {
          return () => _onData(stream, chunk.slice(buffer.length), done);
        }
      });
    };
  }
});

export default class StreamReader extends Transform {
  /**
   * Creates new transform stream which emits `metadata` event when it will be read
   * @param {Number} icyMetaInt Number of bytes from response headers which shows how many bytes need to skip
   * @constructor
   */
  constructor(icyMetaInt) {
    super();

    // How many bytes left to read
    this._bytesLeft = 0;

    // Current state of reader, what the reader should do with received bytes
    this._currentState = INIT_STATE;

    // Callback for the next chunk
    this._callback = null;

    // Array of collected Buffers
    this._buffers = [];

    // How many bytes already read
    this._buffersLength = 0;

    // icy-metaint number from radio response
    this._icyMetaInt = +icyMetaInt;

    this._passthrough(this._icyMetaInt, this._onMetaSectionStart);
  }

  /**
   * Collect bytes in buffer and trigger callback with collected chunk
   * @param {Number} length Length of bytes that need to read
   * @param {Function} cb Callback function with collected data in arguments
   * @returns {StreamReader}
   * @private
   */
  _bytes(length, cb) {
    this._bytesLeft = length;
    this._currentState = BUFFERING_STATE;
    this._callback = cb;
    return this;
  }

  /**
   * Pass through Transform stream and trigger callback after all data is sent
   * @param {Number} length Length of bytes to pass through
   * @param {Function} cb Callback function when all data will be sent
   * @returns {StreamReader}
   * @private
   */
  _passthrough(length, cb) {
    this._bytesLeft = length;
    this._currentState = PASSTHROUGH_STATE;
    this._callback = cb;
    return this;
  }

  /**
   * Transform stream processor
   * @param {Buffer} chunk Chunk of data
   * @param {String} encoding Current encoding of chunk
   * @param {Function} done Callback function when processing is done
   * @returns {Function}
   * @private
   */
  _transform(chunk, encoding, done) {
    _onData(this, chunk, done);
  }

  /**
   * Triggers when metadata section is starting
   * @private
   */
  _onMetaSectionStart() {
    this._bytes(1, this._onMetaSectionLengthByte);
  }

  /**
   * Triggers when we read 1 byte with metadata section length
   * @param chunk Chunk where located length byte
   * @private
   */
  _onMetaSectionLengthByte(chunk) {
    const length = chunk[0] * METADATA_BLOCK_SIZE;

    if (length > 0) {
      this._bytes(length, this._onMetaData);
    } else {
      this._passthrough(this._icyMetaInt, this._onMetaSectionStart);
    }
  }

  /**
   * Triggers when metadata is collected
   * @param chunk Metadata buffer
   * @private
   */
  _onMetaData(chunk) {
    this.emit('metadata', _parseMetadata(chunk));
    this._passthrough(this._icyMetaInt, this._onMetaSectionStart);
  }
}
<commit_msg>fix(package): Fix issue with trampoline function on arrow functions<commit_after>import util from 'util';
import { Transform } from 'stream';

/**
 * "Init" state
 * @description :: State which indicates that StreamReader is initializing
 * @type {Number}
 * @private
 */
const INIT_STATE = 1;

/**
 * "Buffering" state
 * @description :: State which indicates that StreamReader is grabbing data to buffer
 * @type {Number}
 * @private
 */
const BUFFERING_STATE = 2;

/**
 * "Pass through" state
 * @description :: State which indicates that StreamReader is just sends data without caching
 * @type {Number}
 * @private
 */
const PASSTHROUGH_STATE = 3;

/**
 * Block size of metadata
 * @description :: How many bytes need to multiply to number from response.headers['icy-metaint']
 * @type {Number}
 * @private
 */
const METADATA_BLOCK_SIZE = 16;

/**
 * Parse metadata to object
 * @param {Buffer|String} metadata Buffer or string with metadata information
 * @returns {Object}
 * @private
 */
const _parseMetadata = metadata => {
  const data = Buffer.isBuffer(metadata) ? metadata.toString('utf8') : metadata || '';
  const result = {};

  data.replace(/\0*$/, '').split(';').forEach(item => {
    item = item.split(/\=['"]/);
    result[item[0]] = String(item[1]).replace(/['"]$/, '');
  });

  return result;
};

/**
 * Helper method that returns trampolined function
 * @param {Function} fn Function that need to trampoline
 * @returns {Function} Returns trampolined function
 * @private
 */
const _trampoline = function (fn) {
  return function () {
    let result = fn.apply(this, arguments);
    while (typeof result === 'function') result = result();
    return result;
  };
};

/**
 * Process one chunk of data
 * @param {StreamReader} stream StreamReader instance
 * @param {Buffer} chunk Chunk of data
 * @param {Function} done Triggers when processing is done
 * @returns {Function}
 * @private
 */
const _processData = (stream, chunk, done) => {
  stream._bytesLeft -= chunk.length;

  if (stream._currentState === BUFFERING_STATE) {
    stream._buffers.push(chunk);
    stream._buffersLength += chunk.length;
  } else if (stream._currentState === PASSTHROUGH_STATE) {
    stream.push(chunk);
  }

  if (stream._bytesLeft === 0) {
    const cb = stream._callback;

    if (cb && stream._currentState === BUFFERING_STATE && stream._buffers.length > 1) {
      chunk = Buffer.concat(stream._buffers, stream._buffersLength);
    } else if (stream._currentState !== BUFFERING_STATE) {
      chunk = null;
    }

    stream._currentState = INIT_STATE;
    stream._callback = null;
    stream._buffers.splice(0);
    stream._buffersLength = 0;

    cb.call(stream, chunk);
  }

  return done;
};

/**
 * Function to which sends all data from `_transform` function
 * @param {StreamReader} stream StreamReader instance
 * @param {Buffer} chunk Chunk of data
 * @param {Function} done Function that triggers when processing is done
 * @type {Function}
 * @private
 */
const _onData = _trampoline((stream, chunk, done) => {
  if (chunk.length <= stream._bytesLeft) {
    return () => _processData(stream, chunk, done);
  } else {
    return () => {
      const buffer = chunk.slice(0, stream._bytesLeft);

      return _processData(stream, buffer, error => {
        if (error) return done(error);
        if (chunk.length > buffer.length) {
          return () => _onData(stream, chunk.slice(buffer.length), done);
        }
      });
    };
  }
});

export default class StreamReader extends Transform {
  /**
   * Creates new transform stream which emits `metadata` event when it will be read
   * @param {Number} icyMetaInt Number of bytes from response headers which shows how many bytes need to skip
   * @constructor
   */
  constructor(icyMetaInt) {
    super();

    // How many bytes left to read
    this._bytesLeft = 0;

    // Current state of reader, what the reader should do with received bytes
    this._currentState = INIT_STATE;

    // Callback for the next chunk
    this._callback = null;

    // Array of collected Buffers
    this._buffers = [];

    // How many bytes already read
    this._buffersLength = 0;

    // icy-metaint number from radio response
    this._icyMetaInt = +icyMetaInt;

    this._passthrough(this._icyMetaInt, this._onMetaSectionStart);
  }

  /**
   * Collect bytes in buffer and trigger callback with collected chunk
   * @param {Number} length Length of bytes that need to read
   * @param {Function} cb Callback function with collected data in arguments
   * @returns {StreamReader}
   * @private
   */
  _bytes(length, cb) {
    this._bytesLeft = length;
    this._currentState = BUFFERING_STATE;
    this._callback = cb;
    return this;
  }

  /**
   * Pass through Transform stream and trigger callback after all data is sent
   * @param {Number} length Length of bytes to pass through
   * @param {Function} cb Callback function when all data will be sent
   * @returns {StreamReader}
   * @private
   */
  _passthrough(length, cb) {
    this._bytesLeft = length;
    this._currentState = PASSTHROUGH_STATE;
    this._callback = cb;
    return this;
  }

  /**
   * Transform stream processor
   * @param {Buffer} chunk Chunk of data
   * @param {String} encoding Current encoding of chunk
   * @param {Function} done Callback function when processing is done
   * @returns {Function}
   * @private
   */
  _transform(chunk, encoding, done) {
    _onData(this, chunk, done);
  }

  /**
   * Triggers when metadata section is starting
   * @private
   */
  _onMetaSectionStart() {
    this._bytes(1, this._onMetaSectionLengthByte);
  }

  /**
   * Triggers when we read 1 byte with metadata section length
   * @param chunk Chunk where located length byte
   * @private
   */
  _onMetaSectionLengthByte(chunk) {
    const length = chunk[0] * METADATA_BLOCK_SIZE;

    if (length > 0) {
      this._bytes(length, this._onMetaData);
    } else {
      this._passthrough(this._icyMetaInt, this._onMetaSectionStart);
    }
  }

  /**
   * Triggers when metadata is collected
   * @param chunk Metadata buffer
   * @private
   */
  _onMetaData(chunk) {
    this.emit('metadata', _parseMetadata(chunk));
    this._passthrough(this._icyMetaInt, this._onMetaSectionStart);
  }
}
<|endoftext|>


<commit_before>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import MatrixClientPeg from './MatrixClientPeg';
import CallHandler from './CallHandler';
import { _t } from './languageHandler';
import * as Roles from './Roles';

function textForMemberEvent(ev) {
    // XXX: SYJS-16 "sender is sometimes null for join messages"
    const senderName = ev.sender ? ev.sender.name : ev.getSender();
    const targetName = ev.target ? ev.target.name : ev.getStateKey();
    const prevContent = ev.getPrevContent();
    const content = ev.getContent();

    const ConferenceHandler = CallHandler.getConferenceHandler();
    const reason = content.reason ? (_t('Reason') + ': ' + content.reason) : '';
    switch (content.membership) {
        case 'invite': {
            const threePidContent = content.third_party_invite;
            if (threePidContent) {
                if (threePidContent.display_name) {
                    return _t('%(targetName)s accepted the invitation for %(displayName)s.', {
                        targetName,
                        displayName: threePidContent.display_name,
                    });
                } else {
                    return _t('%(targetName)s accepted an invitation.', {targetName});
                }
            } else {
                if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
                    return _t('%(senderName)s requested a VoIP conference.', {senderName});
                } else {
                    return _t('%(senderName)s invited %(targetName)s.', {senderName, targetName});
                }
            }
        }
        case 'ban':
            return _t('%(senderName)s banned %(targetName)s.', {senderName, targetName}) + ' ' + reason;
        case 'join':
            if (prevContent && prevContent.membership === 'join') {
                if (prevContent.displayname && content.displayname && prevContent.displayname !== content.displayname) {
                    return _t('%(oldDisplayName)s changed their display name to %(displayName)s.', {
                        oldDisplayName: prevContent.displayname,
                        displayName: content.displayname,
                    });
                } else if (!prevContent.displayname && content.displayname) {
                    return _t('%(senderName)s set their display name to %(displayName)s.', {
                        senderName: ev.getSender(),
                        displayName: content.displayname,
                    });
                } else if (prevContent.displayname && !content.displayname) {
                    return _t('%(senderName)s removed their display name (%(oldDisplayName)s).', {
                        senderName,
                        oldDisplayName: prevContent.displayname,
                    });
                } else if (prevContent.avatar_url && !content.avatar_url) {
                    return _t('%(senderName)s removed their profile picture.', {senderName});
                } else if (prevContent.avatar_url && content.avatar_url &&
                    prevContent.avatar_url !== content.avatar_url) {
                    return _t('%(senderName)s changed their profile picture.', {senderName});
                } else if (!prevContent.avatar_url && content.avatar_url) {
                    return _t('%(senderName)s set a profile picture.', {senderName});
                } else {
                    // suppress null rejoins
                    return '';
                }
            } else {
                if (!ev.target) console.warn("Join message has no target! -- " + ev.getContent().state_key);
                if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
                    return _t('VoIP conference started.');
                } else {
                    return _t('%(targetName)s joined the room.', {targetName});
                }
            }
        case 'leave':
            if (ev.getSender() === ev.getStateKey()) {
                if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
                    return _t('VoIP conference finished.');
                } else if (prevContent.membership === "invite") {
                    return _t('%(targetName)s rejected the invitation.', {targetName});
                } else {
                    return _t('%(targetName)s left the room.', {targetName});
                }
            } else if (prevContent.membership === "ban") {
                return _t('%(senderName)s unbanned %(targetName)s.', {senderName, targetName});
            } else if (prevContent.membership === "join") {
                return _t('%(senderName)s kicked %(targetName)s.', {senderName, targetName}) + ' ' + reason;
            } else if (prevContent.membership === "invite") {
                return _t('%(senderName)s withdrew %(targetName)s\'s invitation.', {
                    senderName,
                    targetName,
                }) + ' ' + reason;
            } else {
                return _t('%(targetName)s left the room.', {targetName});
            }
    }
}

function textForTopicEvent(ev) {
    const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
    return _t('%(senderDisplayName)s changed the topic to "%(topic)s".', {
        senderDisplayName,
        topic: ev.getContent().topic,
    });
}

function textForRoomNameEvent(ev) {
    const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();

    if (!ev.getContent().name || ev.getContent().name.trim().length === 0) {
        return _t('%(senderDisplayName)s removed the room name.', {senderDisplayName});
    }
    return _t('%(senderDisplayName)s changed the room name to %(roomName)s.', {
        senderDisplayName,
        roomName: ev.getContent().name,
    });
}

function textForServerACLEvent(ev) {
    const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
    const prev_content = ev.getPrevContent();
    const changes = [];
    let text = "";
    let current = ev.getContent();
    let prev = {
        deny: Array.isArray(prev_content.deny) ? prev_content.deny : [],
        allow: Array.isArray(prev_content.allow) ? prev_content.allow : [],
        allow_ip_literals: !(prev_content.allow_ip_literals === false)
    }
    if (prev.deny.length === 0 && prev.allow.length === 0) {
        text = `${senderDisplayName} set server ACLs for this room: `;
    } else {
        text = `${senderDisplayName} changed the server ACLs for this room: `;
    }

    /* If we know for sure everyone is banned, don't bother showing the diff view */
    if (current.allow.length  === 0) {
        return text + "🎉 All servers are banned from participating! This room can no longer be used.";
    }

    if (!Array.isArray(current.allow)){
        current.allow = []
    }

    if (!Array.isArray(current.deny)){
        current.deny = []
    }

    const bannedServers = current.deny.filter((srv) => typeof(srv) === 'string' && !prev.deny.includes(srv));
    const unbannedServers = prev.deny.filter((srv) => typeof(srv) === 'string' && !current.deny.includes(srv));
    const allowedServers = current.allow.filter((srv) => typeof(srv) === 'string' && !prev.allow.includes(srv));
    const unallowedServers = prev.allow.filter((srv) => typeof(srv) === 'string' && !current.allow.includes(srv));

    console.log(bannedServers,unbannedServers,allowedServers,unallowedServers);

    if (bannedServers.length > 0) {
        changes.push(`Servers matching ${bannedServers.join(",")} are now banned.`);
    }

    if (unbannedServers.length > 0) {
        changes.push(`Servers matching ${unbannedServers.join(",")} were removed from the ban list.`);
    }

    if (allowedServers.length > 0) {
        changes.push(`Servers matching ${allowedServers.join(",")} are now allowed.`);
    }

    if (unallowedServers.length > 0) {
        changes.push(`Servers matching ${unallowedServers.join(",")} were removed from the allowed list.`);
    }

    if (prev.allow_ip_literals !== current.allow_ip_literals) {
        const allowban = current.allow_ip_literals ? "allowed" : "banned";
        changes.push(`Participating from a server using an IP literal hostname is now ${allowban}.`);
    }

    return text + changes.join(" ");
}

function textForMessageEvent(ev) {
    const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
    let message = senderDisplayName + ': ' + ev.getContent().body;
    if (ev.getContent().msgtype === "m.emote") {
        message = "* " + senderDisplayName + " " + message;
    } else if (ev.getContent().msgtype === "m.image") {
        message = _t('%(senderDisplayName)s sent an image.', {senderDisplayName});
    }
    return message;
}

function textForCallAnswerEvent(event) {
    const senderName = event.sender ? event.sender.name : _t('Someone');
    const supported = MatrixClientPeg.get().supportsVoip() ? '' : _t('(not supported by this browser)');
    return _t('%(senderName)s answered the call.', {senderName}) + ' ' + supported;
}

function textForCallHangupEvent(event) {
    const senderName = event.sender ? event.sender.name : _t('Someone');
    const eventContent = event.getContent();
    let reason = "";
    if (!MatrixClientPeg.get().supportsVoip()) {
        reason = _t('(not supported by this browser)');
    } else if (eventContent.reason) {
        if (eventContent.reason === "ice_failed") {
            reason = _t('(could not connect media)');
        } else if (eventContent.reason === "invite_timeout") {
            reason = _t('(no answer)');
        } else {
            reason = _t('(unknown failure: %(reason)s)', {reason: eventContent.reason});
        }
    }
    return _t('%(senderName)s ended the call.', {senderName}) + ' ' + reason;
}

function textForCallInviteEvent(event) {
    const senderName = event.sender ? event.sender.name : _t('Someone');
    // FIXME: Find a better way to determine this from the event?
    let callType = "voice";
    if (event.getContent().offer && event.getContent().offer.sdp &&
            event.getContent().offer.sdp.indexOf('m=video') !== -1) {
        callType = "video";
    }
    const supported = MatrixClientPeg.get().supportsVoip() ? "" : _t('(not supported by this browser)');
    return _t('%(senderName)s placed a %(callType)s call.', {senderName, callType}) + ' ' + supported;
}

function textForThreePidInviteEvent(event) {
    const senderName = event.sender ? event.sender.name : event.getSender();
    return _t('%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.', {
        senderName,
        targetDisplayName: event.getContent().display_name,
    });
}

function textForHistoryVisibilityEvent(event) {
    const senderName = event.sender ? event.sender.name : event.getSender();
    switch (event.getContent().history_visibility) {
        case 'invited':
            return _t('%(senderName)s made future room history visible to all room members, '
                + 'from the point they are invited.', {senderName});
        case 'joined':
            return _t('%(senderName)s made future room history visible to all room members, '
                + 'from the point they joined.', {senderName});
        case 'shared':
            return _t('%(senderName)s made future room history visible to all room members.', {senderName});
        case 'world_readable':
            return _t('%(senderName)s made future room history visible to anyone.', {senderName});
        default:
            return _t('%(senderName)s made future room history visible to unknown (%(visibility)s).', {
                senderName,
                visibility: event.getContent().history_visibility,
            });
    }
}

function textForEncryptionEvent(event) {
    const senderName = event.sender ? event.sender.name : event.getSender();
    return _t('%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).', {
        senderName,
        algorithm: event.getContent().algorithm,
    });
}

// Currently will only display a change if a user's power level is changed
function textForPowerEvent(event) {
    const senderName = event.sender ? event.sender.name : event.getSender();
    if (!event.getPrevContent() || !event.getPrevContent().users) {
        return '';
    }
    const userDefault = event.getContent().users_default || 0;
    // Construct set of userIds
    const users = [];
    Object.keys(event.getContent().users).forEach(
        (userId) => {
            if (users.indexOf(userId) === -1) users.push(userId);
        },
    );
    Object.keys(event.getPrevContent().users).forEach(
        (userId) => {
            if (users.indexOf(userId) === -1) users.push(userId);
        },
    );
    const diff = [];
    // XXX: This is also surely broken for i18n
    users.forEach((userId) => {
        // Previous power level
        const from = event.getPrevContent().users[userId];
        // Current power level
        const to = event.getContent().users[userId];
        if (to !== from) {
            diff.push(
                _t('%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s', {
                    userId,
                    fromPowerLevel: Roles.textualPowerLevel(from, userDefault),
                    toPowerLevel: Roles.textualPowerLevel(to, userDefault),
                }),
            );
        }
    });
    if (!diff.length) {
        return '';
    }
    return _t('%(senderName)s changed the power level of %(powerLevelDiffText)s.', {
        senderName,
        powerLevelDiffText: diff.join(", "),
    });
}

function textForPinnedEvent(event) {
    const senderName = event.getSender();
    return _t("%(senderName)s changed the pinned messages for the room.", {senderName});
}

function textForWidgetEvent(event) {
    const senderName = event.getSender();
    const {name: prevName, type: prevType, url: prevUrl} = event.getPrevContent();
    const {name, type, url} = event.getContent() || {};

    let widgetName = name || prevName || type || prevType || '';
    // Apply sentence case to widget name
    if (widgetName && widgetName.length > 0) {
        widgetName = widgetName[0].toUpperCase() + widgetName.slice(1) + ' ';
    }

    // If the widget was removed, its content should be {}, but this is sufficiently
    // equivalent to that condition.
    if (url) {
        if (prevUrl) {
            return _t('%(widgetName)s widget modified by %(senderName)s', {
                widgetName, senderName,
            });
        } else {
            return _t('%(widgetName)s widget added by %(senderName)s', {
                widgetName, senderName,
            });
        }
    } else {
        return _t('%(widgetName)s widget removed by %(senderName)s', {
            widgetName, senderName,
        });
    }
}

const handlers = {
    'm.room.message': textForMessageEvent,
    'm.call.invite': textForCallInviteEvent,
    'm.call.answer': textForCallAnswerEvent,
    'm.call.hangup': textForCallHangupEvent,
};

const stateHandlers = {
    'm.room.name': textForRoomNameEvent,
    'm.room.topic': textForTopicEvent,
    'm.room.member': textForMemberEvent,
    'm.room.third_party_invite': textForThreePidInviteEvent,
    'm.room.history_visibility': textForHistoryVisibilityEvent,
    'm.room.encryption': textForEncryptionEvent,
    'm.room.power_levels': textForPowerEvent,
    'm.room.pinned_events': textForPinnedEvent,
    'm.room.server_acl': textForServerACLEvent,

    'im.vector.modular.widgets': textForWidgetEvent,
};

module.exports = {
    textForEvent: function(ev) {
        const handler = (ev.isState() ? stateHandlers : handlers)[ev.getType()];
        if (handler) return handler(ev);
        return '';
    },
};
<commit_msg>Remove unused console.log<commit_after>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import MatrixClientPeg from './MatrixClientPeg';
import CallHandler from './CallHandler';
import { _t } from './languageHandler';
import * as Roles from './Roles';

function textForMemberEvent(ev) {
    // XXX: SYJS-16 "sender is sometimes null for join messages"
    const senderName = ev.sender ? ev.sender.name : ev.getSender();
    const targetName = ev.target ? ev.target.name : ev.getStateKey();
    const prevContent = ev.getPrevContent();
    const content = ev.getContent();

    const ConferenceHandler = CallHandler.getConferenceHandler();
    const reason = content.reason ? (_t('Reason') + ': ' + content.reason) : '';
    switch (content.membership) {
        case 'invite': {
            const threePidContent = content.third_party_invite;
            if (threePidContent) {
                if (threePidContent.display_name) {
                    return _t('%(targetName)s accepted the invitation for %(displayName)s.', {
                        targetName,
                        displayName: threePidContent.display_name,
                    });
                } else {
                    return _t('%(targetName)s accepted an invitation.', {targetName});
                }
            } else {
                if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
                    return _t('%(senderName)s requested a VoIP conference.', {senderName});
                } else {
                    return _t('%(senderName)s invited %(targetName)s.', {senderName, targetName});
                }
            }
        }
        case 'ban':
            return _t('%(senderName)s banned %(targetName)s.', {senderName, targetName}) + ' ' + reason;
        case 'join':
            if (prevContent && prevContent.membership === 'join') {
                if (prevContent.displayname && content.displayname && prevContent.displayname !== content.displayname) {
                    return _t('%(oldDisplayName)s changed their display name to %(displayName)s.', {
                        oldDisplayName: prevContent.displayname,
                        displayName: content.displayname,
                    });
                } else if (!prevContent.displayname && content.displayname) {
                    return _t('%(senderName)s set their display name to %(displayName)s.', {
                        senderName: ev.getSender(),
                        displayName: content.displayname,
                    });
                } else if (prevContent.displayname && !content.displayname) {
                    return _t('%(senderName)s removed their display name (%(oldDisplayName)s).', {
                        senderName,
                        oldDisplayName: prevContent.displayname,
                    });
                } else if (prevContent.avatar_url && !content.avatar_url) {
                    return _t('%(senderName)s removed their profile picture.', {senderName});
                } else if (prevContent.avatar_url && content.avatar_url &&
                    prevContent.avatar_url !== content.avatar_url) {
                    return _t('%(senderName)s changed their profile picture.', {senderName});
                } else if (!prevContent.avatar_url && content.avatar_url) {
                    return _t('%(senderName)s set a profile picture.', {senderName});
                } else {
                    // suppress null rejoins
                    return '';
                }
            } else {
                if (!ev.target) console.warn("Join message has no target! -- " + ev.getContent().state_key);
                if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
                    return _t('VoIP conference started.');
                } else {
                    return _t('%(targetName)s joined the room.', {targetName});
                }
            }
        case 'leave':
            if (ev.getSender() === ev.getStateKey()) {
                if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
                    return _t('VoIP conference finished.');
                } else if (prevContent.membership === "invite") {
                    return _t('%(targetName)s rejected the invitation.', {targetName});
                } else {
                    return _t('%(targetName)s left the room.', {targetName});
                }
            } else if (prevContent.membership === "ban") {
                return _t('%(senderName)s unbanned %(targetName)s.', {senderName, targetName});
            } else if (prevContent.membership === "join") {
                return _t('%(senderName)s kicked %(targetName)s.', {senderName, targetName}) + ' ' + reason;
            } else if (prevContent.membership === "invite") {
                return _t('%(senderName)s withdrew %(targetName)s\'s invitation.', {
                    senderName,
                    targetName,
                }) + ' ' + reason;
            } else {
                return _t('%(targetName)s left the room.', {targetName});
            }
    }
}

function textForTopicEvent(ev) {
    const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
    return _t('%(senderDisplayName)s changed the topic to "%(topic)s".', {
        senderDisplayName,
        topic: ev.getContent().topic,
    });
}

function textForRoomNameEvent(ev) {
    const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();

    if (!ev.getContent().name || ev.getContent().name.trim().length === 0) {
        return _t('%(senderDisplayName)s removed the room name.', {senderDisplayName});
    }
    return _t('%(senderDisplayName)s changed the room name to %(roomName)s.', {
        senderDisplayName,
        roomName: ev.getContent().name,
    });
}

function textForServerACLEvent(ev) {
    const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
    const prev_content = ev.getPrevContent();
    const changes = [];
    let text = "";
    let current = ev.getContent();
    let prev = {
        deny: Array.isArray(prev_content.deny) ? prev_content.deny : [],
        allow: Array.isArray(prev_content.allow) ? prev_content.allow : [],
        allow_ip_literals: !(prev_content.allow_ip_literals === false)
    }
    if (prev.deny.length === 0 && prev.allow.length === 0) {
        text = `${senderDisplayName} set server ACLs for this room: `;
    } else {
        text = `${senderDisplayName} changed the server ACLs for this room: `;
    }

    /* If we know for sure everyone is banned, don't bother showing the diff view */
    if (current.allow.length  === 0) {
        return text + "🎉 All servers are banned from participating! This room can no longer be used.";
    }

    if (!Array.isArray(current.allow)){
        current.allow = []
    }

    if (!Array.isArray(current.deny)){
        current.deny = []
    }

    const bannedServers = current.deny.filter((srv) => typeof(srv) === 'string' && !prev.deny.includes(srv));
    const unbannedServers = prev.deny.filter((srv) => typeof(srv) === 'string' && !current.deny.includes(srv));
    const allowedServers = current.allow.filter((srv) => typeof(srv) === 'string' && !prev.allow.includes(srv));
    const unallowedServers = prev.allow.filter((srv) => typeof(srv) === 'string' && !current.allow.includes(srv));

    if (bannedServers.length > 0) {
        changes.push(`Servers matching ${bannedServers.join(",")} are now banned.`);
    }

    if (unbannedServers.length > 0) {
        changes.push(`Servers matching ${unbannedServers.join(",")} were removed from the ban list.`);
    }

    if (allowedServers.length > 0) {
        changes.push(`Servers matching ${allowedServers.join(",")} are now allowed.`);
    }

    if (unallowedServers.length > 0) {
        changes.push(`Servers matching ${unallowedServers.join(",")} were removed from the allowed list.`);
    }

    if (prev.allow_ip_literals !== current.allow_ip_literals) {
        const allowban = current.allow_ip_literals ? "allowed" : "banned";
        changes.push(`Participating from a server using an IP literal hostname is now ${allowban}.`);
    }

    return text + changes.join(" ");
}

function textForMessageEvent(ev) {
    const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
    let message = senderDisplayName + ': ' + ev.getContent().body;
    if (ev.getContent().msgtype === "m.emote") {
        message = "* " + senderDisplayName + " " + message;
    } else if (ev.getContent().msgtype === "m.image") {
        message = _t('%(senderDisplayName)s sent an image.', {senderDisplayName});
    }
    return message;
}

function textForCallAnswerEvent(event) {
    const senderName = event.sender ? event.sender.name : _t('Someone');
    const supported = MatrixClientPeg.get().supportsVoip() ? '' : _t('(not supported by this browser)');
    return _t('%(senderName)s answered the call.', {senderName}) + ' ' + supported;
}

function textForCallHangupEvent(event) {
    const senderName = event.sender ? event.sender.name : _t('Someone');
    const eventContent = event.getContent();
    let reason = "";
    if (!MatrixClientPeg.get().supportsVoip()) {
        reason = _t('(not supported by this browser)');
    } else if (eventContent.reason) {
        if (eventContent.reason === "ice_failed") {
            reason = _t('(could not connect media)');
        } else if (eventContent.reason === "invite_timeout") {
            reason = _t('(no answer)');
        } else {
            reason = _t('(unknown failure: %(reason)s)', {reason: eventContent.reason});
        }
    }
    return _t('%(senderName)s ended the call.', {senderName}) + ' ' + reason;
}

function textForCallInviteEvent(event) {
    const senderName = event.sender ? event.sender.name : _t('Someone');
    // FIXME: Find a better way to determine this from the event?
    let callType = "voice";
    if (event.getContent().offer && event.getContent().offer.sdp &&
            event.getContent().offer.sdp.indexOf('m=video') !== -1) {
        callType = "video";
    }
    const supported = MatrixClientPeg.get().supportsVoip() ? "" : _t('(not supported by this browser)');
    return _t('%(senderName)s placed a %(callType)s call.', {senderName, callType}) + ' ' + supported;
}

function textForThreePidInviteEvent(event) {
    const senderName = event.sender ? event.sender.name : event.getSender();
    return _t('%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.', {
        senderName,
        targetDisplayName: event.getContent().display_name,
    });
}

function textForHistoryVisibilityEvent(event) {
    const senderName = event.sender ? event.sender.name : event.getSender();
    switch (event.getContent().history_visibility) {
        case 'invited':
            return _t('%(senderName)s made future room history visible to all room members, '
                + 'from the point they are invited.', {senderName});
        case 'joined':
            return _t('%(senderName)s made future room history visible to all room members, '
                + 'from the point they joined.', {senderName});
        case 'shared':
            return _t('%(senderName)s made future room history visible to all room members.', {senderName});
        case 'world_readable':
            return _t('%(senderName)s made future room history visible to anyone.', {senderName});
        default:
            return _t('%(senderName)s made future room history visible to unknown (%(visibility)s).', {
                senderName,
                visibility: event.getContent().history_visibility,
            });
    }
}

function textForEncryptionEvent(event) {
    const senderName = event.sender ? event.sender.name : event.getSender();
    return _t('%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).', {
        senderName,
        algorithm: event.getContent().algorithm,
    });
}

// Currently will only display a change if a user's power level is changed
function textForPowerEvent(event) {
    const senderName = event.sender ? event.sender.name : event.getSender();
    if (!event.getPrevContent() || !event.getPrevContent().users) {
        return '';
    }
    const userDefault = event.getContent().users_default || 0;
    // Construct set of userIds
    const users = [];
    Object.keys(event.getContent().users).forEach(
        (userId) => {
            if (users.indexOf(userId) === -1) users.push(userId);
        },
    );
    Object.keys(event.getPrevContent().users).forEach(
        (userId) => {
            if (users.indexOf(userId) === -1) users.push(userId);
        },
    );
    const diff = [];
    // XXX: This is also surely broken for i18n
    users.forEach((userId) => {
        // Previous power level
        const from = event.getPrevContent().users[userId];
        // Current power level
        const to = event.getContent().users[userId];
        if (to !== from) {
            diff.push(
                _t('%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s', {
                    userId,
                    fromPowerLevel: Roles.textualPowerLevel(from, userDefault),
                    toPowerLevel: Roles.textualPowerLevel(to, userDefault),
                }),
            );
        }
    });
    if (!diff.length) {
        return '';
    }
    return _t('%(senderName)s changed the power level of %(powerLevelDiffText)s.', {
        senderName,
        powerLevelDiffText: diff.join(", "),
    });
}

function textForPinnedEvent(event) {
    const senderName = event.getSender();
    return _t("%(senderName)s changed the pinned messages for the room.", {senderName});
}

function textForWidgetEvent(event) {
    const senderName = event.getSender();
    const {name: prevName, type: prevType, url: prevUrl} = event.getPrevContent();
    const {name, type, url} = event.getContent() || {};

    let widgetName = name || prevName || type || prevType || '';
    // Apply sentence case to widget name
    if (widgetName && widgetName.length > 0) {
        widgetName = widgetName[0].toUpperCase() + widgetName.slice(1) + ' ';
    }

    // If the widget was removed, its content should be {}, but this is sufficiently
    // equivalent to that condition.
    if (url) {
        if (prevUrl) {
            return _t('%(widgetName)s widget modified by %(senderName)s', {
                widgetName, senderName,
            });
        } else {
            return _t('%(widgetName)s widget added by %(senderName)s', {
                widgetName, senderName,
            });
        }
    } else {
        return _t('%(widgetName)s widget removed by %(senderName)s', {
            widgetName, senderName,
        });
    }
}

const handlers = {
    'm.room.message': textForMessageEvent,
    'm.call.invite': textForCallInviteEvent,
    'm.call.answer': textForCallAnswerEvent,
    'm.call.hangup': textForCallHangupEvent,
};

const stateHandlers = {
    'm.room.name': textForRoomNameEvent,
    'm.room.topic': textForTopicEvent,
    'm.room.member': textForMemberEvent,
    'm.room.third_party_invite': textForThreePidInviteEvent,
    'm.room.history_visibility': textForHistoryVisibilityEvent,
    'm.room.encryption': textForEncryptionEvent,
    'm.room.power_levels': textForPowerEvent,
    'm.room.pinned_events': textForPinnedEvent,
    'm.room.server_acl': textForServerACLEvent,

    'im.vector.modular.widgets': textForWidgetEvent,
};

module.exports = {
    textForEvent: function(ev) {
        const handler = (ev.isState() ? stateHandlers : handlers)[ev.getType()];
        if (handler) return handler(ev);
        return '';
    },
};
<|endoftext|>


<commit_before>$.getJSON("http://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1&callback=",
	function(a) {
		//Store data in Variables
		var ID = a[0].id;
		var Title = a[0].title;
		var Content = a[0].content;
		var Link = a[0].link;

		//Processing text only version
		var ID2 = ($(ID).text());
		var Title2 = ($(Title).text());
		var Content2 = ($(Content).text());

		$("#qod-quote-text").append(Content2 + " ―" + Title2);
	}
);<commit_msg>quote.js revert title<commit_after>$.getJSON("http://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1&callback=",
	function(a) {
		//Store data in Variables
		var ID = a[0].id;
		var Title = a[0].title;
		var Content = a[0].content;
		var Link = a[0].link;

		//Processing text only version
		var ID2 = ($(ID).text());
		var Title2 = ($(Title).text());
		var Content2 = ($(Content).text());

		$("#qod-quote-text").append(Content2 + " ―" + Title);
	}
);<|endoftext|>


<commit_before>// a component view for the composite design pattern
// used in the view layer of MVC applications
//
var LIB_View = function(model, controller, /*optional*/ doc) {
    this.setModel(model);
    this.setController(controller);
    this._doc = doc || document;
    this.renderAndUpdate();
};

LIB_mixinComponent(LIB_View.prototype);

LIB_View.prototype.renderAndUpdate = function() {
    this.render();
    this.update();
};

LIB_View.prototype.createRootEl = function() {
    return this._doc.createElement('div');
};

LIB_View.prototype.getRootEl = function() {
    if (!this._rootEl) {
        this._rootEl = this.createRootEl();
    }
    return this._rootEl();
};

// build the HTML shell of the view that does not depend
// on the model state
LIB_View.prototype.render = function() {
    // to be overridden in concrete view subclasses
};

// update the HTML of the view to represent model state
LIB_View.prototype.update = function() {
    // to be overridden by concrete view subclasses
};

LIB_View.prototype.destroy = function() {
    LIB_Component.prototype.destroy.call(this);
    this.setModel(null);
    this.setController(null);
    evento.purgeEventListener(this);
    delete this._doc;
    delete this._rootEl;
};

LIB_View.prototype.getModel = function() {
    return this._model;
};

LIB_View.prototype.setModel = function(model) {
    if (this._model) {
        evento.removeEventListener(this._model, 'change', this, 'update');
        delete this._model;
    }
    if (model) {
        evento.addEventListener(model, 'change', this, 'update');
        this._model = model;
        this.update();
    }
};

LIB_View.prototype.getController = function() {
    return this._controller;
};

LIB_View.prototype.setController = function(controller) {
    if (this._controller) {
        delete this._controller;
    }
    if (controller) {
        this._controller = controller;
    }
};
<commit_msg>don't really like this style of creating DOM root object. This will be changing later.<commit_after>// a component view for the composite design pattern
// used in the view layer of MVC applications
//
var LIB_View = function(model, controller, /*optional*/ doc) {
    this.setModel(model);
    this.setController(controller);
    this._doc = doc || document;
    this.renderAndUpdate();
};

LIB_mixinComponent(LIB_View.prototype);

LIB_View.prototype.renderAndUpdate = function() {
    this.render();
    this.update();
};

LIB_View.prototype.tagName = 'div';
LIB_View.prototype.className = '';

LIB_View.prototype.createRootEl = function() {
    var rootEl = this._doc.createElement(this.tagName);
    rootEl.className = this.className;
    return rootEl;
};

LIB_View.prototype.getRootEl = function() {
    if (!this._rootEl) {
        this._rootEl = this.createRootEl();
    }
    return this._rootEl();
};

// build the HTML shell of the view that does not depend
// on the model state
LIB_View.prototype.render = function() {
    // to be overridden in concrete view subclasses
};

// update the HTML of the view to represent model state
LIB_View.prototype.update = function() {
    // to be overridden by concrete view subclasses
};

LIB_View.prototype.destroy = function() {
    LIB_Component.prototype.destroy.call(this);
    this.setModel(null);
    this.setController(null);
    evento.purgeEventListener(this);
    delete this._doc;
    delete this._rootEl;
};

LIB_View.prototype.getModel = function() {
    return this._model;
};

LIB_View.prototype.setModel = function(model) {
    if (this._model) {
        evento.removeEventListener(this._model, 'change', this, 'update');
        delete this._model;
    }
    if (model) {
        evento.addEventListener(model, 'change', this, 'update');
        this._model = model;
        this.update();
    }
};

LIB_View.prototype.getController = function() {
    return this._controller;
};

LIB_View.prototype.setController = function(controller) {
    if (this._controller) {
        delete this._controller;
    }
    if (controller) {
        this._controller = controller;
    }
};
<|endoftext|>


<commit_before>'use strict';

////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Alan Plum
////////////////////////////////////////////////////////////////////////////////

const _ = require('lodash');
const assert = require('assert');
const typeIs = require('type-is');
const mediaTyper = require('media-typer');
const requestParts = require('internal').requestParts;

exports.validateParams = function validateParams(typeDefs, rawParams, type) {
  if (!type) {
    type = 'parameter';
  }
  const params = {};
  for (const entry of typeDefs) {
    const name = entry[0];
    const def = entry[1];
    if (def.schema.isJoi) {
      const result = def.schema.validate(rawParams[name]);
      if (result.error) {
        const e = result.error;
        e.message = e.message.replace(/^"value"/, `${type} "${name}"`);
        throw e;
      }
      params[name] = result.value;
    }
  }
  return params;
};

exports.parseRequestBody = function parseRequestBody(def, req) {
  let body = req.body;

  if (!def.contentTypes) {
    assert(!body || !body.length, 'Unexpected request body');
    return null;
  }

  const indicatedType = req.get('content-type');
  let actualType;

  if (indicatedType) {
    for (const candidate of def.contentTypes) {
      if (typeIs.is(indicatedType, candidate)) {
        actualType = candidate;
        break;
      }
    }
  }

  if (!actualType) {
    actualType = def.contentTypes[0] || indicatedType;
  }

  const parsedType = mediaTyper.parse(actualType);
  actualType = mediaTyper.format(_.pick(parsedType, ['type', 'subtype', 'suffix']));

  if (parsedType.type === 'multipart') {
    body = requestParts(req._raw);
  }

  let handler;
  for (const entry of req.context.service.types.entries()) {
    const key = entry[0];
    const value = entry[1];
    let match;
    if (key instanceof RegExp) {
      match = actualType.test(key);
    } else if (typeof key === 'function') {
      match = key(actualType);
    } else {
      match = typeIs.is(key, actualType);
    }
    if (match && value.fromClient) {
      handler = value;
      break;
    }
  }

  if (handler) {
    body = handler.fromClient(body, req, parsedType);
  }

  return body;
};

exports.validateRequestBody = function validateRequestBody(def, req) {
  let body = req.body;

  const schema = def.model && (def.model.schema || def.model);
  if (!schema) {
    return body;
  }

  if (schema.isJoi) {
    const result = schema.validate(body);

    if (result.error) {
      result.error.message = result.error.message.replace(/^"value"/, '"request body"');
      throw result.error;
    }

    body = result.value;
  }

  if (def.model && def.model.fromClient) {
    body = def.model.fromClient(body);
  }

  return body;
};
<commit_msg>Remove redundant quotes<commit_after>'use strict';

////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Alan Plum
////////////////////////////////////////////////////////////////////////////////

const _ = require('lodash');
const assert = require('assert');
const typeIs = require('type-is');
const mediaTyper = require('media-typer');
const requestParts = require('internal').requestParts;

exports.validateParams = function validateParams(typeDefs, rawParams, type) {
  if (!type) {
    type = 'parameter';
  }
  const params = {};
  for (const entry of typeDefs) {
    const name = entry[0];
    const def = entry[1];
    if (def.schema.isJoi) {
      const result = def.schema.validate(rawParams[name]);
      if (result.error) {
        const e = result.error;
        e.message = e.message.replace(/^"value"/, `${type} "${name}"`);
        throw e;
      }
      params[name] = result.value;
    }
  }
  return params;
};

exports.parseRequestBody = function parseRequestBody(def, req) {
  let body = req.body;

  if (!def.contentTypes) {
    assert(!body || !body.length, 'Unexpected request body');
    return null;
  }

  const indicatedType = req.get('content-type');
  let actualType;

  if (indicatedType) {
    for (const candidate of def.contentTypes) {
      if (typeIs.is(indicatedType, candidate)) {
        actualType = candidate;
        break;
      }
    }
  }

  if (!actualType) {
    actualType = def.contentTypes[0] || indicatedType;
  }

  const parsedType = mediaTyper.parse(actualType);
  actualType = mediaTyper.format(_.pick(parsedType, ['type', 'subtype', 'suffix']));

  if (parsedType.type === 'multipart') {
    body = requestParts(req._raw);
  }

  let handler;
  for (const entry of req.context.service.types.entries()) {
    const key = entry[0];
    const value = entry[1];
    let match;
    if (key instanceof RegExp) {
      match = actualType.test(key);
    } else if (typeof key === 'function') {
      match = key(actualType);
    } else {
      match = typeIs.is(key, actualType);
    }
    if (match && value.fromClient) {
      handler = value;
      break;
    }
  }

  if (handler) {
    body = handler.fromClient(body, req, parsedType);
  }

  return body;
};

exports.validateRequestBody = function validateRequestBody(def, req) {
  let body = req.body;

  const schema = def.model && (def.model.schema || def.model);
  if (!schema) {
    return body;
  }

  if (schema.isJoi) {
    const result = schema.validate(body);

    if (result.error) {
      result.error.message = result.error.message.replace(/^"value"/, 'request body');
      throw result.error;
    }

    body = result.value;
  }

  if (def.model && def.model.fromClient) {
    body = def.model.fromClient(body);
  }

  return body;
};
<|endoftext|>


<commit_before>/*
 * L.esri.WebMap
 * A leaflet plugin to display ArcGIS Web Map. https://github.com/ynunokawa/L.esri.WebMap
 * (c) 2016 Yusuke Nunokawa
 *
 * @example
 *
 * ```js
 * var webmap = L.webmap('22c504d229f14c789c5b49ebff38b941', { map: L.map('map') });
 * ```
 */

import { version } from '../package.json';

import L from 'leaflet';
import { operationalLayer } from './OperationalLayer';

export var WebMap = L.Evented.extend({
  options: {
    // L.Map
    map: {},
    // access token for secure contents on ArcGIS Online
    token: null,
    // server domain name (default= 'www.arcgis.com')
    server: 'www.arcgis.com'
  },

  initialize: function (webmapId, options) {
    L.setOptions(this, options);

    this._map = this.options.map;
    this._token = this.options.token;
    this._server = this.options.server;
    this._webmapId = webmapId;
    this._loaded = false;
    this._metadataLoaded = false;
    this._loadedLayersNum = 0;
    this._layersNum = 0;

    this.layers = []; // Check the layer types here -> https://github.com/ynunokawa/L.esri.WebMap/wiki/Layer-types
    this.title = ''; // Web Map Title
    this.bookmarks = []; // Web Map Bookmarks -> [{ name: 'Bookmark name', bounds: <L.latLngBounds> }]
    this.portalItem = {}; // Web Map Metadata

    this.VERSION = version;

    this._loadWebMapMetaData(webmapId);
    this._loadWebMap(webmapId);
  },

  _checkLoaded: function () {
    this._loadedLayersNum++;
    if (this._loadedLayersNum === this._layersNum) {
      this._loaded = true;
      this.fire('load');
    }
  },

  _operationalLayer: function (layer, layers, map, params, paneName) {
    var lyr = operationalLayer(layer, layers, map, params).addTo(map);
    if (lyr !== undefined && layer.visibility === true) {
      lyr.addTo(map);
    }
  },

  _loadWebMapMetaData: function (id) {
    var params = {};
    var map = this._map;
    var webmap = this;
    var webmapMetaDataRequestUrl = 'https://' + this._server + '/sharing/rest/content/items/' + id;
    if (this._token && this._token.length > 0) {
      params.token = this._token;
    }

    L.esri.request(webmapMetaDataRequestUrl, params, function (error, response) {
      if (error) {
        console.log(error);
      } else {
        console.log('WebMap MetaData: ', response);
        webmap.portalItem = response;
        webmap.title = response.title;
        webmap._metadataLoaded = true;
        webmap.fire('metadataLoad');
        map.fitBounds([response.extent[0].reverse(), response.extent[1].reverse()]);
      }
    });
  },

  _loadWebMap: function (id) {
    var map = this._map;
    var layers = this.layers;
    var server = this._server;
    var params = {};
    var webmapRequestUrl = 'https://' + server + '/sharing/rest/content/items/' + id + '/data';
    if (this._token && this._token.length > 0) {
      params.token = this._token;
    }

    L.esri.request(webmapRequestUrl, params, function (error, response) {
      if (error) {
        console.log(error);
      } else {
        console.log('WebMap: ', response);
        this._layersNum = response.baseMap.baseMapLayers.length + response.operationalLayers.length;

        // Add Basemap
        response.baseMap.baseMapLayers.map(function (baseMapLayer) {
          if (baseMapLayer.itemId !== undefined) {
            var itemRequestUrl = 'https://' + server + '/sharing/rest/content/items/' + baseMapLayer.itemId;
            L.esri.request(itemRequestUrl, params, function (err, res) {
              if (err) {
                console.error(error);
              } else {
                console.log(res.access);
                if (res.access !== 'public') {
                  this._operationalLayer(baseMapLayer, layers, map, params);
                } else {
                  this._operationalLayer(baseMapLayer, layers, map, {});
                }
              }
              this._checkLoaded();
            }, this);
          } else {
            this._operationalLayer(baseMapLayer, layers, map, {});
            this._checkLoaded();
          }
        }.bind(this));

        // Add Operational Layers
        response.operationalLayers.map(function (layer, i) {
          var paneName = 'esri-webmap-layer' + i;
          map.createPane(paneName);
          if (layer.itemId !== undefined) {
            var itemRequestUrl = 'https://' + server + '/sharing/rest/content/items/' + layer.itemId;
            L.esri.request(itemRequestUrl, params, function (err, res) {
              if (err) {
                console.error(error);
              } else {
                console.log(res.access);
                if (res.access !== 'public') {
                  this._operationalLayer(layer, layers, map, params, paneName);
                } else {
                  this._operationalLayer(layer, layers, map, {}, paneName);
                }
              }
              this._checkLoaded();
            }, this);
          } else {
            this._operationalLayer(layer, layers, map, {}, paneName);
            this._checkLoaded();
          }
        }.bind(this));

        // Add Bookmarks
        if (response.bookmarks !== undefined && response.bookmarks.length > 0) {
          response.bookmarks.map(function (bookmark) {
            // Esri Extent Geometry to L.latLngBounds
            var northEast = L.Projection.SphericalMercator.unproject(L.point(bookmark.extent.xmax, bookmark.extent.ymax));
            var southWest = L.Projection.SphericalMercator.unproject(L.point(bookmark.extent.xmin, bookmark.extent.ymin));
            var bounds = L.latLngBounds(southWest, northEast);
            this.bookmarks.push({ name: bookmark.name, bounds: bounds });
          }.bind(this));
        }

        //this._loaded = true;
        //this.fire('load');
      }
    }.bind(this));
  }
});

export function webMap (webmapId, options) {
  return new WebMap(webmapId, options);
}

export default webMap;
<commit_msg>bug fix: layer visibility<commit_after>/*
 * L.esri.WebMap
 * A leaflet plugin to display ArcGIS Web Map. https://github.com/ynunokawa/L.esri.WebMap
 * (c) 2016 Yusuke Nunokawa
 *
 * @example
 *
 * ```js
 * var webmap = L.webmap('22c504d229f14c789c5b49ebff38b941', { map: L.map('map') });
 * ```
 */

import { version } from '../package.json';

import L from 'leaflet';
import { operationalLayer } from './OperationalLayer';

export var WebMap = L.Evented.extend({
  options: {
    // L.Map
    map: {},
    // access token for secure contents on ArcGIS Online
    token: null,
    // server domain name (default= 'www.arcgis.com')
    server: 'www.arcgis.com'
  },

  initialize: function (webmapId, options) {
    L.setOptions(this, options);

    this._map = this.options.map;
    this._token = this.options.token;
    this._server = this.options.server;
    this._webmapId = webmapId;
    this._loaded = false;
    this._metadataLoaded = false;
    this._loadedLayersNum = 0;
    this._layersNum = 0;

    this.layers = []; // Check the layer types here -> https://github.com/ynunokawa/L.esri.WebMap/wiki/Layer-types
    this.title = ''; // Web Map Title
    this.bookmarks = []; // Web Map Bookmarks -> [{ name: 'Bookmark name', bounds: <L.latLngBounds> }]
    this.portalItem = {}; // Web Map Metadata

    this.VERSION = version;

    this._loadWebMapMetaData(webmapId);
    this._loadWebMap(webmapId);
  },

  _checkLoaded: function () {
    this._loadedLayersNum++;
    if (this._loadedLayersNum === this._layersNum) {
      this._loaded = true;
      this.fire('load');
    }
  },

  _operationalLayer: function (layer, layers, map, params, paneName) {
    var lyr = operationalLayer(layer, layers, map, params);
    if (lyr !== undefined && layer.visibility === true) {
      lyr.addTo(map);
    }
  },

  _loadWebMapMetaData: function (id) {
    var params = {};
    var map = this._map;
    var webmap = this;
    var webmapMetaDataRequestUrl = 'https://' + this._server + '/sharing/rest/content/items/' + id;
    if (this._token && this._token.length > 0) {
      params.token = this._token;
    }

    L.esri.request(webmapMetaDataRequestUrl, params, function (error, response) {
      if (error) {
        console.log(error);
      } else {
        console.log('WebMap MetaData: ', response);
        webmap.portalItem = response;
        webmap.title = response.title;
        webmap._metadataLoaded = true;
        webmap.fire('metadataLoad');
        map.fitBounds([response.extent[0].reverse(), response.extent[1].reverse()]);
      }
    });
  },

  _loadWebMap: function (id) {
    var map = this._map;
    var layers = this.layers;
    var server = this._server;
    var params = {};
    var webmapRequestUrl = 'https://' + server + '/sharing/rest/content/items/' + id + '/data';
    if (this._token && this._token.length > 0) {
      params.token = this._token;
    }

    L.esri.request(webmapRequestUrl, params, function (error, response) {
      if (error) {
        console.log(error);
      } else {
        console.log('WebMap: ', response);
        this._layersNum = response.baseMap.baseMapLayers.length + response.operationalLayers.length;

        // Add Basemap
        response.baseMap.baseMapLayers.map(function (baseMapLayer) {
          if (baseMapLayer.itemId !== undefined) {
            var itemRequestUrl = 'https://' + server + '/sharing/rest/content/items/' + baseMapLayer.itemId;
            L.esri.request(itemRequestUrl, params, function (err, res) {
              if (err) {
                console.error(error);
              } else {
                console.log(res.access);
                if (res.access !== 'public') {
                  this._operationalLayer(baseMapLayer, layers, map, params);
                } else {
                  this._operationalLayer(baseMapLayer, layers, map, {});
                }
              }
              this._checkLoaded();
            }, this);
          } else {
            this._operationalLayer(baseMapLayer, layers, map, {});
            this._checkLoaded();
          }
        }.bind(this));

        // Add Operational Layers
        response.operationalLayers.map(function (layer, i) {
          var paneName = 'esri-webmap-layer' + i;
          map.createPane(paneName);
          if (layer.itemId !== undefined) {
            var itemRequestUrl = 'https://' + server + '/sharing/rest/content/items/' + layer.itemId;
            L.esri.request(itemRequestUrl, params, function (err, res) {
              if (err) {
                console.error(error);
              } else {
                console.log(res.access);
                if (res.access !== 'public') {
                  this._operationalLayer(layer, layers, map, params, paneName);
                } else {
                  this._operationalLayer(layer, layers, map, {}, paneName);
                }
              }
              this._checkLoaded();
            }, this);
          } else {
            this._operationalLayer(layer, layers, map, {}, paneName);
            this._checkLoaded();
          }
        }.bind(this));

        // Add Bookmarks
        if (response.bookmarks !== undefined && response.bookmarks.length > 0) {
          response.bookmarks.map(function (bookmark) {
            // Esri Extent Geometry to L.latLngBounds
            var northEast = L.Projection.SphericalMercator.unproject(L.point(bookmark.extent.xmax, bookmark.extent.ymax));
            var southWest = L.Projection.SphericalMercator.unproject(L.point(bookmark.extent.xmin, bookmark.extent.ymin));
            var bounds = L.latLngBounds(southWest, northEast);
            this.bookmarks.push({ name: bookmark.name, bounds: bounds });
          }.bind(this));
        }

        //this._loaded = true;
        //this.fire('load');
      }
    }.bind(this));
  }
});

export function webMap (webmapId, options) {
  return new WebMap(webmapId, options);
}

export default webMap;
<|endoftext|>


<commit_before>const { debug, setDebugPhase, getDebug } = require('./debug');
const responseBuilder = require('./response-builder');
const requestUtils = require('./request-utils');
const FetchMock = {};

// see https://heycam.github.io/webidl/#aborterror for the standardised interface
// Note that this differs slightly from node-fetch
class AbortError extends Error {
	constructor() {
		super(...arguments);
		this.name = 'AbortError';
		this.message = 'The operation was aborted.';

		// Do not include this class in the stacktrace
		if (Error.captureStackTrace) {
			Error.captureStackTrace(this, this.constructor);
		}
	}
}

// Patch native fetch to avoid "NotSupportedError:ReadableStream uploading is not supported" in Safari.
// See also https://github.com/wheresrhys/fetch-mock/issues/584
// See also https://stackoverflow.com/a/50952018/1273406
const patchNativeFetchForSafari = (nativeFetch) => {
	// Try to patch fetch only on Safari
	if (
		!navigator ||
		!navigator.vendor ||
		navigator.vendor !== 'Apple Computer, Inc.'
	) {
		return nativeFetch;
	}
	// It seems the code is working on Safari thus patch native fetch to avoid the error.
	return async (request) => {
		const { method } = request;
		if (!['POST', 'PUT', 'PATCH'].includes(method)) {
			// No patch is required in this case
			return nativeFetch(request);
		}
		const body = await request.clone().text();
		const {
			cache,
			credentials,
			headers,
			integrity,
			mode,
			redirect,
			referrer,
		} = request;
		const init = {
			body,
			cache,
			credentials,
			headers,
			integrity,
			mode,
			redirect,
			referrer,
			method,
		};
		return nativeFetch(request.url, init);
	};
};

const resolve = async (
	{ response, responseIsFetch = false },
	url,
	options,
	request
) => {
	const debug = getDebug('resolve()');
	debug('Recursively resolving function and promise responses');
	// We want to allow things like
	// - function returning a Promise for a response
	// - delaying (using a timeout Promise) a function's execution to generate
	//   a response
	// Because of this we can't safely check for function before Promisey-ness,
	// or vice versa. So to keep it DRY, and flexible, we keep trying until we
	// have something that looks like neither Promise nor function
	while (true) {
		if (typeof response === 'function') {
			debug('  Response is a function');
			// in the case of falling back to the network we need to make sure we're using
			// the original Request instance, not our normalised url + options
			if (responseIsFetch) {
				if (request) {
					debug('  -> Calling fetch with Request instance');
					return response(request);
				}
				debug('  -> Calling fetch with url and options');
				return response(url, options);
			} else {
				debug('  -> Calling response function');
				response = response(url, options, request);
			}
		} else if (typeof response.then === 'function') {
			debug('  Response is a promise');
			debug('  -> Resolving promise');
			response = await response;
		} else {
			debug('  Response is not a function or a promise');
			debug('  -> Exiting response resolution recursion');
			return response;
		}
	}
};

FetchMock.needsAsyncBodyExtraction = function ({ request }) {
	return request && this.routes.some(({ usesBody }) => usesBody);
};

FetchMock.fetchHandler = function (url, options) {
	setDebugPhase('handle');
	const debug = getDebug('fetchHandler()');
	debug('fetch called with:', url, options);

	const normalizedRequest = requestUtils.normalizeRequest(
		url,
		options,
		this.config.Request
	);

	debug('Request normalised');
	debug('  url', normalizedRequest.url);
	debug('  options', normalizedRequest.options);
	debug('  request', normalizedRequest.request);
	debug('  signal', normalizedRequest.signal);

	if (this.needsAsyncBodyExtraction(normalizedRequest)) {
		debug(
			'Need to wait for Body to be streamed before calling router: switching to async mode'
		);
		return this._extractBodyThenHandle(normalizedRequest);
	}
	return this._fetchHandler(normalizedRequest);
};

FetchMock._extractBodyThenHandle = async function (normalizedRequest) {
	normalizedRequest.options.body = await normalizedRequest.options.body;
	return this._fetchHandler(normalizedRequest);
};

FetchMock._fetchHandler = function ({ url, options, request, signal }) {
	const { route, callLog } = this.executeRouter(url, options, request);

	this.recordCall(callLog);

	// this is used to power the .flush() method
	let done;
	this._holdingPromises.push(new this.config.Promise((res) => (done = res)));

	// wrapped in this promise to make sure we respect custom Promise
	// constructors defined by the user
	return new this.config.Promise((res, rej) => {
		if (signal) {
			debug('signal exists - enabling fetch abort');
			const abort = () => {
				debug('aborting fetch');
				// note that DOMException is not available in node.js;
				// even node-fetch uses a custom error class:
				// https://github.com/bitinn/node-fetch/blob/master/src/abort-error.js
				rej(
					typeof DOMException !== 'undefined'
						? new DOMException('The operation was aborted.', 'AbortError')
						: new AbortError()
				);
				done();
			};
			if (signal.aborted) {
				debug('signal is already aborted - aborting the fetch');
				abort();
			}
			signal.addEventListener('abort', abort);
		}

		this.generateResponse({ route, url, options, request, callLog })
			.then(res, rej)
			.then(done, done)
			.then(() => {
				setDebugPhase();
			});
	});
};

FetchMock.fetchHandler.isMock = true;

FetchMock.executeRouter = function (url, options, request) {
	const debug = getDebug('executeRouter()');
	const callLog = { url, options, request, isUnmatched: true };
	debug(`Attempting to match request to a route`);
	if (this.getOption('fallbackToNetwork') === 'always') {
		debug(
			'  Configured with fallbackToNetwork=always - passing through to fetch'
		);
		return {
			route: { response: this.getNativeFetch(), responseIsFetch: true },
			// BUG - this callLog never used to get sent. Discovered the bug
			// but can't fix outside a major release as it will potentially
			// cause too much disruption
			//
			// callLog,
		};
	}

	const route = this.router(url, options, request);

	if (route) {
		debug('  Matching route found');
		return {
			route,
			callLog: {
				url,
				options,
				request,
				identifier: route.identifier,
			},
		};
	}

	if (this.getOption('warnOnFallback')) {
		console.warn(`Unmatched ${(options && options.method) || 'GET'} to ${url}`); // eslint-disable-line
	}

	if (this.fallbackResponse) {
		debug('  No matching route found - using fallbackResponse');
		return { route: { response: this.fallbackResponse }, callLog };
	}

	if (!this.getOption('fallbackToNetwork')) {
		throw new Error(
			`fetch-mock: No fallback response defined for ${
				(options && options.method) || 'GET'
			} to ${url}`
		);
	}

	debug('  Configured to fallbackToNetwork - passing through to fetch');
	return {
		route: { response: this.getNativeFetch(), responseIsFetch: true },
		callLog,
	};
};

FetchMock.generateResponse = async function ({
	route,
	url,
	options,
	request,
	callLog = {},
}) {
	const debug = getDebug('generateResponse()');
	const response = await resolve(route, url, options, request);

	// If the response says to throw an error, throw it
	// Type checking is to deal with sinon spies having a throws property :-0
	if (response.throws && typeof response !== 'function') {
		debug('response.throws is defined - throwing an error');
		throw response.throws;
	}

	// If the response is a pre-made Response, respond with it
	if (this.config.Response.prototype.isPrototypeOf(response)) {
		debug('response is already a Response instance - returning it');
		callLog.response = response;
		return response;
	}

	// finally, if we need to convert config into a response, we do it
	const [realResponse, finalResponse] = responseBuilder({
		url,
		responseConfig: response,
		fetchMock: this,
		route,
	});

	callLog.response = realResponse;

	return finalResponse;
};

FetchMock.router = function (url, options, request) {
	const route = this.routes.find((route, i) => {
		debug(`Trying to match route ${i}`);
		return route.matcher(url, options, request);
	});

	if (route) {
		return route;
	}
};

FetchMock.getNativeFetch = function () {
	const func = this.realFetch || (this.isSandbox && this.config.fetch);
	if (!func) {
		throw new Error(
			'fetch-mock: Falling back to network only available on global fetch-mock, or by setting config.fetch on sandboxed fetch-mock'
		);
	}
	return patchNativeFetchForSafari(func);
};

FetchMock.recordCall = function (obj) {
	debug('Recording fetch call', obj);
	if (obj) {
		this._calls.push(obj);
	}
};

module.exports = FetchMock;
<commit_msg>fix server side code<commit_after>const { debug, setDebugPhase, getDebug } = require('./debug');
const responseBuilder = require('./response-builder');
const requestUtils = require('./request-utils');
const FetchMock = {};

// see https://heycam.github.io/webidl/#aborterror for the standardised interface
// Note that this differs slightly from node-fetch
class AbortError extends Error {
	constructor() {
		super(...arguments);
		this.name = 'AbortError';
		this.message = 'The operation was aborted.';

		// Do not include this class in the stacktrace
		if (Error.captureStackTrace) {
			Error.captureStackTrace(this, this.constructor);
		}
	}
}

// Patch native fetch to avoid "NotSupportedError:ReadableStream uploading is not supported" in Safari.
// See also https://github.com/wheresrhys/fetch-mock/issues/584
// See also https://stackoverflow.com/a/50952018/1273406
const patchNativeFetchForSafari = (nativeFetch) => {
	// Try to patch fetch only on Safari
	if (
		typeof navigator === 'undefined' ||
		!navigator.vendor ||
		navigator.vendor !== 'Apple Computer, Inc.'
	) {
		return nativeFetch;
	}
	// It seems the code is working on Safari thus patch native fetch to avoid the error.
	return async (request) => {
		const { method } = request;
		if (!['POST', 'PUT', 'PATCH'].includes(method)) {
			// No patch is required in this case
			return nativeFetch(request);
		}
		const body = await request.clone().text();
		const {
			cache,
			credentials,
			headers,
			integrity,
			mode,
			redirect,
			referrer,
		} = request;
		const init = {
			body,
			cache,
			credentials,
			headers,
			integrity,
			mode,
			redirect,
			referrer,
			method,
		};
		return nativeFetch(request.url, init);
	};
};

const resolve = async (
	{ response, responseIsFetch = false },
	url,
	options,
	request
) => {
	const debug = getDebug('resolve()');
	debug('Recursively resolving function and promise responses');
	// We want to allow things like
	// - function returning a Promise for a response
	// - delaying (using a timeout Promise) a function's execution to generate
	//   a response
	// Because of this we can't safely check for function before Promisey-ness,
	// or vice versa. So to keep it DRY, and flexible, we keep trying until we
	// have something that looks like neither Promise nor function
	while (true) {
		if (typeof response === 'function') {
			debug('  Response is a function');
			// in the case of falling back to the network we need to make sure we're using
			// the original Request instance, not our normalised url + options
			if (responseIsFetch) {
				if (request) {
					debug('  -> Calling fetch with Request instance');
					return response(request);
				}
				debug('  -> Calling fetch with url and options');
				return response(url, options);
			} else {
				debug('  -> Calling response function');
				response = response(url, options, request);
			}
		} else if (typeof response.then === 'function') {
			debug('  Response is a promise');
			debug('  -> Resolving promise');
			response = await response;
		} else {
			debug('  Response is not a function or a promise');
			debug('  -> Exiting response resolution recursion');
			return response;
		}
	}
};

FetchMock.needsAsyncBodyExtraction = function ({ request }) {
	return request && this.routes.some(({ usesBody }) => usesBody);
};

FetchMock.fetchHandler = function (url, options) {
	setDebugPhase('handle');
	const debug = getDebug('fetchHandler()');
	debug('fetch called with:', url, options);

	const normalizedRequest = requestUtils.normalizeRequest(
		url,
		options,
		this.config.Request
	);

	debug('Request normalised');
	debug('  url', normalizedRequest.url);
	debug('  options', normalizedRequest.options);
	debug('  request', normalizedRequest.request);
	debug('  signal', normalizedRequest.signal);

	if (this.needsAsyncBodyExtraction(normalizedRequest)) {
		debug(
			'Need to wait for Body to be streamed before calling router: switching to async mode'
		);
		return this._extractBodyThenHandle(normalizedRequest);
	}
	return this._fetchHandler(normalizedRequest);
};

FetchMock._extractBodyThenHandle = async function (normalizedRequest) {
	normalizedRequest.options.body = await normalizedRequest.options.body;
	return this._fetchHandler(normalizedRequest);
};

FetchMock._fetchHandler = function ({ url, options, request, signal }) {
	const { route, callLog } = this.executeRouter(url, options, request);

	this.recordCall(callLog);

	// this is used to power the .flush() method
	let done;
	this._holdingPromises.push(new this.config.Promise((res) => (done = res)));

	// wrapped in this promise to make sure we respect custom Promise
	// constructors defined by the user
	return new this.config.Promise((res, rej) => {
		if (signal) {
			debug('signal exists - enabling fetch abort');
			const abort = () => {
				debug('aborting fetch');
				// note that DOMException is not available in node.js;
				// even node-fetch uses a custom error class:
				// https://github.com/bitinn/node-fetch/blob/master/src/abort-error.js
				rej(
					typeof DOMException !== 'undefined'
						? new DOMException('The operation was aborted.', 'AbortError')
						: new AbortError()
				);
				done();
			};
			if (signal.aborted) {
				debug('signal is already aborted - aborting the fetch');
				abort();
			}
			signal.addEventListener('abort', abort);
		}

		this.generateResponse({ route, url, options, request, callLog })
			.then(res, rej)
			.then(done, done)
			.then(() => {
				setDebugPhase();
			});
	});
};

FetchMock.fetchHandler.isMock = true;

FetchMock.executeRouter = function (url, options, request) {
	const debug = getDebug('executeRouter()');
	const callLog = { url, options, request, isUnmatched: true };
	debug(`Attempting to match request to a route`);
	if (this.getOption('fallbackToNetwork') === 'always') {
		debug(
			'  Configured with fallbackToNetwork=always - passing through to fetch'
		);
		return {
			route: { response: this.getNativeFetch(), responseIsFetch: true },
			// BUG - this callLog never used to get sent. Discovered the bug
			// but can't fix outside a major release as it will potentially
			// cause too much disruption
			//
			// callLog,
		};
	}

	const route = this.router(url, options, request);

	if (route) {
		debug('  Matching route found');
		return {
			route,
			callLog: {
				url,
				options,
				request,
				identifier: route.identifier,
			},
		};
	}

	if (this.getOption('warnOnFallback')) {
		console.warn(`Unmatched ${(options && options.method) || 'GET'} to ${url}`); // eslint-disable-line
	}

	if (this.fallbackResponse) {
		debug('  No matching route found - using fallbackResponse');
		return { route: { response: this.fallbackResponse }, callLog };
	}

	if (!this.getOption('fallbackToNetwork')) {
		throw new Error(
			`fetch-mock: No fallback response defined for ${
				(options && options.method) || 'GET'
			} to ${url}`
		);
	}

	debug('  Configured to fallbackToNetwork - passing through to fetch');
	return {
		route: { response: this.getNativeFetch(), responseIsFetch: true },
		callLog,
	};
};

FetchMock.generateResponse = async function ({
	route,
	url,
	options,
	request,
	callLog = {},
}) {
	const debug = getDebug('generateResponse()');
	const response = await resolve(route, url, options, request);

	// If the response says to throw an error, throw it
	// Type checking is to deal with sinon spies having a throws property :-0
	if (response.throws && typeof response !== 'function') {
		debug('response.throws is defined - throwing an error');
		throw response.throws;
	}

	// If the response is a pre-made Response, respond with it
	if (this.config.Response.prototype.isPrototypeOf(response)) {
		debug('response is already a Response instance - returning it');
		callLog.response = response;
		return response;
	}

	// finally, if we need to convert config into a response, we do it
	const [realResponse, finalResponse] = responseBuilder({
		url,
		responseConfig: response,
		fetchMock: this,
		route,
	});

	callLog.response = realResponse;

	return finalResponse;
};

FetchMock.router = function (url, options, request) {
	const route = this.routes.find((route, i) => {
		debug(`Trying to match route ${i}`);
		return route.matcher(url, options, request);
	});

	if (route) {
		return route;
	}
};

FetchMock.getNativeFetch = function () {
	const func = this.realFetch || (this.isSandbox && this.config.fetch);
	if (!func) {
		throw new Error(
			'fetch-mock: Falling back to network only available on global fetch-mock, or by setting config.fetch on sandboxed fetch-mock'
		);
	}
	return patchNativeFetchForSafari(func);
};

FetchMock.recordCall = function (obj) {
	debug('Recording fetch call', obj);
	if (obj) {
		this._calls.push(obj);
	}
};

module.exports = FetchMock;
<|endoftext|>


<commit_before>// Generated by CoffeeScript 1.9.3
var deleteCookie, getCookie, setCookie;

setCookie = function(name, value, days) {
  var date, expires;
  if (days) {
    date = new Date();
    date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
    expires = "; expires=" + date.toGMTString();
  } else {
    expires = "";
  }
  return document.cookie = name + "=" + value + expires + "; path=/";
};

getCookie = function(name) {
  var c, ca, i, nameEQ;
  nameEQ = name + "=";
  ca = document.cookie.split(";");
  i = 0;
  while (i < ca.length) {
    c = ca[i];
    while (c.charAt(0) === " ") {
      c = c.substring(1, c.length);
    }
    if (c.indexOf(nameEQ) === 0) {
      return c.substring(nameEQ.length, c.length);
    }
    i++;
  }
  return null;
};

deleteCookie = function(name) {
  return setCookie(name, "", -1);
};

window.p_hi = new Parser('devanagari', devanagari_tokens, devanagari_token_regex, devanagari_graph, devanagari_onmatch);

window.p_ur = new Parser('urdu', urdu_tokens, urdu_token_regex, urdu_graph, urdu_onmatch);

window.p_trans = new Parser('diacritics', diacritics_tokens, diacritics_token_regex, diacritics_graph, diacritics_onmatch);

$(function() {
  var c, changeScript, getParser, languageBar, languageBarHTML, lastClass, loc, parseText, parser, textClasses, textPreference, urduItemsOriginals;
  parseText = function() {
    $('em.urdu').each((function(_this) {
      return function(index, u) {
        var em, get_text, j, len, n, orig, te;
        orig = urduItemsOriginals[index];
        if (parser === null) {
          return $(u).replaceWith(orig);
        } else {
          em = $(orig).clone(true);
          te = [];
          get_text = function(n) {
            return $(n).contents().each(function(index, n) {
              if (n.nodeType === 3) {
                return te.push(n);
              } else if (n.nodeType === 1) {
                return get_text(n);
              }
            });
          };
          get_text(em);
          for (j = 0, len = te.length; j < len; j++) {
            n = te[j];
            n.textContent = parser.parse(n.textContent);
          }
          return $(u).replaceWith(em);
        }
      };
    })(this));
    $('em.urdu').removeClass(window.lastClass).addClass(textClasses[textPreference]);
    window.lastClass = textClasses[textPreference];
  };
  urduItemsOriginals = $('em.urdu').clone();
  getParser = function() {
    switch (false) {
      case textPreference !== 'urdu':
        return p_ur;
      case textPreference !== 'devanagari':
        return p_hi;
      case textPreference !== 'diacritics':
        return p_trans;
      default:
        return null;
    }
  };
  textClasses = {
    'urdu': 'Nastaliq',
    'devanagari': 'Devanagari',
    'diacritics': 'Diacritics',
    'plain_roman': ''
  };
  lastClass = '';
  c = getCookie('mealac_script');
  languageBarHTML = '';
  if (!c) {
    setCookie('mealac_script', 'diacritics', 1000, '/');
    getCookie('mealac_script');
    if (!c) {
      languageBarHTML = '
Cookies need to be enabled to store your script preference between pages.
';
    }
  }
  if (c) {
    textPreference = c;
  } else {
    textPreference = 'diacritics';
  }
  parser = getParser();
  languageBarHTML += '
 -- urdu script -- devanagari -- diacritics -- plain roman --  more information --
';
  languageBar = $(languageBarHTML);
  languageBar.appendTo('body');
  changeScript = function() {
    $('a.languageButton').each((function(_this) {
      return function(index, element) {
        var id;
        id = $(element).attr("id");
        if (id.slice(0, id.length - '_button'.length) === textPreference) {
          $(element).removeAttr('href');
        } else {
          $(element).attr('href', '#');
        }
        parser = getParser();
        parseText();
        return setCookie('mealac_script', textPreference, 1000, '/');
      };
    })(this));
  };
  $('a.languageButton').each((function(_this) {
    return function(index, element) {
      var id;
      id = $(element).attr("id");
      $(element).click(function() {
        textPreference = id.slice(0, id.length - '_button'.length);
        changeScript();
        return void 0;
      });
    };
  })(this));
  loc = $('div.verse:first');
  if (!loc.length) {
    loc = $('div.verse-entry:first');
  }
  if (!loc.length) {
    loc = $('div.boxer:first');
  }
  if (loc.length) {
    $(languageBar).insertBefore(loc);
  }
  changeScript();
  return void 0;
});
<commit_msg>fixed error in cookie checking<commit_after>// Generated by CoffeeScript 1.9.3
var deleteCookie, getCookie, setCookie;

setCookie = function(name, value, days) {
  var date, expires;
  if (days) {
    date = new Date();
    date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
    expires = "; expires=" + date.toGMTString();
  } else {
    expires = "";
  }
  return document.cookie = name + "=" + value + expires + "; path=/";
};

getCookie = function(name) {
  var c, ca, i, nameEQ;
  nameEQ = name + "=";
  ca = document.cookie.split(";");
  i = 0;
  while (i < ca.length) {
    c = ca[i];
    while (c.charAt(0) === " ") {
      c = c.substring(1, c.length);
    }
    if (c.indexOf(nameEQ) === 0) {
      return c.substring(nameEQ.length, c.length);
    }
    i++;
  }
  return null;
};

deleteCookie = function(name) {
  return setCookie(name, "", -1);
};

window.p_hi = new Parser('devanagari', devanagari_tokens, devanagari_token_regex, devanagari_graph, devanagari_onmatch);

window.p_ur = new Parser('urdu', urdu_tokens, urdu_token_regex, urdu_graph, urdu_onmatch);

window.p_trans = new Parser('diacritics', diacritics_tokens, diacritics_token_regex, diacritics_graph, diacritics_onmatch);

$(function() {
  var c, changeScript, getParser, languageBar, languageBarHTML, lastClass, loc, parseText, parser, textClasses, textPreference, urduItemsOriginals;
  parseText = function() {
    $('em.urdu').each((function(_this) {
      return function(index, u) {
        var em, get_text, j, len, n, orig, te;
        orig = urduItemsOriginals[index];
        if (parser === null) {
          return $(u).replaceWith(orig);
        } else {
          em = $(orig).clone(true);
          te = [];
          get_text = function(n) {
            return $(n).contents().each(function(index, n) {
              if (n.nodeType === 3) {
                return te.push(n);
              } else if (n.nodeType === 1) {
                return get_text(n);
              }
            });
          };
          get_text(em);
          for (j = 0, len = te.length; j < len; j++) {
            n = te[j];
            n.textContent = parser.parse(n.textContent);
          }
          return $(u).replaceWith(em);
        }
      };
    })(this));
    $('em.urdu').removeClass(window.lastClass).addClass(textClasses[textPreference]);
    window.lastClass = textClasses[textPreference];
  };
  urduItemsOriginals = $('em.urdu').clone();
  getParser = function() {
    switch (false) {
      case textPreference !== 'urdu':
        return p_ur;
      case textPreference !== 'devanagari':
        return p_hi;
      case textPreference !== 'diacritics':
        return p_trans;
      default:
        return null;
    }
  };
  textClasses = {
    'urdu': 'Nastaliq',
    'devanagari': 'Devanagari',
    'diacritics': 'Diacritics',
    'plain_roman': ''
  };
  lastClass = '';
  c = getCookie('mealac_script');
  languageBarHTML = '';
  if (!c) {
    setCookie('mealac_script', 'diacritics', 1000, '/');
    c=getCookie('mealac_script');
    if (!c) {
      languageBarHTML = '
Cookies need to be enabled to store your script preference between pages.
';
    }
  }
  if (c) {
    textPreference = c;
  } else {
    textPreference = 'diacritics';
  }
  parser = getParser();
  languageBarHTML += '
 -- urdu script -- devanagari -- diacritics -- plain roman --  more information --
';
  languageBar = $(languageBarHTML);
  languageBar.appendTo('body');
  changeScript = function() {
    $('a.languageButton').each((function(_this) {
      return function(index, element) {
        var id;
        id = $(element).attr("id");
        if (id.slice(0, id.length - '_button'.length) === textPreference) {
          $(element).removeAttr('href');
        } else {
          $(element).attr('href', '#');
        }
        parser = getParser();
        parseText();
        return setCookie('mealac_script', textPreference, 1000, '/');
      };
    })(this));
  };
  $('a.languageButton').each((function(_this) {
    return function(index, element) {
      var id;
      id = $(element).attr("id");
      $(element).click(function() {
        textPreference = id.slice(0, id.length - '_button'.length);
        changeScript();
        return void 0;
      });
    };
  })(this));
  loc = $('div.verse:first');
  if (!loc.length) {
    loc = $('div.verse-entry:first');
  }
  if (!loc.length) {
    loc = $('div.boxer:first');
  }
  if (loc.length) {
    $(languageBar).insertBefore(loc);
  }
  changeScript();
  return void 0;
});
<|endoftext|>