<commit_before>/*
Copyright 2016 OpenMarket Ltd
Copyright 2018, 2019 New Vector 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.
*/

const React = require('react');
import PropTypes from 'prop-types';
const MatrixClientPeg = require('../../../MatrixClientPeg');
const sdk = require("../../../index");
import { _t } from '../../../languageHandler';
import Field from "../elements/Field";
import ErrorDialog from "../dialogs/ErrorDialog";
const Modal = require("../../../Modal");

export default class AliasSettings extends React.Component {
    static propTypes = {
        roomId: PropTypes.string.isRequired,
        canSetCanonicalAlias: PropTypes.bool.isRequired,
        canSetAliases: PropTypes.bool.isRequired,
        aliasEvents: PropTypes.array, // [MatrixEvent]
        canonicalAliasEvent: PropTypes.object, // MatrixEvent
    };

    static defaultProps = {
        canSetAliases: false,
        canSetCanonicalAlias: false,
        aliasEvents: [],
    };

    constructor(props) {
        super(props);

        const state = {
            domainToAliases: {}, // { domain.com => [#alias1:domain.com, #alias2:domain.com] }
            remoteDomains: [], // [ domain.com, foobar.com ]
            canonicalAlias: null, // #canonical:domain.com
            updatingCanonicalAlias: false,
            newItem: "",
        };

        const localDomain = MatrixClientPeg.get().getDomain();
        state.domainToAliases = this.aliasEventsToDictionary(props.aliasEvents || []);
        state.remoteDomains = Object.keys(state.domainToAliases).filter((domain) => {
            return domain !== localDomain && state.domainToAliases[domain].length > 0;
        });

        if (props.canonicalAliasEvent) {
            state.canonicalAlias = props.canonicalAliasEvent.getContent().alias;
        }

        this.state = state;
    }

    aliasEventsToDictionary(aliasEvents) { // m.room.alias events
        const dict = {};
        aliasEvents.forEach((event) => {
            dict[event.getStateKey()] = (
                (event.getContent().aliases || []).slice() // shallow-copy
            );
        });
        return dict;
    }

    isAliasValid(alias) {
        // XXX: FIXME https://github.com/matrix-org/matrix-doc/issues/668
        return (alias.match(/^#([^\/:,]+?):(.+)$/) && encodeURI(alias) === alias);
    }

    changeCanonicalAlias(alias) {
        if (!this.props.canSetCanonicalAlias) return;

        this.setState({
            canonicalAlias: alias,
            updatingCanonicalAlias: true,
        });

        const eventContent = {};
        if (alias) eventContent["alias"] = alias;

        MatrixClientPeg.get().sendStateEvent(this.props.roomId, "m.room.canonical_alias",
            eventContent, "").catch((err) => {
            console.error(err);
            Modal.createTrackedDialog('Error updating main address', '', ErrorDialog, {
                title: _t("Error updating main address"),
                description: _t(
                    "There was an error updating the room's main address. It may not be allowed by the server " +
                    "or a temporary failure occurred.",
                ),
            });
        }).finally(() => {
            this.setState({updatingCanonicalAlias: false});
        });
    }

    onNewAliasChanged = (value) => {
        this.setState({newAlias: value});
    };

    onLocalAliasAdded = (alias) => {
        if (!alias || alias.length === 0) return; // ignore attempts to create blank aliases

        const localDomain = MatrixClientPeg.get().getDomain();
        if (!alias.includes(':')) alias += ':' + localDomain;
        if (this.isAliasValid(alias) && alias.endsWith(localDomain)) {
            MatrixClientPeg.get().createAlias(alias, this.props.roomId).then(() => {
                const localAliases = this.state.domainToAliases[localDomain] || [];
                const domainAliases = Object.assign({}, this.state.domainToAliases);
                domainAliases[localDomain] = [...localAliases, alias];

                this.setState({
                    domainToAliases: domainAliases,
                    // Reset the add field
                    newAlias: "",
                });

                if (!this.state.canonicalAlias) {
                    this.changeCanonicalAlias(alias);
                }
            }).catch((err) => {
                console.error(err);
                Modal.createTrackedDialog('Error creating alias', '', ErrorDialog, {
                    title: _t("Error creating alias"),
                    description: _t(
                        "There was an error creating that alias. It may not be allowed by the server " +
                        "or a temporary failure occurred.",
                    ),
                });
            });
        } else {
            const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
            Modal.createTrackedDialog('Invalid alias format', '', ErrorDialog, {
                title: _t('Invalid alias format'),
                description: _t('\'%(alias)s\' is not a valid format for an alias', { alias: alias }),
            });
        }
    };

    onLocalAliasDeleted = (index) => {
        const localDomain = MatrixClientPeg.get().getDomain();

        const alias = this.state.domainToAliases[localDomain][index];

        // TODO: In future, we should probably be making sure that the alias actually belongs
        // to this room. See https://github.com/vector-im/riot-web/issues/7353
        MatrixClientPeg.get().deleteAlias(alias).then(() => {
            const localAliases = this.state.domainToAliases[localDomain].filter((a) => a !== alias);
            const domainAliases = Object.assign({}, this.state.domainToAliases);
            domainAliases[localDomain] = localAliases;

            this.setState({domainToAliases: domainAliases});

            if (this.state.canonicalAlias === alias) {
                this.changeCanonicalAlias(null);
            }
        }).catch((err) => {
            console.error(err);
            Modal.createTrackedDialog('Error removing alias', '', ErrorDialog, {
                title: _t("Error removing alias"),
                description: _t(
                    "There was an error removing that alias. It may no longer exist or a temporary " +
                    "error occurred.",
                ),
            });
        });
    };

    onCanonicalAliasChange = (event) => {
        this.changeCanonicalAlias(event.target.value);
    };

    render() {
        const EditableItemList = sdk.getComponent("elements.EditableItemList");
        const localDomain = MatrixClientPeg.get().getDomain();

        let found = false;
        const canonicalValue = this.state.canonicalAlias || "";
        const canonicalAliasSection = (
            <Field onChange={this.onCanonicalAliasChange} value={canonicalValue}
                   disabled={this.state.updatingCanonicalAlias || !this.props.canSetCanonicalAlias}
                   element='select' id='canonicalAlias' label={_t('Main address')}>
                <option value="" key="unset">{ _t('not specified') }</option>
                {
                    Object.keys(this.state.domainToAliases).map((domain, i) => {
                        return this.state.domainToAliases[domain].map((alias, j) => {
                            if (alias === this.state.canonicalAlias) found = true;
                            return (
                                <option value={alias} key={i + "_" + j}>
                                    { alias }
                                </option>
                            );
                        });
                    })
                }
                {
                    found || !this.state.canonicalAlias ? '' :
                    <option value={ this.state.canonicalAlias } key='arbitrary'>
                        { this.state.canonicalAlias }
                    </option>
                }
            </Field>
        );

        let remoteAliasesSection;
        if (this.state.remoteDomains.length) {
            remoteAliasesSection = (

                        { _t("Remote addresses for this room:") }

                        { this.state.remoteDomains.map((domain, i) => {
                            return this.state.domainToAliases[domain].map((alias, j) => {
                                return
{alias}
;
                            });
                        }) }

            );
        }

        return (

                {canonicalAliasSection}
                <EditableItemList
                    className={"mx_RoomSettings_localAliases"}
                    items={this.state.domainToAliases[localDomain] || []}
                    newItem={this.state.newAlias}
                    onNewItemChanged={this.onNewAliasChanged}
                    canRemove={this.props.canSetAliases}
                    canEdit={this.props.canSetAliases}
                    onItemAdded={this.onLocalAliasAdded}
                    onItemRemoved={this.onLocalAliasDeleted}
                    itemsLabel={_t('Local addresses for this room:')}
                    noItemsLabel={_t('This room has no local addresses')}
                    placeholder={_t(
                        'New address (e.g. #foo:%(localDomain)s)', {localDomain: localDomain},
                    )}
                />
                {remoteAliasesSection}

        );
    }
};
<commit_msg>More misc linter cleanup<commit_after>/*
Copyright 2016 OpenMarket Ltd
Copyright 2018, 2019 New Vector 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.
*/

const React = require('react');
import PropTypes from 'prop-types';
const MatrixClientPeg = require('../../../MatrixClientPeg');
const sdk = require("../../../index");
import { _t } from '../../../languageHandler';
import Field from "../elements/Field";
import ErrorDialog from "../dialogs/ErrorDialog";
const Modal = require("../../../Modal");

export default class AliasSettings extends React.Component {
    static propTypes = {
        roomId: PropTypes.string.isRequired,
        canSetCanonicalAlias: PropTypes.bool.isRequired,
        canSetAliases: PropTypes.bool.isRequired,
        aliasEvents: PropTypes.array, // [MatrixEvent]
        canonicalAliasEvent: PropTypes.object, // MatrixEvent
    };

    static defaultProps = {
        canSetAliases: false,
        canSetCanonicalAlias: false,
        aliasEvents: [],
    };

    constructor(props) {
        super(props);

        const state = {
            domainToAliases: {}, // { domain.com => [#alias1:domain.com, #alias2:domain.com] }
            remoteDomains: [], // [ domain.com, foobar.com ]
            canonicalAlias: null, // #canonical:domain.com
            updatingCanonicalAlias: false,
            newItem: "",
        };

        const localDomain = MatrixClientPeg.get().getDomain();
        state.domainToAliases = this.aliasEventsToDictionary(props.aliasEvents || []);
        state.remoteDomains = Object.keys(state.domainToAliases).filter((domain) => {
            return domain !== localDomain && state.domainToAliases[domain].length > 0;
        });

        if (props.canonicalAliasEvent) {
            state.canonicalAlias = props.canonicalAliasEvent.getContent().alias;
        }

        this.state = state;
    }

    aliasEventsToDictionary(aliasEvents) { // m.room.alias events
        const dict = {};
        aliasEvents.forEach((event) => {
            dict[event.getStateKey()] = (
                (event.getContent().aliases || []).slice() // shallow-copy
            );
        });
        return dict;
    }

    isAliasValid(alias) {
        // XXX: FIXME https://github.com/matrix-org/matrix-doc/issues/668
        return (alias.match(/^#([^/:,]+?):(.+)$/) && encodeURI(alias) === alias);
    }

    changeCanonicalAlias(alias) {
        if (!this.props.canSetCanonicalAlias) return;

        this.setState({
            canonicalAlias: alias,
            updatingCanonicalAlias: true,
        });

        const eventContent = {};
        if (alias) eventContent["alias"] = alias;

        MatrixClientPeg.get().sendStateEvent(this.props.roomId, "m.room.canonical_alias",
            eventContent, "").catch((err) => {
            console.error(err);
            Modal.createTrackedDialog('Error updating main address', '', ErrorDialog, {
                title: _t("Error updating main address"),
                description: _t(
                    "There was an error updating the room's main address. It may not be allowed by the server " +
                    "or a temporary failure occurred.",
                ),
            });
        }).finally(() => {
            this.setState({updatingCanonicalAlias: false});
        });
    }

    onNewAliasChanged = (value) => {
        this.setState({newAlias: value});
    };

    onLocalAliasAdded = (alias) => {
        if (!alias || alias.length === 0) return; // ignore attempts to create blank aliases

        const localDomain = MatrixClientPeg.get().getDomain();
        if (!alias.includes(':')) alias += ':' + localDomain;
        if (this.isAliasValid(alias) && alias.endsWith(localDomain)) {
            MatrixClientPeg.get().createAlias(alias, this.props.roomId).then(() => {
                const localAliases = this.state.domainToAliases[localDomain] || [];
                const domainAliases = Object.assign({}, this.state.domainToAliases);
                domainAliases[localDomain] = [...localAliases, alias];

                this.setState({
                    domainToAliases: domainAliases,
                    // Reset the add field
                    newAlias: "",
                });

                if (!this.state.canonicalAlias) {
                    this.changeCanonicalAlias(alias);
                }
            }).catch((err) => {
                console.error(err);
                Modal.createTrackedDialog('Error creating alias', '', ErrorDialog, {
                    title: _t("Error creating alias"),
                    description: _t(
                        "There was an error creating that alias. It may not be allowed by the server " +
                        "or a temporary failure occurred.",
                    ),
                });
            });
        } else {
            const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
            Modal.createTrackedDialog('Invalid alias format', '', ErrorDialog, {
                title: _t('Invalid alias format'),
                description: _t('\'%(alias)s\' is not a valid format for an alias', { alias: alias }),
            });
        }
    };

    onLocalAliasDeleted = (index) => {
        const localDomain = MatrixClientPeg.get().getDomain();

        const alias = this.state.domainToAliases[localDomain][index];

        // TODO: In future, we should probably be making sure that the alias actually belongs
        // to this room. See https://github.com/vector-im/riot-web/issues/7353
        MatrixClientPeg.get().deleteAlias(alias).then(() => {
            const localAliases = this.state.domainToAliases[localDomain].filter((a) => a !== alias);
            const domainAliases = Object.assign({}, this.state.domainToAliases);
            domainAliases[localDomain] = localAliases;

            this.setState({domainToAliases: domainAliases});

            if (this.state.canonicalAlias === alias) {
                this.changeCanonicalAlias(null);
            }
        }).catch((err) => {
            console.error(err);
            Modal.createTrackedDialog('Error removing alias', '', ErrorDialog, {
                title: _t("Error removing alias"),
                description: _t(
                    "There was an error removing that alias. It may no longer exist or a temporary " +
                    "error occurred.",
                ),
            });
        });
    };

    onCanonicalAliasChange = (event) => {
        this.changeCanonicalAlias(event.target.value);
    };

    render() {
        const EditableItemList = sdk.getComponent("elements.EditableItemList");
        const localDomain = MatrixClientPeg.get().getDomain();

        let found = false;
        const canonicalValue = this.state.canonicalAlias || "";
        const canonicalAliasSection = (
            <Field onChange={this.onCanonicalAliasChange} value={canonicalValue}
                   disabled={this.state.updatingCanonicalAlias || !this.props.canSetCanonicalAlias}
                   element='select' id='canonicalAlias' label={_t('Main address')}>
                <option value="" key="unset">{ _t('not specified') }</option>
                {
                    Object.keys(this.state.domainToAliases).map((domain, i) => {
                        return this.state.domainToAliases[domain].map((alias, j) => {
                            if (alias === this.state.canonicalAlias) found = true;
                            return (
                                <option value={alias} key={i + "_" + j}>
                                    { alias }
                                </option>
                            );
                        });
                    })
                }
                {
                    found || !this.state.canonicalAlias ? '' :
                    <option value={ this.state.canonicalAlias } key='arbitrary'>
                        { this.state.canonicalAlias }
                    </option>
                }
            </Field>
        );

        let remoteAliasesSection;
        if (this.state.remoteDomains.length) {
            remoteAliasesSection = (

                        { _t("Remote addresses for this room:") }

                        { this.state.remoteDomains.map((domain, i) => {
                            return this.state.domainToAliases[domain].map((alias, j) => {
                                return
{alias}
;
                            });
                        }) }

            );
        }

        return (

                {canonicalAliasSection}
                <EditableItemList
                    className={"mx_RoomSettings_localAliases"}
                    items={this.state.domainToAliases[localDomain] || []}
                    newItem={this.state.newAlias}
                    onNewItemChanged={this.onNewAliasChanged}
                    canRemove={this.props.canSetAliases}
                    canEdit={this.props.canSetAliases}
                    onItemAdded={this.onLocalAliasAdded}
                    onItemRemoved={this.onLocalAliasDeleted}
                    itemsLabel={_t('Local addresses for this room:')}
                    noItemsLabel={_t('This room has no local addresses')}
                    placeholder={_t(
                        'New address (e.g. #foo:%(localDomain)s)', {localDomain: localDomain},
                    )}
                />
                {remoteAliasesSection}

        );
    }
}
<|endoftext|>


<commit_before>export const canvasBody = `
  id
  layout
  slug
  thumbnail_title
  thumbnail_image
  published_at
  contributing_authors {
    name
  }
  authors {
    name
  }
`

export const relatedArticles = `
  relatedArticlesPanel {
    id
    layout
    slug
    thumbnail_title
    thumbnail_image
  }
  relatedArticlesCanvas {
    ${canvasBody}
  }
  relatedArticles {
    description
    layout
    thumbnail_title
    thumbnail_image
    title
    slug
    published_at
    media {
      duration
      published
      release_date
    }
  }
`

export const relatedArticlesNews = (offset, limit) => {
  return `
    articles(published: true, in_editorial_feed: true, limit: 4, offset: ${offset}, sort: "-published_at"){
      ${canvasBody}
    }
  `
}
<commit_msg>add authors to relatedArticles query<commit_after>export const canvasBody = `
  id
  layout
  slug
  thumbnail_title
  thumbnail_image
  published_at
  contributing_authors {
    name
  }
  authors {
    name
  }
`

export const relatedArticles = `
  relatedArticlesPanel {
    id
    layout
    slug
    thumbnail_title
    thumbnail_image
  }
  relatedArticlesCanvas {
    ${canvasBody}
  }
  relatedArticles {
    authors {
      name
    }
    description
    layout
    thumbnail_title
    thumbnail_image
    title
    slug
    published_at
    media {
      duration
      published
      release_date
    }
  }
`

export const relatedArticlesNews = (offset, limit) => {
  return `
    articles(published: true, in_editorial_feed: true, limit: 4, offset: ${offset}, sort: "-published_at"){
      ${canvasBody}
    }
  `
}
<|endoftext|>


<commit_before>define(['app'], function(app) {

    app.directive('blockRegion', ['$compile', function($compile) {
        return {
            restrict: 'EA',
            replace: true,
            scope: {
                activate : '=',
                dynamicText: '=?'
            },
            link: function($scope, $element, attrs) {

                function buildBlockText(){
                    var blockText = 'Loading...';
                    if($scope.dynamicText)
                        blockText = $scope.dynamicText;
                    else if(attrs.blockText)
                        blockText = attrs.blockText;

                    blockText = '' + blockText + '';
                    if(!attrs.skipLoadingIcon){
                        blockText = '' + blockText;
                    }

                    $element.addClass('blockRegion');
                    var loadtHtml = '

'+ blockText + '

';

                    $element.empty();//.remove('.inverted.dimmer');
                    $element.append($compile(loadtHtml)($scope));
                }

                $scope.$watch('activate', function(newVal){
                    if(newVal){
                        $element.addClass('blockRegion');
                        if(attrs.updateParentPosition)
                            $element.parent().addClass('blockRegion-parent-position')
                    }
                    else{
                        $element.removeClass('blockRegion');
                        if(attrs.updateParentPosition)
                            $element.parent().removeClass('blockRegion-parent-position')
                    }
                });
                $scope.$watch('dynamicText', function(newVal){
                    buildBlockText();
                });

                $scope.$on('$destroy', function(){
                    if(attrs.updateParentPosition)
                        $element.parent().removeClass('blockRegion-parent-position')
                })

                buildBlockText();
            }
        }
    }]);

});
<commit_msg>fix block-region directive issue<commit_after>define(['app'], function(app) {

    app.directive('blockRegion', ['$compile', function($compile) {
        return {
            restrict: 'EA',
            replace: true,
            scope: {
                activate : '=',
                dynamicText: '=?'
            },
            link: function($scope, $element, attrs) {

                function buildBlockText(){
                    var blockText = 'Loading...';
                    if($scope.dynamicText)
                        blockText = $scope.dynamicText;
                    else if(attrs.blockText)
                        blockText = attrs.blockText;

                    blockText = '' + blockText + '';
                    if(!attrs.skipLoadingIcon){
                        blockText = '' + blockText;
                    }

                    $element.addClass('blockRegion');
                    var loadtHtml = '

'+ blockText + '

';

                    $element.find('.inverted.dimmer').remove();
                    $element.append($compile(loadtHtml)($scope));
                }

                $scope.$watch('activate', function(newVal){
                    if(newVal){
                        $element.addClass('blockRegion');
                        if(attrs.updateParentPosition)
                            $element.parent().addClass('blockRegion-parent-position')
                    }
                    else{
                        $element.removeClass('blockRegion');
                        if(attrs.updateParentPosition)
                            $element.parent().removeClass('blockRegion-parent-position')
                    }
                });
                $scope.$watch('dynamicText', function(newVal){
                    buildBlockText();
                });

                $scope.$on('$destroy', function(){
                    if(attrs.updateParentPosition)
                        $element.parent().removeClass('blockRegion-parent-position')
                })

                buildBlockText();
            }
        }
    }]);

});
<|endoftext|>


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

    Game.ObjectiveManager.Objective = function(game, objectiveManager, trigger, tilemap, object, player, dependencies) {
        Phaser.Group.call(this, game, objectiveManager, object.name);
        this.alpha = 0;

        /**
         * Game instance
         * @type {Phaser.Game}
         */
        this.game = game;

        /**
         * The player who are to complete the objective
         * @type {Phaser.Sprite}
         */
        this.player = player;

        /**
         * Instance of objectiveManager
         * @type {Game.ObjectiveManager.Objective}
         */
        this.objectiveManager = objectiveManager;

        /**
         * The object that this objective belongs to in the tilemap
         * @type {Object}
         */
        this.object = object;

        /**
         * The objects properties from the tilemap
         * @type {Object}
         */
        this.properties = this.object.properties;

        /**
         * The tilemap of which this objectives objective layer belongs to
         * @type {Phaser.Tilemap}
         */
        this.tilemap = tilemap;

        /**
         * Name of the objective
         * @type {String}
         */
        this.name = this.object.name;

        /**
         * Is the objective completed or not
         * @type {Boolean}
         */
        this.completed = false;

        /**
         * List of objective name in strings that has to be completed before this objective can be activated
         * @type {Array#String}
         */
        this.dependencies = dependencies;

        /**
         * The trigger that will trigger this objective
         * @type {Game.Trigger}
         */
        this.trigger = trigger;
        this.trigger.onActive.add(this.activate, this);
        this.trigger.onInactive.add(this.inactivate, this);

        /**
         * Whether or not to remove objective on inactive
         * @type {Boolean}
         */
        this.removeOnInactive = false;

        /**
         * Signal that fires upon completion of objective
         * @type {Phaser.Signal}
         */
        this.onCompletion = new Phaser.Signal();
        this.onCompletion.add(this._onCompletionHandler, this);

        /**
         * Signal that fires upon failure of objective
         * @type {Phaser.Signal}
         */
        this.onFailure = new Phaser.Signal();
        this.onFailure.add(this._onFailureHandler, this);

        /**
         * An object containing style information for _titleText
         * @type {Object}
         */
        this._titleTextStyle = {
            font: '17pt serif'
        };

        /**
         * The Phaser.Text instance of the title
         * @type {Phaser.Text}
         */
        // this._titleText = this.game.add.text(0, 0, this.name, this._titleTextStyle);
        this._titleText = this.game.add.bitmapText(0, 0, 'font', this.name, 28);
        this._titleText.tint = 0x010101;
        this.add(this._titleText);

        this._statusTextStyle = {
            font: '14pt serif'
        };

        /**
         * An internal list of trigger functions to call on completion
         * @type {Array#String}
         */
        this._onComplete = (this.properties['onComplete'] || '').split(',');

        /**
         * The status template to be used for this objective. Formatting is to be implemented by children inheriting the Game.ObjectiveManager.Objective class
         * @type {String}
         */
        this._statusTemplate = (this.object.properties.status || this.name).replace('\\n', '\n');

        /**
         * The Phaser.Text instance of the status
         * @type {Phaser.Text}
         */
        // this._statusText = this.game.add.text(0, 0, this._statusTemplate, this._statusTextStyle);
        this._statusText = this.game.add.bitmapText(20, 0, 'font', this._statusTemplate, 23);
        this._statusText.tint = 0x010101;
        this._statusText.y = this._titleText.height;
        this.add(this._statusText);
    };

    Game.ObjectiveManager.Objective.prototype = Object.create(Phaser.Group.prototype);
    Game.ObjectiveManager.Objective.prototype.constructor = Game.ObjectiveManager.Objective;

    Game.ObjectiveManager.Objective.prototype.update = function() {
        Phaser.Group.prototype.update.call(this);
    };

    Game.ObjectiveManager.Objective.prototype.updateStatusText = function() {
    };

    Game.ObjectiveManager.Objective.prototype.activate = function() {
        if (!this.isActive && !this.completed && this.objectiveManager.isCompleted(this.dependencies)) {
            this.objectiveManager.addObjective(this);
        }
    };

    Game.ObjectiveManager.Objective.prototype.inactivate = function() {
        if (this.removeOnInactive && this.isActive) {
            this.objectiveManager._removeObjective(this);
        }
    };

    Object.defineProperty(Game.ObjectiveManager.Objective.prototype, 'statusTemplate', {

        get: function() {
            return this._statusTemplate;
        },

        set: function(value) {
            this._statusTemplate = value;
            this.updateStatusText();
        }

    });

    Game.ObjectiveManager.Objective.prototype._onCompletionHandler = function() {
        this.completed = true;
        this._statusTextStyle.fill = '#01C611';
        this._statusText.setStyle(this._statusTextStyle);
        this.objectiveManager.onObjectiveComplete.dispatch(this);
        this._callOnCompletionTriggers();
    };

    Game.ObjectiveManager.Objective.prototype._callOnCompletionTriggers = function() {
        var state = this.game.state.getCurrentState();
        var triggerFunctions = state.triggerFunctions;
        var key;

        for (var i = 0; i < this._onComplete.length; i++) {
            key = this._onComplete[i];
            if (triggerFunctions[key]) {
                triggerFunctions[key].call(state);
            }
        }

    };

    Game.ObjectiveManager.Objective.prototype._onFailureHandler = function() {
        this._statusTextStyle.fill = '#ff0000';
        this._statusText.setStyle(this._statusTextStyle);
    };

    Game.ObjectiveManager.Objective.prototype.toString = function() {
        return this.name;
    };

    Object.defineProperty(Game.ObjectiveManager.Objective.prototype, 'statusText', {

        get: function() {
            if (this._statusText) {
                return this._statusText.text;
            }
            return this.name + ' status';
        },

        set: function(value) {
            this._statusText.text = value.replace('\\n', '\n');
        }

    });

    Object.defineProperty(Game.ObjectiveManager.Objective.prototype, 'isActive', {

        get: function() {
            return this.objectiveManager.isActive(this);
        }

    });

})();
<commit_msg>OnComplete on objective now sends arguments from the tilemap<commit_after>(function() {
    'use strict';

    Game.ObjectiveManager.Objective = function(game, objectiveManager, trigger, tilemap, object, player, dependencies) {
        Phaser.Group.call(this, game, objectiveManager, object.name);
        this.alpha = 0;

        /**
         * Game instance
         * @type {Phaser.Game}
         */
        this.game = game;

        /**
         * The player who are to complete the objective
         * @type {Phaser.Sprite}
         */
        this.player = player;

        /**
         * Instance of objectiveManager
         * @type {Game.ObjectiveManager.Objective}
         */
        this.objectiveManager = objectiveManager;

        /**
         * The object that this objective belongs to in the tilemap
         * @type {Object}
         */
        this.object = object;

        /**
         * The objects properties from the tilemap
         * @type {Object}
         */
        this.properties = this.object.properties;

        /**
         * The tilemap of which this objectives objective layer belongs to
         * @type {Phaser.Tilemap}
         */
        this.tilemap = tilemap;

        /**
         * Name of the objective
         * @type {String}
         */
        this.name = this.object.name;

        /**
         * Is the objective completed or not
         * @type {Boolean}
         */
        this.completed = false;

        /**
         * List of objective name in strings that has to be completed before this objective can be activated
         * @type {Array#String}
         */
        this.dependencies = dependencies;

        /**
         * The trigger that will trigger this objective
         * @type {Game.Trigger}
         */
        this.trigger = trigger;
        this.trigger.onActive.add(this.activate, this);
        this.trigger.onInactive.add(this.inactivate, this);

        /**
         * Whether or not to remove objective on inactive
         * @type {Boolean}
         */
        this.removeOnInactive = false;

        /**
         * Signal that fires upon completion of objective
         * @type {Phaser.Signal}
         */
        this.onCompletion = new Phaser.Signal();
        this.onCompletion.add(this._onCompletionHandler, this);

        /**
         * An array containing arguments to call onComplete functions with
         * @type {[type]}
         */
        this.onCompleteArgs = this.properties['onCompleteArgs'] ? this.properties['onCompleteArgs'].split(',') : [];
        // Trigger functions expect the object to be argument number one
        this.onCompleteArgs.splice(0, 0, this.object);

        /**
         * Signal that fires upon failure of objective
         * @type {Phaser.Signal}
         */
        this.onFailure = new Phaser.Signal();
        this.onFailure.add(this._onFailureHandler, this);

        /**
         * An object containing style information for _titleText
         * @type {Object}
         */
        this._titleTextStyle = {
            font: '17pt serif'
        };

        /**
         * The Phaser.Text instance of the title
         * @type {Phaser.Text}
         */
        // this._titleText = this.game.add.text(0, 0, this.name, this._titleTextStyle);
        this._titleText = this.game.add.bitmapText(0, 0, 'font', this.name, 28);
        this._titleText.tint = 0x010101;
        this.add(this._titleText);

        this._statusTextStyle = {
            font: '14pt serif'
        };

        /**
         * An internal list of trigger functions to call on completion
         * @type {Array#String}
         */
        this._onComplete = (this.properties['onComplete'] || '').split(',');

        /**
         * The status template to be used for this objective. Formatting is to be implemented by children inheriting the Game.ObjectiveManager.Objective class
         * @type {String}
         */
        this._statusTemplate = (this.object.properties.status || this.name).replace('\\n', '\n');

        /**
         * The Phaser.Text instance of the status
         * @type {Phaser.Text}
         */
        // this._statusText = this.game.add.text(0, 0, this._statusTemplate, this._statusTextStyle);
        this._statusText = this.game.add.bitmapText(20, 0, 'font', this._statusTemplate, 23);
        this._statusText.tint = 0x010101;
        this._statusText.y = this._titleText.height;
        this.add(this._statusText);
    };

    Game.ObjectiveManager.Objective.prototype = Object.create(Phaser.Group.prototype);
    Game.ObjectiveManager.Objective.prototype.constructor = Game.ObjectiveManager.Objective;

    Game.ObjectiveManager.Objective.prototype.update = function() {
        Phaser.Group.prototype.update.call(this);
    };

    Game.ObjectiveManager.Objective.prototype.updateStatusText = function() {
    };

    Game.ObjectiveManager.Objective.prototype.activate = function() {
        if (!this.isActive && !this.completed && this.objectiveManager.isCompleted(this.dependencies)) {
            this.objectiveManager.addObjective(this);
        }
    };

    Game.ObjectiveManager.Objective.prototype.inactivate = function() {
        if (this.removeOnInactive && this.isActive) {
            this.objectiveManager._removeObjective(this);
        }
    };

    Object.defineProperty(Game.ObjectiveManager.Objective.prototype, 'statusTemplate', {

        get: function() {
            return this._statusTemplate;
        },

        set: function(value) {
            this._statusTemplate = value;
            this.updateStatusText();
        }

    });

    Game.ObjectiveManager.Objective.prototype._onCompletionHandler = function() {
        this.completed = true;
        this._statusTextStyle.fill = '#01C611';
        this._statusText.setStyle(this._statusTextStyle);
        this.objectiveManager.onObjectiveComplete.dispatch(this);
        this._callOnCompletionTriggers();
    };

    Game.ObjectiveManager.Objective.prototype._callOnCompletionTriggers = function() {
        var state = this.game.state.getCurrentState();
        var triggerFunctions = state.triggerFunctions;
        var key;

        for (var i = 0; i < this._onComplete.length; i++) {
            key = this._onComplete[i];
            if (triggerFunctions[key]) {
                console.log(triggerFunctions[key]);
                triggerFunctions[key].apply(state, this.onCompleteArgs);
            }
        }

    };

    Game.ObjectiveManager.Objective.prototype._onFailureHandler = function() {
        this._statusTextStyle.fill = '#ff0000';
        this._statusText.setStyle(this._statusTextStyle);
    };

    Game.ObjectiveManager.Objective.prototype.toString = function() {
        return this.name;
    };

    Object.defineProperty(Game.ObjectiveManager.Objective.prototype, 'statusText', {

        get: function() {
            if (this._statusText) {
                return this._statusText.text;
            }
            return this.name + ' status';
        },

        set: function(value) {
            this._statusText.text = value.replace('\\n', '\n');
        }

    });

    Object.defineProperty(Game.ObjectiveManager.Objective.prototype, 'isActive', {

        get: function() {
            return this.objectiveManager.isActive(this);
        }

    });

})();
<|endoftext|>


<commit_before>app.directive('expenseItemForm', ['moment', '$filter', '$timeout', '$translate', 'spinnerService', 'globalMessagesService', 'expenseItemsRestService',

function(moment, $filter, $timeout, $translate, spinnerService, globalMessagesService, expenseItemsRestService) {
	"use strict";

	return {
		restrict: 'E',
		replace: true,
		templateUrl: 'expense-items/expense-item-form.directive.tpl.html',
		scope: {
			expenseItemUid: '=',
			form: '=',
			validatingFunction: '='
		},
		link: function($scope) {

			var expenseItem = {};
			$scope.calculatedAmount = $filter('number')(0, 2);

			$timeout(function(){
				spinnerService.show('spinnerExpenseItemForm');
			});

			var invalidDate = "";
			var invalidAmount = "";

			$translate(['reimbursement.add-expense-item.invalidDate', 'reimbursement.add-expense-item.invalidAmount']).then(function(translations) {
				invalidDate = translations['reimbursement.add-expense-item.invalidDate'];
				invalidAmount = translations['reimbursement.add-expense-item.invalidAmount'];
			}, function() {
				globalMessagesService.showGeneralError();
			});

			expenseItemsRestService.getCostCategories().then(function(response) {
				$scope.costCategories =  response.data;

				expenseItemsRestService.getSupportedCurrencies().then(function(response) {
					$scope.currencies = response.data;

					expenseItemsRestService.getExpenseItem($scope.expenseItemUid).then(function(response) {
						expenseItem = response.data;

						$scope.form.date = $filter('date')(response.data.date, 'yyyy-MM-dd');
						$scope.form.costCategoryUid = response.data.costCategory.uid;
						$scope.form.originalAmount = response.data.originalAmount;
						$scope.form.currency = response.data.currency;
						$scope.form.project = response.data.project;
						$scope.form.explanation = response.data.explanation;

						spinnerService.hide('spinnerExpenseItemForm');

					}, function() {
						globalMessagesService.showGeneralError();
						spinnerService.hide('spinnerExpenseItemForm');
					});
				}, function() {
					globalMessagesService.showGeneralError();
					spinnerService.hide('spinnerExpenseItemForm');
				});
			}, function() {
				globalMessagesService.showGeneralError();
				spinnerService.hide('spinnerExpenseItemForm');
			});

			var exchangeRates = null;
			var exchangeRateDate = null;
			$scope.calculateAmount = function() {

				function calculate() {
					var exchangeRate = exchangeRates.rates[$scope.form.currency];
					if(isNaN(window.parseFloat($scope.form.originalAmount)) || window.parseFloat($scope.form.originalAmount) < 0) {
						$scope.calculatedAmount = invalidAmount;
					}
					else {
						if(typeof exchangeRate !== "undefined") {
							$scope.calculatedAmount = $filter('number')(window.parseFloat($scope.form.originalAmount) / exchangeRate, 2);
						}
						else {
							$scope.calculatedAmount = $filter('number')(window.parseFloat($scope.form.originalAmount), 2);
						}
					}
				}

				if($scope.form.date !== "") {
					// only make back-end calls if necessary
					if(exchangeRateDate !== $scope.form.date) {
						expenseItemsRestService.getExchangeRates($scope.form.date).then(function(response) {
							exchangeRates = response.data;
							exchangeRateDate = $scope.form.date;
							calculate();
						}, function() {
							$scope.calculatedAmount = invalidDate;
						});
					}
					else {
						calculate();
					}
				}
				else {
					$scope.calculatedAmount = $filter('number')(0, 2);
				}
			};

			$scope.validatingFunction = function(form) {
				if(typeof form.date === "undefined" || form.date === null || !moment(form.date, 'yyyy-MM-dd').isValid()) {
					return false;
				}
				if(typeof form.costCategoryUid === "undefined" || form.costCategoryUid === null || form.costCategoryUid === "") {
					return false;
				}
				if(typeof form.originalAmount === "undefined" || form.originalAmount === null || !jQuery.isNumeric(form.originalAmount) || parseFloat(form.originalAmount) <= 0) {
					return false;
				}
				if(typeof form.currency === "undefined" || form.currency === null || form.currency === "") {
					return false;
				}
				if(typeof form.project === "undefined" || form.project === null || form.project === "") {
					return false;
				}
				if(typeof form.explanation === "undefined" || form.explanation === null || form.explanation === "") {
					return false;
				}
				return true;
			};

			$timeout(function() {
				jQuery('.datepicker').datetimepicker({
					format: 'YYYY-MM-DD',
					viewMode: 'months',
					allowInputToggle: true,
					maxDate: moment(),
					calendarWeeks: true
				}).on('dp.change', function() {
					$scope.form.date = jQuery('.datepicker').find('input').first().val();
					$scope.calculateAmount();
				});
			});
		}
	};

}]);
<commit_msg>fix racing condition<commit_after>app.directive('expenseItemForm', ['moment', '$filter', '$timeout', '$translate', 'spinnerService', 'globalMessagesService', 'expenseItemsRestService',

function(moment, $filter, $timeout, $translate, spinnerService, globalMessagesService, expenseItemsRestService) {
	"use strict";

	return {
		restrict: 'E',
		replace: true,
		templateUrl: 'expense-items/expense-item-form.directive.tpl.html',
		scope: {
			expenseItemUid: '=',
			form: '=',
			validatingFunction: '='
		},
		link: function($scope) {

			var expenseItem = {};
			$scope.calculatedAmount = $filter('number')(0, 2);

			$timeout(function(){
				spinnerService.show('spinnerExpenseItemForm');
			});

			var invalidDate = "";
			var invalidAmount = "";

			$translate(['reimbursement.add-expense-item.invalidDate', 'reimbursement.add-expense-item.invalidAmount']).then(function(translations) {
				invalidDate = translations['reimbursement.add-expense-item.invalidDate'];
				invalidAmount = translations['reimbursement.add-expense-item.invalidAmount'];
			}, function() {
				globalMessagesService.showGeneralError();
			});

			expenseItemsRestService.getCostCategories().then(function(response) {
				$scope.costCategories =  response.data;

				expenseItemsRestService.getSupportedCurrencies().then(function(response) {
					$scope.currencies = response.data;

					expenseItemsRestService.getExpenseItem($scope.expenseItemUid).then(function(response) {
						expenseItem = response.data;

						$scope.form.date = $filter('date')(response.data.date, 'yyyy-MM-dd');
						$scope.form.costCategoryUid = response.data.costCategory.uid;
						$scope.form.originalAmount = response.data.originalAmount;
						$scope.form.project = response.data.project;
						$scope.form.explanation = response.data.explanation;
						$timeout(function() {
							// make sure the currencies are completely loaded before setting the default
							$scope.form.currency = response.data.currency;
						});

						spinnerService.hide('spinnerExpenseItemForm');

					}, function() {
						globalMessagesService.showGeneralError();
						spinnerService.hide('spinnerExpenseItemForm');
					});
				}, function() {
					globalMessagesService.showGeneralError();
					spinnerService.hide('spinnerExpenseItemForm');
				});
			}, function() {
				globalMessagesService.showGeneralError();
				spinnerService.hide('spinnerExpenseItemForm');
			});

			var exchangeRates = null;
			var exchangeRateDate = null;
			$scope.calculateAmount = function() {

				function calculate() {
					var exchangeRate = exchangeRates.rates[$scope.form.currency];
					if(isNaN(window.parseFloat($scope.form.originalAmount)) || window.parseFloat($scope.form.originalAmount) < 0) {
						$scope.calculatedAmount = invalidAmount;
					}
					else {
						if(typeof exchangeRate !== "undefined") {
							$scope.calculatedAmount = $filter('number')(window.parseFloat($scope.form.originalAmount) / exchangeRate, 2);
						}
						else {
							$scope.calculatedAmount = $filter('number')(window.parseFloat($scope.form.originalAmount), 2);
						}
					}
				}

				if($scope.form.date !== "") {
					// only make back-end calls if necessary
					if(exchangeRateDate !== $scope.form.date) {
						expenseItemsRestService.getExchangeRates($scope.form.date).then(function(response) {
							exchangeRates = response.data;
							exchangeRateDate = $scope.form.date;
							calculate();
						}, function() {
							$scope.calculatedAmount = invalidDate;
						});
					}
					else {
						calculate();
					}
				}
				else {
					$scope.calculatedAmount = $filter('number')(0, 2);
				}
			};

			$scope.validatingFunction = function(form) {
				if(typeof form.date === "undefined" || form.date === null || !moment(form.date, 'yyyy-MM-dd').isValid()) {
					return false;
				}
				if(typeof form.costCategoryUid === "undefined" || form.costCategoryUid === null || form.costCategoryUid === "") {
					return false;
				}
				if(typeof form.originalAmount === "undefined" || form.originalAmount === null || !jQuery.isNumeric(form.originalAmount) || parseFloat(form.originalAmount) <= 0) {
					return false;
				}
				if(typeof form.currency === "undefined" || form.currency === null || form.currency === "") {
					return false;
				}
				if(typeof form.project === "undefined" || form.project === null || form.project === "") {
					return false;
				}
				if(typeof form.explanation === "undefined" || form.explanation === null || form.explanation === "") {
					return false;
				}
				return true;
			};

			$timeout(function() {
				jQuery('.datepicker').datetimepicker({
					format: 'YYYY-MM-DD',
					viewMode: 'months',
					allowInputToggle: true,
					maxDate: moment(),
					calendarWeeks: true
				}).on('dp.change', function() {
					$scope.form.date = jQuery('.datepicker').find('input').first().val();
					$scope.calculateAmount();
				});
			});
		}
	};

}]);
<|endoftext|>


<commit_before>const DIGIT_REGEX = /^\d+$/
const readableIdPartFromWord = word => DIGIT_REGEX.test(word) ? word : word[0]
function prepareName(rawName) {
  const name = rawName.trim().toLowerCase().replace(/[^\w\d]/g, ' ')
  const firstNonDigit = name.search(/[^\d\s]/)
  if (firstNonDigit === -1) { return '' }
  return name.slice(firstNonDigit).trim().replace(/\s/g, '_')
}

function getDirectVariableNameFromName(rawName, maxOneWordLength, maxSplitWordLength, cutOffLength) {
  const name = prepareName(rawName)

  const words = name.split(/[\_]/).filter(s => !_.isEmpty(s))

  if (words.length === 1 && name.length < maxOneWordLength) {
    return name
  } else if (words.length < maxSplitWordLength) {
    return name.slice(0, cutOffLength)
  } else {
    return words.map(readableIdPartFromWord).join('').slice(0, cutOffLength)
  }
}

export function getVariableNameFromName(
  rawName,
  existingVariableNames=[],
  maxOneWordLength=30,
  maxSplitWordLength=8,
  totalMaxLength=maxSplitWordLength
) {
  const directName = getDirectVariableNameFromName(rawName, maxOneWordLength, maxSplitWordLength, totalMaxLength)

  const nameRegex = new RegExp(`${directName}(?:_(\d+))?`, 'gi')

  const matchingNames = existingVariableNames.filter(v => nameRegex.test(v))
  if (_.isEmpty(matchingNames)) { return directName }

  const currentMaxSuffix = Math.max(...matchingNames.map(v => parseInt(v.match(nameRegex)[1] || '0')))
  return `${directName}${currentMaxSuffix + 1}`
}

export const shouldTransformName = name => !(_.isEmpty(name) || _.isEmpty(name.replace(/[^\w\d]/g, '').trim()))
<commit_msg>Re-making lost changes.<commit_after>const DIGIT_REGEX = /^\d+$/
const readableIdPartFromWord = word => DIGIT_REGEX.test(word) ? word : word[0]
function prepareName(rawName) {
  const name = rawName.trim().toLowerCase().replace(/[^\w\d]/g, ' ')
  const firstNonDigit = name.search(/[^\d\s]/)
  if (firstNonDigit === -1) { return '' }
  return name.slice(firstNonDigit).trim().replace(/\s/g, '_')
}

function getDirectVariableNameFromName(rawName, maxOneWordLength, maxSplitWordLength, cutOffLength) {
  const name = prepareName(rawName)

  const words = name.split(/[\_]/).filter(s => !_.isEmpty(s))

  if (words.length === 1 && name.length < maxOneWordLength) {
    return name
  } else if (words.length < maxSplitWordLength) {
    return name.slice(0, cutOffLength)
  } else {
    return words.map(readableIdPartFromWord).slice(0, cutOffLength).join('')
  }
}

export function getVariableNameFromName(
  rawName,
  existingVariableNames=[],
  maxOneWordLength=30,
  maxSplitWordLength=8,
  totalMaxLength=maxSplitWordLength
) {
  const directName = getDirectVariableNameFromName(rawName, maxOneWordLength, maxSplitWordLength, totalMaxLength)

  const nameRegex = new RegExp(`${directName}(\\d+)?`, 'i')

  const matchingNames = existingVariableNames.filter(v => nameRegex.test(v))
  if (_.isEmpty(matchingNames)) { return directName }

  const currentMaxSuffix = Math.max(...matchingNames.map(v => parseInt(v.match(nameRegex)[1] || '0')))
  return `${directName}${currentMaxSuffix + 1}`
}

export const shouldTransformName = name => !(_.isEmpty(name) || _.isEmpty(name.replace(/[^a-zA-Z]/g, '').trim()))
<|endoftext|>


<commit_before>'use strict';

var util = require('util'),
    TransportStream = require('./');

var LegacyTransportStream = module.exports = function LegacyTransportStream(opts) {
  opts = opts || {};
  opts.objectMode = true;

  TransportStream.call(this, opts);

  var self = this;
  this.transport = opts.transport;
  this.level = opts.transport.level;

  if (typeof opts.transport.log !== 'function') {
    throw new Error('Invalid transport, must be an object with a log method.');
  }

  console.error('%s is a Legacy winston transport. Consider upgrading', opts.transport.name);

  //
  // Properly bubble up errors from the transport to the LegacyTransportStream
  // instance, but only once no matter how many times this transport is shared.
  //
  function transportError(err) {
    self.emit('error', err, self.transport);
  }

  if (!this.transport.__winstonError) {
    this.transport.__winstonError = transportError;
    this.transport.on('error', this.transport.__winstonError);
  }
};

util.inherits(LegacyTransportStream, TransportStream);

/*
 * @private function _write(info)
 * Writes the info object to our transport instance.
 */
LegacyTransportStream.prototype._write = function (info, enc, callback) {
  //
  // Remark: This has to be handled in the base transport now because we cannot
  // conditionally write to our pipe targets as stream.
  //
  if (!this.transport.level || this.levels[transport.level] <= this.levels[info.level]) {
    this.transport.log(info.level, info.message, info, function () {});
  }

  callback();
};

/*
 * Clean up error handling state on the legacy transport associated
 * with this instance.
 */
LegacyTransportStream.prototype.close = function () {
  if (this.transport.close) {
    this.transport.close();
  }

  if (this.transport.__winstonError) {
    this.transport.removeListener('error', this.transport.__winstonError);
  }
};
<commit_msg>[fix] Correct level comparison in both `LegacyTransportStream` as well as `TransportStream`.<commit_after>'use strict';

var util = require('util'),
    TransportStream = require('./');

var LegacyTransportStream = module.exports = function LegacyTransportStream(opts) {
  opts = opts || {};
  opts.objectMode = true;

  TransportStream.call(this, opts);

  var self = this;
  this.transport = opts.transport;
  this.level = opts.transport.level;

  if (typeof opts.transport.log !== 'function') {
    throw new Error('Invalid transport, must be an object with a log method.');
  }

  console.error('%s is a Legacy winston transport. Consider upgrading', opts.transport.name);

  //
  // Properly bubble up errors from the transport to the LegacyTransportStream
  // instance, but only once no matter how many times this transport is shared.
  //
  function transportError(err) {
    self.emit('error', err, self.transport);
  }

  if (!this.transport.__winstonError) {
    this.transport.__winstonError = transportError;
    this.transport.on('error', this.transport.__winstonError);
  }
};

util.inherits(LegacyTransportStream, TransportStream);

/*
 * @private function _write(info)
 * Writes the info object to our transport instance.
 */
LegacyTransportStream.prototype._write = function (info, enc, callback) {
  //
  // Remark: This has to be handled in the base transport now because we cannot
  // conditionally write to our pipe targets as stream.
  //
  if (!this.level || this.levels[this.level] >= this.levels[info.level]) {
    this.transport.log(info.level, info.message, info, function () {});
  }

  callback();
};

/*
 * Clean up error handling state on the legacy transport associated
 * with this instance.
 */
LegacyTransportStream.prototype.close = function () {
  if (this.transport.close) {
    this.transport.close();
  }

  if (this.transport.__winstonError) {
    this.transport.removeListener('error', this.transport.__winstonError);
  }
};
<|endoftext|>


<commit_before>/**
 * Create mappings between the names parsed from useragent to caniuse
 * name equivalents.  We support the caniuse names listed in the
 * `baselineVersion` map below.  This module must return one of these
 * family names, with a version matching the baseline range, for any
 * polyfills to be served.
 *
 * Multiple names may map to the same canonical caniuse family
 */

var useragent = require('useragent');

// Use a local LRU cache rather than the one built into useragent, since that cannot be configured
var cache = require('lru-cache')({
	max: 5000
});

var baseLineVersions = {
	"ie": ">=6",
	"ie_mob": ">=8",
	"chrome": "*",
	"safari": ">=3",
	"ios_saf": ">=3",
	"firefox": ">=3.6",
	"firefox_mob": ">=4",
	"android": ">=2.3",
	"opera": ">=11",
	"op_mob": ">=10",
	"op_mini": ">=5",
	"bb": ">=6"
};

/* Aliases may be expressed in three formats:
    1. <detectedfamily>: <targetfamily>
       The browser family is renamed, version is maintained
    2. <detectedfamily>: [<targetfamily>, <targetmajor>, <targetminor>, <targetpatch>]
       The browser family is renamed and the version is set to the one specified
    3. <detectedfamily>: { <semver>: [<targetfamily>, <targetmajor>, <targetminor>, <targetpatch>], ... }
       Specific version ranges of this family are mapped to the specified browsers
*/
var aliases = {
	"blackberry webkit": "bb",
	"blackberry": "bb",

	"pale moon (firefox variant)": "firefox",
	"firefox mobile": "firefox_mob",
	"firefox namoroka": "firefox",
	"firefox shiretoko": "firefox",
	"firefox minefield": "firefox",
	"firefox alpha": "firefox",
	"firefox beta": "firefox",
	"microb": "firefox",
	"mozilladeveloperpreview": "firefox",
	"iceweasel": "firefox",

	"opera tablet": "opera",

	"opera mobile": "op_mob",
	"opera mini": "op_mini",

	"chrome mobile": "chrome",
	"chrome frame": "chrome",
	"chromium": "chrome",

	"ie mobile": "ie_mob",

	"ie large screen": "ie",
	"internet explorer": "ie",
	"edge": "ie",
	"edge mobile": "ie",

	"chrome mobile ios": "ios_chr",

	"mobile safari": "ios_saf",
	"iphone": "ios_saf",
	"iphone simulator": "ios_saf",

	"phantomjs": ["safari", 5],

	"yandex browser": {
		"14.10": ["chrome", 37],
		"14.8": ["chrome", 36],
		"14.7": ["chrome", 35],
		"14.5": ["chrome", 34],
		"14.4": ["chrome", 33],
		"14.2": ["chrome", 32],
		"13.12": ["chrome", 30],
		"13.10": ["chrome", 28]
	}
};

// Chrome and Opera on iOS uses a UIWebView of the underlying platform to render
// content, by stripping the CriOS or OPiOS strings the useragent parser will alias the
// user agent to ios_saf for the UIWebView, which is closer to the actual
// renderer
function stripiOSWebViewBrowsers(uaString) {
	return uaString.replace(/((CriOS|OPiOS)\/(\d+)\.(\d+)\.(\d+)\.(\d+))/, '');
}

var UA = function(uaString) {
	var semver, a;

	// The longest string that can possibly be a normalized browser name that we
	// support is XXXXXXXXXX/###.###.### (22 chars), so avoid doing the regex if
	// the input string is longer than that
	var normalized = (uaString.length < 22) && uaString.match(/^(\w+)\/(\d+)(?:\.(\d+)(?:\.(\d+))?)?$/i);
	if (!normalized) {
		normalized = cache.get(uaString);
	}
	if (normalized) {
		this.ua = new useragent.Agent(normalized[1], normalized[2], (normalized[3] || 0), (normalized[4] || 0));
	} else {
		this.ua = useragent.parse(stripiOSWebViewBrowsers(uaString));

		// For improved CDN cache performance, remove the patch version.  There are few cases in which a patch release drops the requirement for a polyfill, but if so, the polyfill can simply be served unnecessarily to the patch versions that contain the fix, and we can stop targeting at the next minor release.
		this.ua.patch = '0';

		// Resolve aliases
		this.ua.family = this.ua.family.toLowerCase();
		if (aliases[this.ua.family]) {

			// Map to different family, use same version scheme
			if (typeof aliases[this.ua.family] === 'string') {
				this.ua.family = aliases[this.ua.family];

			// Map to different family with constant version
			} else if (Array.isArray(aliases[this.ua.family]) && aliases[this.ua.family].length >= 2) {
				a = aliases[this.ua.family];
				this.ua = new useragent.Agent(a[0], a[1], (a[2] || 0), (a[3] || 0));

			// Map to different family with per-version mapping
			} else if (typeof aliases[this.ua.family] === 'object') {
				for (semver in aliases[this.ua.family]) {
					if (this.ua.satisfies(semver) && Array.isArray(aliases[this.ua.family][semver])) {
						a = aliases[this.ua.family][semver];
						this.ua = new useragent.Agent(a[0], a[1], (a[2] || 0), (a[3] || 0));
						break;
					}
				}
			}
		}
		cache.set(uaString, ["", this.ua.family, this.ua.major, this.ua.minor, this.ua.patch]);
	}
};

UA.prototype.getFamily = function() {
	return this.ua.family;
};

UA.prototype.getVersion = function() {
	return this.ua.toVersion();
};

UA.prototype.satisfies = function() {
	return (
		this.ua.satisfies.apply(this.ua, arguments) &&
		this.ua.family in baseLineVersions &&
		this.ua.satisfies(baseLineVersions[this.ua.family])
	);
};
UA.prototype.getBaseline = function() {
	return baseLineVersions[this.ua.family];
};
UA.prototype.meetsBaseline = function() {
	return (this.ua.satisfies(baseLineVersions[this.ua.family]));
};
UA.prototype.isUnknown = function() {
	return (Object.keys(baseLineVersions).indexOf(this.ua.family) === -1);
};

UA.normalize = function(uaString) {
	if (uaString.match(/^\w+\/\d+(\.\d+(\.\d+)?)?$/i)) {
		return uaString.toLowerCase();
	}
	var ua = new UA(uaString);
	return ua ? ua.getFamily() + '/' + ua.getVersion() : undefined;
};

UA.getBaselines = function() {
	return baseLineVersions;
};

UA.normalizeName = function(uaName, version) {
	var semver;
	var name = aliases[uaName.toLowerCase()] || uaName.toLowerCase();
	if (typeof name == 'string') return name;
	if (Array.isArray(name)) return name[0];
	if (typeof name === 'object' && version) {
		var ver = version.split('.');
		var ua = new useragent.Agent(uaName, ver[0], (ver[1] || 0), (ver[2] || 0));
		for (semver in name) {
			if (ua.satisfies(semver)) return name[semver][0];
		}
	} else if (typeof name === 'object') {
		return name[Object.keys(name)[0]][0];
	}
};

module.exports = UA;
<commit_msg>Limit effects of long UAs on UA parsing time<commit_after>/**
 * Create mappings between the names parsed from useragent to caniuse
 * name equivalents.  We support the caniuse names listed in the
 * `baselineVersion` map below.  This module must return one of these
 * family names, with a version matching the baseline range, for any
 * polyfills to be served.
 *
 * Multiple names may map to the same canonical caniuse family
 */

var useragent = require('useragent');
var MAX_UA_LEN = 200;

// Use a local LRU cache rather than the one built into useragent, since that cannot be configured
var cache = require('lru-cache')({
	max: 5000
});

var baseLineVersions = {
	"ie": ">=6",
	"ie_mob": ">=8",
	"chrome": "*",
	"safari": ">=3",
	"ios_saf": ">=3",
	"firefox": ">=3.6",
	"firefox_mob": ">=4",
	"android": ">=2.3",
	"opera": ">=11",
	"op_mob": ">=10",
	"op_mini": ">=5",
	"bb": ">=6"
};

/* Aliases may be expressed in three formats:
    1. <detectedfamily>: <targetfamily>
       The browser family is renamed, version is maintained
    2. <detectedfamily>: [<targetfamily>, <targetmajor>, <targetminor>, <targetpatch>]
       The browser family is renamed and the version is set to the one specified
    3. <detectedfamily>: { <semver>: [<targetfamily>, <targetmajor>, <targetminor>, <targetpatch>], ... }
       Specific version ranges of this family are mapped to the specified browsers
*/
var aliases = {
	"blackberry webkit": "bb",
	"blackberry": "bb",

	"pale moon (firefox variant)": "firefox",
	"firefox mobile": "firefox_mob",
	"firefox namoroka": "firefox",
	"firefox shiretoko": "firefox",
	"firefox minefield": "firefox",
	"firefox alpha": "firefox",
	"firefox beta": "firefox",
	"microb": "firefox",
	"mozilladeveloperpreview": "firefox",
	"iceweasel": "firefox",

	"opera tablet": "opera",

	"opera mobile": "op_mob",
	"opera mini": "op_mini",

	"chrome mobile": "chrome",
	"chrome frame": "chrome",
	"chromium": "chrome",

	"ie mobile": "ie_mob",

	"ie large screen": "ie",
	"internet explorer": "ie",
	"edge": "ie",
	"edge mobile": "ie",

	"chrome mobile ios": "ios_chr",

	"mobile safari": "ios_saf",
	"iphone": "ios_saf",
	"iphone simulator": "ios_saf",

	"phantomjs": ["safari", 5],

	"yandex browser": {
		"14.10": ["chrome", 37],
		"14.8": ["chrome", 36],
		"14.7": ["chrome", 35],
		"14.5": ["chrome", 34],
		"14.4": ["chrome", 33],
		"14.2": ["chrome", 32],
		"13.12": ["chrome", 30],
		"13.10": ["chrome", 28]
	}
};

// Chrome and Opera on iOS uses a UIWebView of the underlying platform to render
// content, by stripping the CriOS or OPiOS strings the useragent parser will alias the
// user agent to ios_saf for the UIWebView, which is closer to the actual
// renderer
function stripiOSWebViewBrowsers(uaString) {
	return uaString.replace(/((CriOS|OPiOS)\/(\d+)\.(\d+)\.(\d+)\.(\d+))/, '');
}

var UA = function(uaString) {
	var semver, a;

	// Limit the length of the UA to avoid perf issues in UA parsing
	uaString = uaString.substr(0, MAX_UA_LEN);

	// The longest string that can possibly be a normalized browser name that we
	// support is XXXXXXXXXX/###.###.### (22 chars), so avoid doing the regex if
	// the input string is longer than that
	var normalized = (uaString.length < 22) && uaString.match(/^(\w+)\/(\d+)(?:\.(\d+)(?:\.(\d+))?)?$/i);
	if (!normalized) {
		normalized = cache.get(uaString);
	}
	if (normalized) {
		this.ua = new useragent.Agent(normalized[1], normalized[2], (normalized[3] || 0), (normalized[4] || 0));
	} else {
		this.ua = useragent.parse(stripiOSWebViewBrowsers(uaString));

		// For improved CDN cache performance, remove the patch version.  There are few cases in which a patch release drops the requirement for a polyfill, but if so, the polyfill can simply be served unnecessarily to the patch versions that contain the fix, and we can stop targeting at the next minor release.
		this.ua.patch = '0';

		// Resolve aliases
		this.ua.family = this.ua.family.toLowerCase();
		if (aliases[this.ua.family]) {

			// Map to different family, use same version scheme
			if (typeof aliases[this.ua.family] === 'string') {
				this.ua.family = aliases[this.ua.family];

			// Map to different family with constant version
			} else if (Array.isArray(aliases[this.ua.family]) && aliases[this.ua.family].length >= 2) {
				a = aliases[this.ua.family];
				this.ua = new useragent.Agent(a[0], a[1], (a[2] || 0), (a[3] || 0));

			// Map to different family with per-version mapping
			} else if (typeof aliases[this.ua.family] === 'object') {
				for (semver in aliases[this.ua.family]) {
					if (this.ua.satisfies(semver) && Array.isArray(aliases[this.ua.family][semver])) {
						a = aliases[this.ua.family][semver];
						this.ua = new useragent.Agent(a[0], a[1], (a[2] || 0), (a[3] || 0));
						break;
					}
				}
			}
		}
		cache.set(uaString, ["", this.ua.family, this.ua.major, this.ua.minor, this.ua.patch]);
	}
};

UA.prototype.getFamily = function() {
	return this.ua.family;
};

UA.prototype.getVersion = function() {
	return this.ua.toVersion();
};

UA.prototype.satisfies = function() {
	return (
		this.ua.satisfies.apply(this.ua, arguments) &&
		this.ua.family in baseLineVersions &&
		this.ua.satisfies(baseLineVersions[this.ua.family])
	);
};
UA.prototype.getBaseline = function() {
	return baseLineVersions[this.ua.family];
};
UA.prototype.meetsBaseline = function() {
	return (this.ua.satisfies(baseLineVersions[this.ua.family]));
};
UA.prototype.isUnknown = function() {
	return (Object.keys(baseLineVersions).indexOf(this.ua.family) === -1);
};

UA.normalize = function(uaString) {
	if (uaString.match(/^\w+\/\d+(\.\d+(\.\d+)?)?$/i)) {
		return uaString.toLowerCase();
	}
	var ua = new UA(uaString);
	return ua ? ua.getFamily() + '/' + ua.getVersion() : undefined;
};

UA.getBaselines = function() {
	return baseLineVersions;
};

UA.normalizeName = function(uaName, version) {
	var semver;
	var name = aliases[uaName.toLowerCase()] || uaName.toLowerCase();
	if (typeof name == 'string') return name;
	if (Array.isArray(name)) return name[0];
	if (typeof name === 'object' && version) {
		var ver = version.split('.');
		var ua = new useragent.Agent(uaName, ver[0], (ver[1] || 0), (ver[2] || 0));
		for (semver in name) {
			if (ua.satisfies(semver)) return name[semver][0];
		}
	} else if (typeof name === 'object') {
		return name[Object.keys(name)[0]][0];
	}
};

module.exports = UA;
<|endoftext|>


<commit_before>function BH() {
    this._lastGenId = 0;
    this._lastMatchId = 0;
    this._matchers = [];
    this._dirtyEnv = false;
    for (var i in {}) {
        this._dirtyEnv = true;
        break;
    }
    this._selfCloseHtmlTags = {
        area: 1,
        base: 1,
        br: 1,
        col: 1,
        command: 1,
        embed: 1,
        hr: 1,
        img: 1,
        input: 1,
        keygen: 1,
        link: 1,
        meta: 1,
        param: 1,
        source: 1,
        wbr: 1
    };
    /**
     * External libs namespace.
     * @type {Object}
     */
    this.lib = {};
    this.utils = {
        bh: this,
        extend: function(target) {
            typeof target !== 'object' && (target = {});
            for(var i = 1, len = arguments.length; i < len; i++) {
                var obj = arguments[i];
                if(obj) {
                    for(var key in obj) {
                        obj.hasOwnProperty(key) && (target[key] = obj[key]);
                    }
                }
            }
            return target;
        },
        isArray: function (obj) {
            return Array.isArray(obj);
        },
        position: function () {
            var node = this.node;
            return node.index === 'content' ? 0 : node.index;
        },
        isFirst: function () {
            var node = this.node;
            return node.index === 'content' || node.index === 0;
        },
        isLast: function () {
            var node = this.node;
            return node.index === 'content' ? true : node.index === node.arr.length - 1;
        },
        tParam: function (key, value) {
            var keyName = '__tp_' + key;
            if (arguments.length === 2) {
                this.node[keyName] = value;
            } else {
                var node = this.node;
                while (node) {
                    if (node.hasOwnProperty(keyName)) {
                        return node[keyName];
                    }
                    node = node.parentNode;
                }
            }
        },
        apply: function (bemjson) {
            return this.bh.processBemjson(bemjson);
        }
    };
}

BH.prototype = {

    /**
     * Converts BEMJSON to HTML code.
     * @param {Object|Array|String} bemjson
     */
    apply: function (bemjson) {
        return this.toHtml(this.processBemjson(bemjson));
    },

    /**
     * Declares matcher.
     * @example
     *
     *      bh.match('b-page', function(ctx) {
     *          ctx.mix.push({ block: 'i-ua' });
     *          ctx.cls = ctx.cls || 'i-ua_js_no i-ua_css_standard';
     *      });
     *
     *      bh.match('block_mod_modVal', function(ctx) {
     *          ctx.tag = ctx.tag || 'span';
     *      });
     *
     *      bh.match('block__elem', function(ctx) {
     *          ctx.attrs.disabled = 'disabled';
     *      });
     *
     *      bh.match('block__elem_elemMod_elemModVal', function(ctx) {
     *          ctx.mods.active = ctx.mods.active || 'yes';
     *      });
     *
     *      bh.match('block_blockMod_blockModVal__elem', function(ctx) {
     *          ctx.content = {
     *              elem: 'wrapper',
     *              content: ctx
     *          };
     *      });
     *
     * @param {String} expr
     * @param {Function} matcher
     */
    match: function (expr, matcher) {
        matcher.__id = '__func' + (this._lastMatchId++);
        this._matchers.push([expr, matcher]);
    },

    generateId: function () {
        return 'uniq' + (this._lastGenId++);
    },

    buildMatcher: function () {
        var i;
        var res = ['(function() {'];
        var vars = ['ms = this._matchers', 'bh = this'];
        var allMatchers = this._matchers;
        var currentBlock;
        var prevExpr;
        for (i = allMatchers.length - 1; i >= 0; i--) {
            vars.push('_m' + i + ' = ms[' + i + '][1]');
        }
        res.push('var ' + vars.join(', ') + ';');
        res.push('function applyMatchers(ctx) {');
        res.push('var subRes;');
        for (i = allMatchers.length - 1; i >= 0; i--) {
            var mi = allMatchers[i];
            var expr = mi[0];
            var decl = {};
            var exprBits;
            var blockExprBits;
            var jsCond = '';
            if (expr) {
                if (~expr.indexOf('__')) {
                    exprBits = expr.split('__');
                    blockExprBits = exprBits[0].split('_');
                    decl.block = blockExprBits[0];
                    if (blockExprBits.length > 1) {
                        decl.blockMod = blockExprBits[1];
                        decl.blockModVal = blockExprBits[2];
                    }
                    exprBits = exprBits[1].split('_');
                    decl.elem = exprBits[0];
                    if (exprBits.length > 1) {
                        decl.mod = exprBits[1];
                        decl.modVal = exprBits[2];
                    }
                } else {
                    exprBits = expr.split('_');
                    decl.block = exprBits[0];
                    if (exprBits.length > 1) {
                        decl.mod = exprBits[1];
                        decl.modVal = exprBits[2];
                    }
                }
            }
            if (currentBlock !== decl.block) {
                if (currentBlock) {
                    res.push('}');
                }
                currentBlock = decl.block;
                if (currentBlock) {
                    res.push('if (ctx.block === "' + currentBlock + '") {');
                }
            }
            var conds = [];
            decl.elem && conds.push('ctx.elem === "' + decl.elem + '"');
            decl.block && !decl.elem && conds.push('!ctx.elem');
            decl.mod && conds.push('ctx.mods.' + decl.mod + ' === "' + decl.modVal + '"');
            if (decl.block && decl.blockMod) {
                conds.push('ctx.blockMods.' + decl.blockMod + ' === "' + decl.blockModVal + '"');
            }
            jsCond && conds.push(jsCond);
            conds.push('!ctx.' + mi[1].__id);
            res.push('if (' + conds.join(' && ') + ') {');
            res.push('ctx.' + mi[1].__id + ' = true;');
            var strFn = mi[1].toString();
            if (~strFn.indexOf('attrs')) {
                res.push('ctx.attrs = ctx.attrs || {};');
            }
            if (~strFn.indexOf('mods')) {
                res.push('ctx.mods = ctx.mods || {};');
            }
            if (~strFn.indexOf('mix')) {
                res.push('ctx.mix = ctx.mix || [];');
            }
            res.push('subRes = _m' + i + '(ctx);');
            res.push('if (subRes) { return subRes; }');
            res.push('}');
            prevExpr = expr;
        }
        if (currentBlock) {
            res.push('}');
        }
        res.push('};');
        res.push('return applyMatchers;');
        res.push('})');
        return res.join('\n');
    },

    processBemjson: function (bemjson, blockName) {
        var utils = this.utils;
        var resultArr = [bemjson];
        var nodes = [{ json: bemjson, arr: resultArr, index: 0, blockName: blockName, blockMods: bemjson.mods || {} }];
        var node, json, block, blockMods, i, l, p, child, subRes;
        var compiledMatcher = (this._fastMatcher || (this._fastMatcher = eval(this.buildMatcher()).call(this)));
        while (node = nodes.shift()) {
            json = node.json;
            block = node.blockName;
            blockMods = node.blockMods;
            if (Array.isArray(json)) {
                for (i = 0, l = json.length; i < l; i++) {
                    child = json[i];
                    if (child !== false && child != null && typeof child !== 'string') {
                        nodes.push({ json: child, arr: json, index: i, blockName: block, blockMods: blockMods, parentNode: node });
                    }
                }
            } else {
                var content, stopProcess = false;
                if (json.elem) {
                    block = json.block = json.block || block;
                    blockMods = json.blockMods = json.blockMods || blockMods;
                } else if (json.block) {
                    block = json.block;
                    blockMods = json.mods || (json.mods = {});
                }

                if (json.block) {
                    subRes = null;

                    utils.node = node;

                    subRes = compiledMatcher(json);

                    if (subRes) {
                        json = subRes;
                        node.json = json;
                        node.blockName = block;
                        node.blockMods = blockMods;
                        nodes.push(node);
                        stopProcess = true;
                    }
                }
                if (!stopProcess) {
                    if (Array.isArray(json)) {
                        node.json = json;
                        node.blockName = block;
                        node.blockMods = blockMods;
                        nodes.push(node);
                    } else {
                        if (content = json.content) {
                            if (Array.isArray(content)) {
                                do {
                                    var flatten = false;
                                    for (i = 0, l = content.length; i < l; i++) {
                                        if (Array.isArray(content[i])) {
                                            flatten = true;
                                            break;
                                        }
                                    }
                                    if (flatten) {
                                        var res = [];
                                        for (i = 0, l = content.length; i < l; i++) {
                                            res = res.concat(content[i]);
                                        }
                                        json.content = content = res;
                                    }
                                } while (flatten);
                                for (i = 0, l = content.length, p = l - 1; i < l; i++) {
                                    child = content[i];
                                    if (child !== false && child != null && typeof child !== 'string') {
                                        nodes.push({ json: child, arr: content, index: i, blockName: block, blockMods: blockMods, parentNode: node });
                                    }
                                }
                            } else {
                                nodes.push({ json: content, arr: json, index: 'content', blockName: block, blockMods: blockMods, parentNode: node });
                            }
                        }
                    }
                }
            }
            node.arr[node.index] = json;
        }
        return resultArr[0];
    },

    escapeAttr: function (attrVal) {
        return (attrVal + '').replace(/&/g, '&')
               .replace(/"/g, '"');
    },

    toHtml: function (json) {
        var res, i, l, item;
        if (json === false || json == null) return '';
        if (typeof json === 'string') {
            return json;
        }
        else if (Array.isArray(json)) {
            res = '';
            for (i = 0, l = json.length; i < l; i++) {
                item = json[i];
                if (item !== false && item != null) {
                    res += this.toHtml(item);
                }
            }
            return res;
        } else {
            var cls = json.bem !== false && json.block ? this.toBEMCssClasses(json, json.block) : '',
                jattr, attrs = '', jsParams, hasMixJsParams = false;

            if (jattr = json.attrs) {
                if (this._dirtyEnv) {
                    for (i in jattr) {
                        jattr.hasOwnProperty(i) && (attrs += ' ' + i + '="' + this.escapeAttr(jattr[i]) + '"');
                    }
                } else {
                    for (i in jattr) {
                        attrs += ' ' + i + '="' + this.escapeAttr(jattr[i]) + '"';
                    }
                }
            }

            if (json.js) {
                (jsParams = {})[json.block + (json.elem ? '__' + json.elem : '')] = json.js === true ? {} : json.js;
            }

            var mixes = json.mix;
            if (mixes && mixes.length) {
                for (i = 0, l = mixes.length; i < l; i++) {
                    var mix = mixes[i];
                    if (mix.js) {
                        (jsParams = jsParams || {})[(mix.block || json.block) + (mix.elem ? '__' + mix.elem : '')] = mix.js === true ? {} : mix.js;
                        hasMixJsParams = true;
                    }
                }
            }

            if (jsParams) {
                if (json.bem !== false) {
                    cls = cls + ' i-bem';
                }
            }

            if (jsParams) {
                attrs += (json.jsAttr || 'onclick') + '="return ' +
                    (!hasMixJsParams && json.js === true
                        ? '{"' + json.block + (json.elem ? '__' + json.elem : '') + '":{}}'
                        : this.escapeAttr(JSON.stringify(jsParams))) + ';"';
            }

            json.cls && (cls = cls ? cls + ' ' + json.cls : json.cls);

            var content, tag = (json.tag || 'div');
            res = '<' + tag + (cls ? ' class="' + cls + '"' : '') + (attrs ? attrs : '');

            if (this._selfCloseHtmlTags[tag]) {
                res += '/>';
            } else {
                res += '>';
                if (content = json.content) {
                    if (Array.isArray(content)) {
                        for (i = 0, l = content.length; i < l; i++) {
                            item = content[i];
                            if (item !== false && item != null) {
                                res += this.toHtml(item);
                            }
                        }
                    } else {
                        res += this.toHtml(content);
                    }
                }
                res += '</' + tag + '>';
            }
            return res;
        }
    },

    toBEMCssClasses: function (json, blockName) {
        var mods, res, base = (json.block || blockName)
            + (json.elem ? '__' + json.elem : ''), mix, i, l;
        res = base;
        if (mods = json.mods) {
            if (this._dirtyEnv) {
                for (i in mods) {
                    mods.hasOwnProperty(i) && (res += ' ' + base + '_' + i + '_' + mods[i]);
                }
            } else {
                for (i in mods) {
                    res += ' ' + base + '_' + i + '_' + mods[i];
                }
            }
        }
        if ((mix = json.mix) && (l = mix.length)) {
            for (i = 0; i < l; i++) {
                res += ' ' + this.toBEMCssClasses(mix[i], blockName);
            }
        }
        return res;
    }

};

module.exports = BH;
<commit_msg>mods fix<commit_after>function BH() {
    this._lastGenId = 0;
    this._lastMatchId = 0;
    this._matchers = [];
    this._dirtyEnv = false;
    for (var i in {}) {
        this._dirtyEnv = true;
        break;
    }
    this._selfCloseHtmlTags = {
        area: 1,
        base: 1,
        br: 1,
        col: 1,
        command: 1,
        embed: 1,
        hr: 1,
        img: 1,
        input: 1,
        keygen: 1,
        link: 1,
        meta: 1,
        param: 1,
        source: 1,
        wbr: 1
    };
    /**
     * External libs namespace.
     * @type {Object}
     */
    this.lib = {};
    this.utils = {
        bh: this,
        extend: function(target) {
            typeof target !== 'object' && (target = {});
            for(var i = 1, len = arguments.length; i < len; i++) {
                var obj = arguments[i];
                if(obj) {
                    for(var key in obj) {
                        obj.hasOwnProperty(key) && (target[key] = obj[key]);
                    }
                }
            }
            return target;
        },
        isArray: function (obj) {
            return Array.isArray(obj);
        },
        position: function () {
            var node = this.node;
            return node.index === 'content' ? 0 : node.index;
        },
        isFirst: function () {
            var node = this.node;
            return node.index === 'content' || node.index === 0;
        },
        isLast: function () {
            var node = this.node;
            return node.index === 'content' ? true : node.index === node.arr.length - 1;
        },
        tParam: function (key, value) {
            var keyName = '__tp_' + key;
            if (arguments.length === 2) {
                this.node[keyName] = value;
            } else {
                var node = this.node;
                while (node) {
                    if (node.hasOwnProperty(keyName)) {
                        return node[keyName];
                    }
                    node = node.parentNode;
                }
            }
        },
        apply: function (bemjson) {
            return this.bh.processBemjson(bemjson);
        }
    };
}

BH.prototype = {

    /**
     * Converts BEMJSON to HTML code.
     * @param {Object|Array|String} bemjson
     */
    apply: function (bemjson) {
        return this.toHtml(this.processBemjson(bemjson));
    },

    /**
     * Declares matcher.
     * @example
     *
     *      bh.match('b-page', function(ctx) {
     *          ctx.mix.push({ block: 'i-ua' });
     *          ctx.cls = ctx.cls || 'i-ua_js_no i-ua_css_standard';
     *      });
     *
     *      bh.match('block_mod_modVal', function(ctx) {
     *          ctx.tag = ctx.tag || 'span';
     *      });
     *
     *      bh.match('block__elem', function(ctx) {
     *          ctx.attrs.disabled = 'disabled';
     *      });
     *
     *      bh.match('block__elem_elemMod_elemModVal', function(ctx) {
     *          ctx.mods.active = ctx.mods.active || 'yes';
     *      });
     *
     *      bh.match('block_blockMod_blockModVal__elem', function(ctx) {
     *          ctx.content = {
     *              elem: 'wrapper',
     *              content: ctx
     *          };
     *      });
     *
     * @param {String} expr
     * @param {Function} matcher
     */
    match: function (expr, matcher) {
        matcher.__id = '__func' + (this._lastMatchId++);
        this._matchers.push([expr, matcher]);
    },

    generateId: function () {
        return 'uniq' + (this._lastGenId++);
    },

    buildMatcher: function () {
        var i;
        var res = ['(function() {'];
        var vars = ['ms = this._matchers', 'bh = this'];
        var allMatchers = this._matchers;
        var currentBlock;
        var prevExpr;
        for (i = allMatchers.length - 1; i >= 0; i--) {
            vars.push('_m' + i + ' = ms[' + i + '][1]');
        }
        res.push('var ' + vars.join(', ') + ';');
        res.push('function applyMatchers(ctx) {');
        res.push('var subRes;');
        for (i = allMatchers.length - 1; i >= 0; i--) {
            var mi = allMatchers[i];
            var expr = mi[0];
            var decl = {};
            var exprBits;
            var blockExprBits;
            var jsCond = '';
            if (expr) {
                if (~expr.indexOf('__')) {
                    exprBits = expr.split('__');
                    blockExprBits = exprBits[0].split('_');
                    decl.block = blockExprBits[0];
                    if (blockExprBits.length > 1) {
                        decl.blockMod = blockExprBits[1];
                        decl.blockModVal = blockExprBits[2];
                    }
                    exprBits = exprBits[1].split('_');
                    decl.elem = exprBits[0];
                    if (exprBits.length > 1) {
                        decl.mod = exprBits[1];
                        decl.modVal = exprBits[2];
                    }
                } else {
                    exprBits = expr.split('_');
                    decl.block = exprBits[0];
                    if (exprBits.length > 1) {
                        decl.mod = exprBits[1];
                        decl.modVal = exprBits[2];
                    }
                }
            }
            if (currentBlock !== decl.block) {
                if (currentBlock) {
                    res.push('}');
                }
                currentBlock = decl.block;
                if (currentBlock) {
                    res.push('if (ctx.block === "' + currentBlock + '") {');
                }
            }
            var conds = [];
            decl.elem && conds.push('ctx.elem === "' + decl.elem + '"');
            decl.block && !decl.elem && conds.push('!ctx.elem');
            decl.mod && conds.push('ctx.mods && ctx.mods.' + decl.mod + ' === "' + decl.modVal + '"');
            if (decl.block && decl.blockMod) {
                conds.push('ctx.blockMods.' + decl.blockMod + ' === "' + decl.blockModVal + '"');
            }
            jsCond && conds.push(jsCond);
            conds.push('!ctx.' + mi[1].__id);
            res.push('if (' + conds.join(' && ') + ') {');
            res.push('ctx.' + mi[1].__id + ' = true;');
            var strFn = mi[1].toString();
            if (~strFn.indexOf('attrs')) {
                res.push('ctx.attrs = ctx.attrs || {};');
            }
            if (~strFn.indexOf('mods')) {
                res.push('ctx.mods = ctx.mods || {};');
            }
            if (~strFn.indexOf('mix')) {
                res.push('ctx.mix = ctx.mix || [];');
            }
            res.push('subRes = _m' + i + '(ctx);');
            res.push('if (subRes) { return subRes; }');
            res.push('}');
            prevExpr = expr;
        }
        if (currentBlock) {
            res.push('}');
        }
        res.push('};');
        res.push('return applyMatchers;');
        res.push('})');
        return res.join('\n');
    },

    processBemjson: function (bemjson, blockName) {
        var utils = this.utils;
        var resultArr = [bemjson];
        var nodes = [{ json: bemjson, arr: resultArr, index: 0, blockName: blockName, blockMods: bemjson.mods || {} }];
        var node, json, block, blockMods, i, l, p, child, subRes;
        var compiledMatcher = (this._fastMatcher || (this._fastMatcher = eval(this.buildMatcher()).call(this)));
        while (node = nodes.shift()) {
            json = node.json;
            block = node.blockName;
            blockMods = node.blockMods;
            if (Array.isArray(json)) {
                for (i = 0, l = json.length; i < l; i++) {
                    child = json[i];
                    if (child !== false && child != null && typeof child !== 'string') {
                        nodes.push({ json: child, arr: json, index: i, blockName: block, blockMods: blockMods, parentNode: node });
                    }
                }
            } else {
                var content, stopProcess = false;
                if (json.elem) {
                    block = json.block = json.block || block;
                    blockMods = json.blockMods = json.blockMods || blockMods;
                } else if (json.block) {
                    block = json.block;
                    blockMods = json.mods || (json.mods = {});
                }

                if (json.block) {
                    subRes = null;

                    utils.node = node;

                    subRes = compiledMatcher(json);

                    if (subRes) {
                        json = subRes;
                        node.json = json;
                        node.blockName = block;
                        node.blockMods = blockMods;
                        nodes.push(node);
                        stopProcess = true;
                    }
                }
                if (!stopProcess) {
                    if (Array.isArray(json)) {
                        node.json = json;
                        node.blockName = block;
                        node.blockMods = blockMods;
                        nodes.push(node);
                    } else {
                        if (content = json.content) {
                            if (Array.isArray(content)) {
                                do {
                                    var flatten = false;
                                    for (i = 0, l = content.length; i < l; i++) {
                                        if (Array.isArray(content[i])) {
                                            flatten = true;
                                            break;
                                        }
                                    }
                                    if (flatten) {
                                        var res = [];
                                        for (i = 0, l = content.length; i < l; i++) {
                                            res = res.concat(content[i]);
                                        }
                                        json.content = content = res;
                                    }
                                } while (flatten);
                                for (i = 0, l = content.length, p = l - 1; i < l; i++) {
                                    child = content[i];
                                    if (child !== false && child != null && typeof child !== 'string') {
                                        nodes.push({ json: child, arr: content, index: i, blockName: block, blockMods: blockMods, parentNode: node });
                                    }
                                }
                            } else {
                                nodes.push({ json: content, arr: json, index: 'content', blockName: block, blockMods: blockMods, parentNode: node });
                            }
                        }
                    }
                }
            }
            node.arr[node.index] = json;
        }
        return resultArr[0];
    },

    escapeAttr: function (attrVal) {
        return (attrVal + '').replace(/&/g, '&')
               .replace(/"/g, '"');
    },

    toHtml: function (json) {
        var res, i, l, item;
        if (json === false || json == null) return '';
        if (typeof json === 'string') {
            return json;
        }
        else if (Array.isArray(json)) {
            res = '';
            for (i = 0, l = json.length; i < l; i++) {
                item = json[i];
                if (item !== false && item != null) {
                    res += this.toHtml(item);
                }
            }
            return res;
        } else {
            var cls = json.bem !== false && json.block ? this.toBEMCssClasses(json, json.block) : '',
                jattr, attrs = '', jsParams, hasMixJsParams = false;

            if (jattr = json.attrs) {
                if (this._dirtyEnv) {
                    for (i in jattr) {
                        jattr.hasOwnProperty(i) && (attrs += ' ' + i + '="' + this.escapeAttr(jattr[i]) + '"');
                    }
                } else {
                    for (i in jattr) {
                        attrs += ' ' + i + '="' + this.escapeAttr(jattr[i]) + '"';
                    }
                }
            }

            if (json.js) {
                (jsParams = {})[json.block + (json.elem ? '__' + json.elem : '')] = json.js === true ? {} : json.js;
            }

            var mixes = json.mix;
            if (mixes && mixes.length) {
                for (i = 0, l = mixes.length; i < l; i++) {
                    var mix = mixes[i];
                    if (mix.js) {
                        (jsParams = jsParams || {})[(mix.block || json.block) + (mix.elem ? '__' + mix.elem : '')] = mix.js === true ? {} : mix.js;
                        hasMixJsParams = true;
                    }
                }
            }

            if (jsParams) {
                if (json.bem !== false) {
                    cls = cls + ' i-bem';
                }
            }

            if (jsParams) {
                attrs += (json.jsAttr || 'onclick') + '="return ' +
                    (!hasMixJsParams && json.js === true
                        ? '{"' + json.block + (json.elem ? '__' + json.elem : '') + '":{}}'
                        : this.escapeAttr(JSON.stringify(jsParams))) + ';"';
            }

            json.cls && (cls = cls ? cls + ' ' + json.cls : json.cls);

            var content, tag = (json.tag || 'div');
            res = '<' + tag + (cls ? ' class="' + cls + '"' : '') + (attrs ? attrs : '');

            if (this._selfCloseHtmlTags[tag]) {
                res += '/>';
            } else {
                res += '>';
                if (content = json.content) {
                    if (Array.isArray(content)) {
                        for (i = 0, l = content.length; i < l; i++) {
                            item = content[i];
                            if (item !== false && item != null) {
                                res += this.toHtml(item);
                            }
                        }
                    } else {
                        res += this.toHtml(content);
                    }
                }
                res += '</' + tag + '>';
            }
            return res;
        }
    },

    toBEMCssClasses: function (json, blockName) {
        var mods, res, base = (json.block || blockName)
            + (json.elem ? '__' + json.elem : ''), mix, i, l;
        res = base;
        if (mods = json.mods) {
            if (this._dirtyEnv) {
                for (i in mods) {
                    mods.hasOwnProperty(i) && (res += ' ' + base + '_' + i + '_' + mods[i]);
                }
            } else {
                for (i in mods) {
                    res += ' ' + base + '_' + i + '_' + mods[i];
                }
            }
        }
        if ((mix = json.mix) && (l = mix.length)) {
            for (i = 0; i < l; i++) {
                res += ' ' + this.toBEMCssClasses(mix[i], blockName);
            }
        }
        return res;
    }

};

module.exports = BH;
<|endoftext|>