<commit_before>import Ember from 'ember';
import setWindowTitle from '../utils/set-window-title';
import setDockMenu from '../utils/set-dock-menu';
import setUsertasks from '../utils/set-user-tasks';
import getCurrentWindow from '../utils/get-current-window';

const {Component} = Ember;

export default Component.extend({
    store: Ember.inject.service(),
    autoUpdate: Ember.inject.service(),
    classNameBindings: ['isMac:mac', 'isWindows:win',':gh-app'],
    isFindInViewActive: false,
    isMac: !!(process.platform === 'darwin'),
    isWindows: !!(process.platform === 'win32'),

    didReceiveAttrs() {
        this.setup();
        this.createSingleInstance();
        this.get('autoUpdate').checkForUpdates();
    },

    /**
     * Boolean value that returns true if there are any blogs
     */
    hasBlogs: Ember.computed('blogs', function () {
        let b = this.get('blogs');
        return (b && b.content && b.content.length && b.content.length > 0);
    }),

    blogsObserver: Ember.observer('hasBlogs', function () {
        if (!this.get('hasBlogs')) {
            this.send('showAddBlog');
        }
    }),

    titleObserver: Ember.observer('title', function () {
        setWindowTitle(this.get('title'));
    }),

    /**
     * Setup method, determining which blog to display.
     */
    setup() {
        if (this.get('hasBlogs')) {
            this.send('switchToBlog', this.findSelectedBlog() || this.get('blogs.firstObject'));
            this.createMenus();
        } else {
            this.set('isEditBlogVisible', true);
        }
    },

    /**
     * Ensures Ghost runs as a single instance.
     */
    createSingleInstance() {
        let {remote} = requireNode('electron');
        let {app} = remote;

        if (!this.appWindow) {
            this.appWindow = getCurrentWindow();
        }

        let shouldQuit = app.makeSingleInstance(this.onInstanceCheck.bind(this));

        if (shouldQuit) {
            app.quit();
        }
    },

    /**
     * Checks if the instance was supplied with a blog url as a parameter, if so, switch to it.
     *
     * @param {Array} argv - Arguments used to start the instance
     * @param {string} workingDirectory - The working directory when the instance was created.
     */
    onInstanceCheck(argv) {
        if (argv.length >= 2) {
            let [ , url] = argv;

            let blog = this.get('blogs').find((blog) => {
                return blog.get('url') === url;
            });

            if (blog) {
                this.send('switchToBlog', blog);
            }
        }

        if (this.appWindow) {
            if (this.appWindow.isMinimized()) {
                this.appWindow.restore();
            }
            this.appWindow.focus();
        }
    },

    /**
     * Gets the current blogs and creates the various menus.
     * On Windows: User Tasks (taskbar)
     * On OS X: Dock Menu
     * On all: Window Menu
     */
    createMenus() {
        let he    = requireNode('he');
        let blogs = this.get('blogs');
        let menu  = [];

        blogs.forEach((blog) => {
            menu.push({
                name: he.decode(blog.get('name')),
                callback: () => this.send('switchToBlog', blog)
            });
        });

        if (process.platform === 'darwin') {
            setDockMenu(menu);
        }

        if (process.platform === 'win32') {
            setUsertasks(menu);
        }
    },

    /**
     * Finds the first blog marked as "selected"
     *
     * @returns {Object} blog
     */
    findSelectedBlog() {
        if (!this.get('hasBlogs')) {
            return null;
        }

        return this.get('blogs').find((blog) => {
            return blog.get('isSelected');
        });
    },

    /**
     * Reloads the blogs from the local databse
     */
    refreshBlogs() {
        this.get('store').findAll('blog')
            .then((result) => {
                this.set('blogs', result);
                this.setup();
            });
    },

    /**
     * Sets the visibility of the preferences ui, the edit blog ui,
     * and the blogs.
     *
     * @param {Object}   [options={}] - Options object
     * @param {boolean}  [options.showBlog=true] - "Edit Blog" UI
     * @param {boolean}  [options.showPreferences=false] - "Preferences" UI
     * @param {DS.Model} [options.blog] - Blog to display
     */
    setScreenVisibility({showAddBlog = true, showPreferences = false, blog = null}) {
        let selectedBlog = this.get('selectedBlog');

        if ((!blog && selectedBlog) || (selectedBlog && blog && selectedBlog !== blog)) {
            selectedBlog.unselect();
        }

        if (blog) {
            blog.select();
            this.set('title', `Ghost - ${blog.get('name')}`);
            this.set('selectedBlog', blog);
        }

        this.setProperties({
            isPreferencesVisible: showPreferences,
            isEditBlogVisible: showAddBlog
        });
    },

    /**
     * Displays the "add blog" UI
     */
    showEditBlogUI() {
        this.setScreenVisibility({
            showAddBlog: true,
            showPreferences: false
        });
    },

    /**
     * Displays the "preferences" UI
     */
    showPreferencesUI() {
        this.setScreenVisibility({
            showAddBlog: false,
            showPreferences: true
        });
    },

    actions: {
        /**
         * Switches to a given blog
         *
         * @param {Object} blog - Blog to switch to
         */
        switchToBlog(blog) {
            if (blog) {
                this.setScreenVisibility({
                    showAddBlog: false,
                    showPreferences: false,
                    blog
                });
            }
        },

        /**
         * Clears the "blogToEdit" property, turning the
         * edit blog UI into an "add blog" UI
         */
        showAddBlog() {
            this.set('blogToEdit', undefined);
            this.showEditBlogUI();
        },

        /**
         * Sets the blogToEdit property to a given blog
         *
         * @param blog - Blog to edit
         */
        showEditBlog(blog, editWarning) {
            this.set('blogToEdit', blog);
            this.set('editWarning', editWarning);
            this.showEditBlogUI();
        },

        /**
         * Shows the preferences
         */
        showPreferences() {
            this.showPreferencesUI();
        },

        /**
         * Handles an added blog
         *
         * @param {Object} blog - Added blog
         */
        blogAdded(blog) {
            this.send('switchToBlog', blog);
        },

        /**
         * Handles the removal of a blog
         */
        blogRemoved() {
            this.refreshBlogs();
        }
    }
});
<commit_msg>:wrench: Housekeeping: gh-app<commit_after>import Ember from 'ember';
import setWindowTitle from '../utils/set-window-title';
import setDockMenu from '../utils/set-dock-menu';
import setUsertasks from '../utils/set-user-tasks';
import getCurrentWindow from '../utils/get-current-window';

const {Component, inject, computed, observer} = Ember;

export default Component.extend({
    store: inject.service(),
    autoUpdate: inject.service(),
    ipc: inject.service(),
    classNameBindings: ['isMac:mac', 'isWindows:win',':gh-app'],
    isFindInViewActive: false,
    isMac: !!(process.platform === 'darwin'),
    isWindows: !!(process.platform === 'win32'),

    /**
     * Called when the attributes passed into the component have been updated.
     * Called both during the initial render of a container and during a rerender.
     * Can be used in place of an observer; code placed here will be executed
     * every time any attribute updates.
     */
    didReceiveAttrs() {
        this.setup();
        this.createSingleInstance();
        this.get('autoUpdate').checkForUpdates();
    },

    /**
     * Called when the element of the view has been inserted into the DOM.
     */
    didInsertElement() {
        this.get('ipc').notifyReady();
    },

    /**
     * Boolean value that returns true if there are any blogs
     */
    hasBlogs: computed('blogs', function () {
        let b = this.get('blogs');
        return (b && b.content && b.content.length && b.content.length > 0);
    }),

    blogsObserver: observer('hasBlogs', function () {
        if (!this.get('hasBlogs')) this.send('showAddBlog');
    }),

    titleObserver: observer('title', function () {
        setWindowTitle(this.get('title'));
    }),

    /**
     * Setup method, determining which blog to display.
     */
    setup() {
        if (this.get('hasBlogs')) {
            this.send('switchToBlog', this.findSelectedBlog() || this.get('blogs.firstObject'));
            this.createMenus();
        } else {
            this.set('isEditBlogVisible', true);
        }
    },

    /**
     * Ensures Ghost runs as a single instance.
     */
    createSingleInstance() {
        const {remote} = requireNode('electron');
        const {app} = remote;

        if (!this.appWindow) this.appWindow = getCurrentWindow();

        const shouldQuit = app.makeSingleInstance(this.onInstanceCheck.bind(this));
        if (shouldQuit) app.quit();
    },

    /**
     * Checks if the instance was supplied with a blog url as a parameter, if so, switch to it.
     *
     * @param {Array} argv - Arguments used to start the instance
     * @param {string} workingDirectory - The working directory when the instance was created.
     */
    onInstanceCheck(argv) {
        if (argv.length >= 2) {
            const [ , url] = argv;
            const blog = this.get('blogs').find((blog) => blog.get('url') === url);

            if (blog) this.send('switchToBlog', blog);
        }

        if (this.appWindow) {
            if (this.appWindow.isMinimized()) this.appWindow.restore();
            this.appWindow.focus();
        }
    },

    /**
     * Gets the current blogs and creates the various menus.
     * On Windows: User Tasks (taskbar)
     * On OS X: Dock Menu
     * On all: Window Menu
     */
    createMenus() {
        const he = requireNode('he');
        const blogs = this.get('blogs');
        let menu = [];

        blogs.forEach((blog) => {
            menu.push({
                name: he.decode(blog.get('name')),
                callback: () => this.send('switchToBlog', blog)
            });
        });

        if (process.platform === 'darwin') setDockMenu(menu);
        if (process.platform === 'win32') setUsertasks(menu);
    },

    /**
     * Finds the first blog marked as "selected"
     *
     * @returns {Object|null} blog
     */
    findSelectedBlog() {
        if (!this.get('hasBlogs')) return null;

        return this.get('blogs').find((blog) =>  blog.get('isSelected'));
    },

    /**
     * Reloads the blogs from the local databse
     */
    refreshBlogs() {
        this.get('store').findAll('blog')
            .then((result) => {
                this.set('blogs', result);
                this.setup();
            });
    },

    /**
     * Sets the visibility of the preferences ui, the edit blog ui,
     * and the blogs.
     *
     * @param {Object}   [options={}] - Options object
     * @param {boolean}  [options.showBlog=true] - "Edit Blog" UI
     * @param {boolean}  [options.showPreferences=false] - "Preferences" UI
     * @param {DS.Model} [options.blog] - Blog to display
     */
    setScreenVisibility({showAddBlog = true, showPreferences = false, blog = null}) {
        const selectedBlog = this.get('selectedBlog');

        if ((!blog && selectedBlog) || (selectedBlog && blog && selectedBlog !== blog)) {
            selectedBlog.unselect();
        }

        if (blog) {
            blog.select();
            this.set('title', `Ghost - ${blog.get('name')}`);
            this.set('selectedBlog', blog);
        }

        this.setProperties({
            isPreferencesVisible: showPreferences,
            isEditBlogVisible: showAddBlog
        });
    },

    /**
     * Displays the "add blog" UI
     */
    showEditBlogUI() {
        this.setScreenVisibility({
            showAddBlog: true,
            showPreferences: false
        });
    },

    /**
     * Displays the "preferences" UI
     */
    showPreferencesUI() {
        this.setScreenVisibility({
            showAddBlog: false,
            showPreferences: true
        });
    },

    actions: {
        /**
         * Switches to a given blog
         *
         * @param {Object} blog - Blog to switch to
         */
        switchToBlog(blog) {
            if (blog) {
                this.setScreenVisibility({
                    showAddBlog: false,
                    showPreferences: false,
                    blog
                });
            }
        },

        /**
         * Clears the "blogToEdit" property, turning the
         * edit blog UI into an "add blog" UI
         */
        showAddBlog() {
            this.set('blogToEdit', undefined);
            this.showEditBlogUI();
        },

        /**
         * Sets the blogToEdit property to a given blog
         *
         * @param blog - Blog to edit
         */
        showEditBlog(blog, editWarning) {
            this.set('blogToEdit', blog);
            this.set('editWarning', editWarning);
            this.showEditBlogUI();
        },

        /**
         * Shows the preferences
         */
        showPreferences() {
            this.showPreferencesUI();
        },

        /**
         * Handles an added blog
         *
         * @param {Object} blog - Added blog
         */
        blogAdded(blog) {
            this.send('switchToBlog', blog);
        },

        /**
         * Handles the removal of a blog
         */
        blogRemoved() {
            this.refreshBlogs();
        }
    }
});
<|endoftext|>


<commit_before>const cx = require('classnames');
const React = require('react');
const types = React.PropTypes;

class LogoBar extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (

献立

                {this.props.expandedMenu &&

                        <fieldset>
                            <legend>Select a Sutra</legend>
                            <select>
                                <option>
                                    Select One
                                </option>
                                <optgroup label="Maka Hannya Haramitta Shin Gyo">
                                    <option value="yes">Heart of Great Perfect Wisdom Sutra</option>
                                </optgroup>
                                <optgroup label="Sandokai">
                                    <option value="yes">Harmony of Difference and Equality</option>
                                </optgroup>
                                <optgroup label="Hokyo Zammai">
                                    <option value="yes">Song of the Jewel Mirror Samadhi</option>
                                </optgroup>
                            </select>
                        </fieldset>

                        <fieldset>
                            <legend>Display</legend>

                                <input type="checkbox"/>Kanji

                                <input type="checkbox"/>Hiragana

                                <input type="checkbox"/>Romaji

                                <input type="checkbox"/>English

                                <input type="checkbox"/>Character #

                        </fieldset>

                        <fieldset>
                            <legend>Layout</legend>

                                <input type="radio"/>English

                                <input type="radio"/>Kanji

                        </fieldset>

                }

        );
    }
}
LogoBar.propTypes = {
    onClick: types.func.isRequired,
    expandedMenu: types.bool
};

class Header extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            expandedMenu: true
        };

    }

    toggleExpandMenu = (event) => {
        event.preventDefault();
        this.setState({expandedMenu: !this.state.expandedMenu});
    }

    render() {
        const {store: {}} = this.props;
        return (

                <LogoBar {...{expandedMenu: this.state.expandedMenu, onClick: this.toggleExpandMenu}} />

        );
    }
}

Header.propTypes = {
    store: types.object.isRequired
};

module.exports = Header;<commit_msg>--amend<commit_after>const cx = require('classnames');
const React = require('react');
const types = React.PropTypes;

class LogoBar extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (

献立

                {this.props.expandedMenu &&

                        <fieldset>
                            <legend>Select a Sutra</legend>
                            <select>
                                <option>
                                    Select One
                                </option>
                                <optgroup label="Maka Hannya Haramitta Shin Gyo">
                                    <option value="yes">Heart of Great Perfect Wisdom Sutra</option>
                                </optgroup>
                                <optgroup label="Sandokai">
                                    <option value="yes">Harmony of Difference and Equality</option>
                                </optgroup>
                                <optgroup label="Hokyo Zammai">
                                    <option value="yes">Song of the Jewel Mirror Samadhi</option>
                                </optgroup>
                            </select>
                        </fieldset>

                        <fieldset>
                            <legend>Display</legend>

                                <input type="checkbox"/>Kanji

                                <input type="checkbox"/>Hiragana

                                <input type="checkbox"/>Romaji

                                <input type="checkbox"/>English

                                <input type="checkbox"/>Character #

                        </fieldset>

                        <fieldset>
                            <legend>Layout</legend>

                                <input type="radio"/>English

                                <input type="radio"/>Kanji

                        </fieldset>

                }

        );
    }
}
LogoBar.propTypes = {
    onClick: types.func.isRequired,
    expandedMenu: types.bool
};

class Header extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            expandedMenu: false
        };

    }

    toggleExpandMenu = (event) => {
        event.preventDefault();
        this.setState({expandedMenu: !this.state.expandedMenu});
    }

    render() {
        const {store: {}} = this.props;
        return (

                <LogoBar {...{expandedMenu: this.state.expandedMenu, onClick: this.toggleExpandMenu}} />

        );
    }
}

Header.propTypes = {
    store: types.object.isRequired
};

module.exports = Header;<|endoftext|>


<commit_before>'use strict';

const logger = require('heroku-logger');

function parseRetryCount(req) {
  const retryCountFromHeader = Number(req.get('x-blink-retry-count')) || 0;
  const retryCountFromQuery = Number(req.query['x-blink-retry-count']) || 0;
  const retryCount = retryCountFromHeader || retryCountFromQuery || 0;

  if (retryCount) {
    req.metadata.retryCount = retryCount;
    logger.info('Blink retry count', { retryCount });
  }
}

function parseRequestId(req) {
  const requestIdFromHeader = req.get('x-request-id');
  const requestIdFromQuery = req.query['x-request-id'];
  const requestId = requestIdFromHeader || requestIdFromQuery;

  if (requestId) {
    req.metadata.requestId = requestId;
    logger.info('Request ID', { requestId });
  }
}

function registerIsARetryRequestFunction(req) {
  req.isARetryRequest = () => !!req.metadata.retryCount;
}

module.exports = function parseMetadata() {
  return (req, res, next) => {
    req.metadata = {};
    parseRetryCount(req);
    parseRequestId(req);
    registerIsARetryRequestFunction(req);
    return next();
  };
};
<commit_msg>moved defining req.attachments to the metadata middleware so its defined for all routes<commit_after>'use strict';

const logger = require('heroku-logger');

function parseRetryCount(req) {
  const retryCountFromHeader = Number(req.get('x-blink-retry-count')) || 0;
  const retryCountFromQuery = Number(req.query['x-blink-retry-count']) || 0;
  const retryCount = retryCountFromHeader || retryCountFromQuery || 0;

  if (retryCount) {
    req.metadata.retryCount = retryCount;
    logger.info('Blink retry count', { retryCount });
  }
}

function parseRequestId(req) {
  const requestIdFromHeader = req.get('x-request-id');
  const requestIdFromQuery = req.query['x-request-id'];
  const requestId = requestIdFromHeader || requestIdFromQuery;

  if (requestId) {
    req.metadata.requestId = requestId;
    logger.info('Request ID', { requestId });
  }
}

function registerIsARetryRequestFunction(req) {
  req.isARetryRequest = () => !!req.metadata.retryCount;
}

/**
 * parseMetadata - Here we parse global properties. All requests to Conversations API will run
 * through this middleware. Most parsing should be done at the specific route's middleware.
 * You should have a good reason to parse it here.
 *
 * @return {type}  description
 */
module.exports = function parseMetadata() {
  return (req, res, next) => {
    req.metadata = {};
    // This is being defined at the global level to support attachments for all routes.
    req.attachments = {
      inbound: [],
      outbound: [],
    };
    parseRetryCount(req);
    parseRequestId(req);
    registerIsARetryRequestFunction(req);
    return next();
  };
};
<|endoftext|>


<commit_before>"use strict";
/**
 * @module opcua.address_space.types
 */

require("requirish")._(module);
var BinaryStreamSizeCalculator = require("lib/misc/binaryStream").BinaryStreamSizeCalculator;
var assert = require("better-assert");
var _ = require("underscore");
var hexDump = require("lib/misc/utils").hexDump;

var getFactory = require("lib/misc/factories_factories").getFactory;
var _defaultTypeMap = require("lib/misc/factories_builtin_types")._defaultTypeMap;

var get_base_schema = require("lib/misc/factories_schema_helpers").get_base_schema;

/**
 * @class BaseUAObject
 * @constructor
 */
function BaseUAObject() {

}

/**
 * Encode the object to the binary stream.
 * @class BaseUAObject
 * @method encode
 * @param stream {BinaryStream}
 * @param options {BinaryStream}
 */
BaseUAObject.prototype.encode = function (/*stream,options*/) {

};

/**
 * Decode the object from the binary stream.
 * @class BaseUAObject
 * @method decode
 * @param stream {BinaryStream}
 * @param options {Object}
 */
BaseUAObject.prototype.decode = function (/*stream,options*/) {

};

/**
 * Calculate the required size to store this object in a binary stream.
 * @method binaryStoreSize
 * @return {Number}
 */
BaseUAObject.prototype.binaryStoreSize = function (options) {

    var stream = new BinaryStreamSizeCalculator();
    this.encode(stream, options);
    return stream.length;
};

/**
 * @method toString
 * @return {String}
 */
BaseUAObject.prototype.toString = function () {

    var self = this;

    if (self._schema && self._schema.hasOwnProperty("toString")) {

        return self._schema.toString.apply(self, arguments);

    } else {
        if (!self.explore) {
            console.log(require("util").inspect(self));
            return Object.prototype.toString.apply(self,arguments);
        }
        return self.explore.apply(self,arguments);
    }
};

/**
 *
 * verify that all object attributes values are valid according to schema
 * @method isValid
 * @return {Boolean}
 */
BaseUAObject.prototype.isValid = function () {
    assert(this._schema);
    if (this._schema.isValid) {
        return this._schema.isValid(this);
    } else {
        return true;
    }
};

function _decode_member_(value, field, stream, options) {

    var tracer = options.tracer;
    var cursor_before = stream.length;
    var fieldType = field.fieldType;

    if (field.category === "basic") {

        value = field.schema.decode(stream);
        tracer.trace("member", options.name, value, cursor_before, stream.length, fieldType);

    } else if (field.category === "enumeration") {

        value = field.schema.decode(stream);
        tracer.trace("member", options.name, value, cursor_before, stream.length, fieldType);

    } else {
        assert(field.category === "complex");
        assert(_.isFunction(field.schema));
        var Constructor = field.schema;
        value = new Constructor();
        value.decode_debug(stream, options);

    }
    return value;
}

/**
 * @method decode_debug
 *
 */
BaseUAObject.prototype.decode_debug = function (stream, options) {

    var tracer = options.tracer;
    var schema = this._schema;

    tracer.trace("start", options.name + "(" + schema.name + ")", stream.length, stream.length);
    var self = this;
    schema.fields.forEach(function (field) {

        var value = self[field.name];

        if (field.isArray) {

            var cursor_before = stream.length;
            var nb = stream.readUInt32();
            if (nb === 0xFFFFFFFF) {
                nb = 0;
            }
            options.name = field.name + [];

            tracer.trace("start_array", field.name, nb, cursor_before, stream.length);
            for (var i = 0; i < nb; i++) {
                tracer.trace("start_element", field.name, i);
                options.name = "element #" + i;

                _decode_member_(value, field, stream, options);

                tracer.trace("end_element", field.name, i);

            }
            tracer.trace("end_array", field.name, stream.length - 4);
        } else {

            options.name = field.name;
            _decode_member_(value, field, stream, options);

        }

    });

    tracer.trace("end", schema.name, stream.length, stream.length);
};

function r(str) {
    return (str + "                                ").substr(0, 30);
}

function apply_on_all_schema_fields(self, schema, data, callback , args) {

    assert(schema);
    var fields = schema.fields;
    var field, i, n = fields.length;
    for (i = 0; i < n; i++) {
        field = fields[i];
        callback(self, field, data , args);
    }
}

var _nb_elements = process.env.ARRAYLENGTH ? parseInt(process.env.NNN) : 10;

function _array_ellypsis(value,field) {

    if (!value) {
        return "null[]";
    } else {
        assert(_.isArray(value));
        var v = [];
        var m = Math.min(_nb_elements, value.length);
        for (var i = 0; i < m; i++) {
            var element = value[i];
            v.push(element ? element.toString() : null);
        }
        return "[ " + v.join(",") + ( value.length > 10 ? " ... " : "") + "] (l=" + value.length + ")";
    }
}

var _exploreObject = function (self, field, data, args) {

    if (!self) {
        return;
    }
    assert(self);

    var fieldType = field.fieldType;
    var fieldName = field.name;
    var category = field.category;

    var padding = data.padding;

    var value = self[fieldName];

    var str;

    var fieldName_f = r(padding + fieldName, 30).yellow;
    var fieldType_f = ("/* " + r(fieldType, 10) + ( field.isArray ? "[]" : "  ") + " */").cyan;

    // compact version of very usual objects
    if (fieldType === "QualifiedName" && !field.isArray && value) {

        value = value.toString() || "<null>";
        str = fieldName_f + " " + fieldType_f + ": " + value.toString().green;
        data.lines.push(str);
        return;
    }
    if (fieldType === "LocalizedText" && !field.isArray && value) {
        value = value.toString() || "<null>";
        str = fieldName_f + " " + fieldType_f + ": " + value.toString().green;
        data.lines.push(str);
        return;
    }

    var _dump_simple_value = function (self, field, data, value, fieldType) {

        var str = "";
        if (value instanceof Buffer) {

            var _hexDump = hexDump(value);
            data.lines.push(fieldName_f + " " + fieldType_f);
            data.lines.push("BUFFER{" + _hexDump + "}");

        } else {

            if (field.isArray) {

                str = fieldName_f + " " + fieldType_f + ": " + _array_ellypsis(value,field);

            } else {
                if (fieldType === "IntegerId" || fieldType === "UInt32") {

                    value = "" + value + "               0x" + value.toString(16);

                } else if (fieldType === "DateTime" || fieldType === "UtcTime") {
                    value = (value && value.toISOString) ? value.toISOString() : value;
                } else if (typeof value === "object" && value !== null) {
                    value = value.toString.apply(value,args);
                }
                str = fieldName_f + " " + fieldType_f + ": " + ((value === null) ? "null".blue.bold : value.toString());
            }
            data.lines.push(str);
        }

    };

    switch (category) {

        case "enumeration":

            str = fieldName_f + " " + fieldType_f + ": " + value.key + " ( " + value.value + ")";
            data.lines.push(str);

            break;

        case "basic":
            _dump_simple_value(self, field, data, value, fieldType);
            break;

        case "complex":
            if (field.subtype) {

                // this is a synonymous
                fieldType = field.subType;
                _dump_simple_value(self, field, data, value, fieldType);

            } else {
                var _new_desc = getFactory(fieldType).prototype._schema;

                if (field.isArray) {
                    if (value === null) {
                        data.lines.push(fieldName_f + " " + fieldType_f + ": null []");
                    } else if (value.length === 0) {
                        data.lines.push(fieldName_f + " " + fieldType_f + ": [ /* empty */ ]");
                    } else {
                        data.lines.push(fieldName_f + " " + fieldType_f + ": [");

                        var i = 0;

                        var m = Math.min(_nb_elements, value.length);
                        for (i = 0; i < m; i++) {
                            var element = value[i];
                            data.lines.push(padding + "  { " + ("/*" + i + "*/").cyan);

                            var data1 = {padding: padding + "    ", lines: []};
                            apply_on_all_schema_fields(element, _new_desc, data1, _exploreObject , args);
                            data.lines = data.lines.concat(data1.lines);

                            data.lines.push(padding + "  }" + ((i === value.length - 1) ? "" : ","));
                        }
                        if (m < value.length) {
                            data.lines.push(padding + " ..... ( " + value.length + " elements )");
                        }
                        data.lines.push(padding + "]");

                    }

                } else {

                    data.lines.push(fieldName_f + " " + fieldType_f + ": {");

                    data1 = {padding: padding + "  ", lines: []};
                    apply_on_all_schema_fields(value, _new_desc, data1, _exploreObject,args);
                    data.lines = data.lines.concat(data1.lines);

                    data.lines.push(padding + "}");
                }
            }

            break;
        default:
            throw new Error("internal error: unknown kind_of_field");
    }
};

BaseUAObject.prototype.explore = function () {

    var self = this;
    var data = {padding: " ", lines: []};
    data.lines.push("{" + (" /*" + this._schema.name + "*/").cyan);
    apply_on_all_schema_fields(self, self._schema, data, _exploreObject,arguments);
    data.lines.push("};");
    return data.lines.join("\n");
};

function _visit_schema_chain(self, schema, options, func, extra_data) {
    assert(_.isFunction(func));

    // apply also construct to baseType schema first
    var base_schema = get_base_schema(schema);
    if (base_schema) {
        _visit_schema_chain(self, base_schema, options, func, extra_data);
    }
    func.call(self, schema, options, extra_data);
}

function _JSONify(schema, options) {

    /* jshint validthis: true */
    var self = this;
    schema.fields.forEach(function (field) {
        var f = self[field.name];
        if (f === null || f === undefined) {
            return;
        }

        var t = _defaultTypeMap[field.fieldType];

        function jsonify(value) {

            if (_.isFunction(field.toJSON)) {
                return field.toJSON(value);
            } else if (t && t.toJSON) {
                return t.toJSON(value);
            } else if (value.toJSON) {
                return value.toJSON();
            } else {
                return f;
            }

        }

        if (field.isArray) {
            options[field.name] = f.map(jsonify);
        } else {
            options[field.name] = jsonify(f);
        }
    });
}

BaseUAObject.prototype.toJSON = function () {

    var self = this;

    assert(this._schema);
    if (this._schema.toJSON) {
        return this._schema.toJSON.apply(this, arguments);
    } else {
        //xx return Object.toJSON.apply(this,arguments);
        assert(self._schema);
        var schema = self._schema;
        var options = {};
        _visit_schema_chain(self, schema, options, _JSONify);
        return options;
    }
};

exports.BaseUAObject = BaseUAObject;
<commit_msg> fix object dump<commit_after>"use strict";
/**
 * @module opcua.address_space.types
 */

require("requirish")._(module);
var BinaryStreamSizeCalculator = require("lib/misc/binaryStream").BinaryStreamSizeCalculator;
var assert = require("better-assert");
var _ = require("underscore");
var hexDump = require("lib/misc/utils").hexDump;

var getFactory = require("lib/misc/factories_factories").getFactory;
var _defaultTypeMap = require("lib/misc/factories_builtin_types")._defaultTypeMap;

var get_base_schema = require("lib/misc/factories_schema_helpers").get_base_schema;
var utils = require("lib/misc/utils");

/**
 * @class BaseUAObject
 * @constructor
 */
function BaseUAObject() {

}

/**
 * Encode the object to the binary stream.
 * @class BaseUAObject
 * @method encode
 * @param stream {BinaryStream}
 * @param options {BinaryStream}
 */
BaseUAObject.prototype.encode = function (/*stream,options*/) {

};

/**
 * Decode the object from the binary stream.
 * @class BaseUAObject
 * @method decode
 * @param stream {BinaryStream}
 * @param options {Object}
 */
BaseUAObject.prototype.decode = function (/*stream,options*/) {

};

/**
 * Calculate the required size to store this object in a binary stream.
 * @method binaryStoreSize
 * @return {Number}
 */
BaseUAObject.prototype.binaryStoreSize = function (options) {

    var stream = new BinaryStreamSizeCalculator();
    this.encode(stream, options);
    return stream.length;
};

/**
 * @method toString
 * @return {String}
 */
BaseUAObject.prototype.toString = function () {

    var self = this;

    if (self._schema && self._schema.hasOwnProperty("toString")) {

        return self._schema.toString.apply(self, arguments);

    } else {
        if (!self.explore) {
            console.log(require("util").inspect(self));
            return Object.prototype.toString.apply(self,arguments);
        }
        return self.explore.apply(self,arguments);
    }
};

/**
 *
 * verify that all object attributes values are valid according to schema
 * @method isValid
 * @return {Boolean}
 */
BaseUAObject.prototype.isValid = function () {
    assert(this._schema);
    if (this._schema.isValid) {
        return this._schema.isValid(this);
    } else {
        return true;
    }
};

function _decode_member_(value, field, stream, options) {

    var tracer = options.tracer;
    var cursor_before = stream.length;
    var fieldType = field.fieldType;

    if (field.category === "basic") {

        value = field.schema.decode(stream);
        tracer.trace("member", options.name, value, cursor_before, stream.length, fieldType);

    } else if (field.category === "enumeration") {

        value = field.schema.decode(stream);
        tracer.trace("member", options.name, value, cursor_before, stream.length, fieldType);

    } else {
        assert(field.category === "complex");
        assert(_.isFunction(field.schema));
        var Constructor = field.schema;
        value = new Constructor();
        value.decode_debug(stream, options);

    }
    return value;
}

/**
 * @method decode_debug
 *
 */
BaseUAObject.prototype.decode_debug = function (stream, options) {

    var tracer = options.tracer;
    var schema = this._schema;

    tracer.trace("start", options.name + "(" + schema.name + ")", stream.length, stream.length);
    var self = this;
    schema.fields.forEach(function (field) {

        var value = self[field.name];

        if (field.isArray) {

            var cursor_before = stream.length;
            var nb = stream.readUInt32();
            if (nb === 0xFFFFFFFF) {
                nb = 0;
            }
            options.name = field.name + [];

            tracer.trace("start_array", field.name, nb, cursor_before, stream.length);
            for (var i = 0; i < nb; i++) {
                tracer.trace("start_element", field.name, i);
                options.name = "element #" + i;

                _decode_member_(value, field, stream, options);

                tracer.trace("end_element", field.name, i);

            }
            tracer.trace("end_array", field.name, stream.length - 4);
        } else {

            options.name = field.name;
            _decode_member_(value, field, stream, options);

        }

    });

    tracer.trace("end", schema.name, stream.length, stream.length);
};

function r(str) {
    return (str + "                                ").substr(0, 30);
}

function apply_on_all_schema_fields(self, schema, data, callback , args) {

    assert(schema);
    var fields = schema.fields;
    var field, i, n = fields.length;
    for (i = 0; i < n; i++) {
        field = fields[i];
        callback(self, field, data , args);
    }
}

var _nb_elements = process.env.ARRAYLENGTH ? parseInt(process.env.NNN) : 10;

function _array_ellypsis(value,field) {

    if (!value) {
        return "null []";
    } else {
        if (value.length===0) {
            return "[ /* empty*/ ]";
        }
        assert(_.isArray(value));
        var v = [];
        var m = Math.min(_nb_elements, value.length);
        for (var i = 0; i < m; i++) {
            var element = value[i];
            v.push( !utils.isNullOrUndefined(element) ? element.toString() : null);
        }
        return "[ " + v.join(",") + ( value.length > 10 ? " ... " : "") + "] (l=" + value.length + ")";
    }
}

var _exploreObject = function (self, field, data, args) {

    if (!self) {
        return;
    }
    assert(self);

    var fieldType = field.fieldType;
    var fieldName = field.name;
    var category = field.category;

    var padding = data.padding;

    var value = self[fieldName];

    var str;

    var fieldName_f = r(padding + fieldName, 30).yellow;
    var fieldType_f = ("/* " + r(fieldType, 10) + ( field.isArray ? "[]" : "  ") + " */").cyan;

    // compact version of very usual objects
    if (fieldType === "QualifiedName" && !field.isArray && value) {

        value = value.toString() || "<null>";
        str = fieldName_f + " " + fieldType_f + ": " + value.toString().green;
        data.lines.push(str);
        return;
    }
    if (fieldType === "LocalizedText" && !field.isArray && value) {
        value = value.toString() || "<null>";
        str = fieldName_f + " " + fieldType_f + ": " + value.toString().green;
        data.lines.push(str);
        return;
    }

    var _dump_simple_value = function (self, field, data, value, fieldType) {

        var str = "";
        if (value instanceof Buffer) {

            var _hexDump = hexDump(value);
            data.lines.push(fieldName_f + " " + fieldType_f);
            data.lines.push("BUFFER{" + _hexDump + "}");

        } else {

            if (field.isArray) {

                str = fieldName_f + " " + fieldType_f + ": " + _array_ellypsis(value,field);

            } else {
                if (fieldType === "IntegerId" || fieldType === "UInt32") {

                    value = "" + value + "               0x" + value.toString(16);

                } else if (fieldType === "DateTime" || fieldType === "UtcTime") {
                    value = (value && value.toISOString) ? value.toISOString() : value;
                } else if (typeof value === "object" && value !== null) {
                    value = value.toString.apply(value,args);
                }
                str = fieldName_f + " " + fieldType_f + ": " + ((value === null) ? "null".blue.bold : value.toString());
            }
            data.lines.push(str);
        }

    };

    switch (category) {

        case "enumeration":

            str = fieldName_f + " " + fieldType_f + ": " + value.key + " ( " + value.value + ")";
            data.lines.push(str);

            break;

        case "basic":
            _dump_simple_value(self, field, data, value, fieldType);
            break;

        case "complex":
            if (field.subtype) {

                // this is a synonymous
                fieldType = field.subType;
                _dump_simple_value(self, field, data, value, fieldType);

            } else {
                var _new_desc = getFactory(fieldType).prototype._schema;

                if (field.isArray) {
                    if (value === null) {
                        data.lines.push(fieldName_f + " " + fieldType_f + ": null []");
                    } else if (value.length === 0) {
                        data.lines.push(fieldName_f + " " + fieldType_f + ": [ /* empty */ ]");
                    } else {
                        data.lines.push(fieldName_f + " " + fieldType_f + ": [");

                        var i = 0;

                        var m = Math.min(_nb_elements, value.length);
                        for (i = 0; i < m; i++) {
                            var element = value[i];
                            data.lines.push(padding + "  { " + ("/*" + i + "*/").cyan);

                            var data1 = {padding: padding + "    ", lines: []};
                            apply_on_all_schema_fields(element, _new_desc, data1, _exploreObject , args);
                            data.lines = data.lines.concat(data1.lines);

                            data.lines.push(padding + "  }" + ((i === value.length - 1) ? "" : ","));
                        }
                        if (m < value.length) {
                            data.lines.push(padding + " ..... ( " + value.length + " elements )");
                        }
                        data.lines.push(padding + "]");

                    }

                } else {

                    data.lines.push(fieldName_f + " " + fieldType_f + ": {");

                    data1 = {padding: padding + "  ", lines: []};
                    apply_on_all_schema_fields(value, _new_desc, data1, _exploreObject,args);
                    data.lines = data.lines.concat(data1.lines);

                    data.lines.push(padding + "}");
                }
            }

            break;
        default:
            throw new Error("internal error: unknown kind_of_field");
    }
};

BaseUAObject.prototype.explore = function () {

    var self = this;
    var data = {padding: " ", lines: []};
    data.lines.push("{" + (" /*" + this._schema.name + "*/").cyan);
    apply_on_all_schema_fields(self, self._schema, data, _exploreObject,arguments);
    data.lines.push("};");
    return data.lines.join("\n");
};

function _visit_schema_chain(self, schema, options, func, extra_data) {
    assert(_.isFunction(func));

    // apply also construct to baseType schema first
    var base_schema = get_base_schema(schema);
    if (base_schema) {
        _visit_schema_chain(self, base_schema, options, func, extra_data);
    }
    func.call(self, schema, options, extra_data);
}

function _JSONify(schema, options) {

    /* jshint validthis: true */
    var self = this;
    schema.fields.forEach(function (field) {
        var f = self[field.name];
        if (f === null || f === undefined) {
            return;
        }

        var t = _defaultTypeMap[field.fieldType];

        function jsonify(value) {

            if (_.isFunction(field.toJSON)) {
                return field.toJSON(value);
            } else if (t && t.toJSON) {
                return t.toJSON(value);
            } else if (value.toJSON) {
                return value.toJSON();
            } else {
                return f;
            }

        }

        if (field.isArray) {
            options[field.name] = f.map(jsonify);
        } else {
            options[field.name] = jsonify(f);
        }
    });
}

BaseUAObject.prototype.toJSON = function () {

    var self = this;

    assert(this._schema);
    if (this._schema.toJSON) {
        return this._schema.toJSON.apply(this, arguments);
    } else {
        //xx return Object.toJSON.apply(this,arguments);
        assert(self._schema);
        var schema = self._schema;
        var options = {};
        _visit_schema_chain(self, schema, options, _JSONify);
        return options;
    }
};

exports.BaseUAObject = BaseUAObject;
<|endoftext|>


<commit_before>/** @babel */

import {TOP, MIDDLE, BOTTOM} from './position';
import {OURS, THEIRS, BASE} from './source';
import Side from './side';
import Banner from './banner';
import Separator from './separator';

// Regular expression that matches the beginning of a potential conflict.
const CONFLICT_START_REGEX = /^<{7} (.+)\r?\n/g;

// Options used to create markers
const MARKER_OPTIONS = {invalidate: 'never'};

/*
 * Private: conflict parser visitor that ignores all events.
 */
class NoopVisitor {

  visitOurSide(position, bannerRow, textRowStart, textRowEnd) { }

  visitBaseSide(position, bannerRow, textRowStart, textRowEnd) { }

  visitSeparator(sepRowStart, sepRowEnd) { }

  visitTheirSide(position, bannerRow, textRowStart, textRowEnd) { }

}

/*
 * Private: conflict parser visitor that marks each buffer range and assembles a Conflict from the
 * pieces.
 */
class ConflictVisitor {

  /*
   * editor - [TextEditor] displaying the conflicting text.
   */
  constructor(editor) {
    this.editor = editor;

    this.ours = null;
    this.base = null;
    this.separator = null;
    this.theirs = null;
  }

  /*
   * position - [Position] one of TOP or BOTTOM.
   * bannerRow - [Integer] of the buffer row that contains our side's banner.
   * textRowStart - [Integer] of the first buffer row that contain this side's text.
   * textRowEnd - [Integer] of the first buffer row beyond the extend of this side's text.
   */
  visitOurSide(position, bannerRow, textRowStart, textRowEnd) {
    this.ours = this.markSide(position, OURS, bannerRow, textRowStart, textRowEnd);
  }

  /*
   * bannerRow - [Integer] the buffer row that contains our side's banner.
   * textRowStart - [Integer] first buffer row that contain this side's text.
   * textRowEnd - [Integer] first buffer row beyond the extend of this side's text.
   */
  visitBaseSide(bannerRow, textRowStart, textRowEnd) {
    this.base = this.markSide(MIDDLE, BASE, bannerRow, textRowStart, textRowEnd);
  }

  /*
   * sepRowStart - [Integer] buffer row that contains the "=======" separator.
   * sepRowEnd - [Integer] the buffer row after the separator.
   */
  visitSeparator(sepRowStart, sepRowEnd) {
    const marker = this.editor.markBufferRange([[sepRowStart, 0], [sepRowEnd, 0]], MARKER_OPTIONS);
    this.separator = new Separator(marker);
  }

  /*
   * position - [Position] alignment within the conflict marker: TOP or BOTTOM.
   * bannerRow - [Integer] the buffer row that contains our side's banner.
   * textRowStart - [Integer] first buffer row that contain this side's text.
   * textRowEnd - [Integer] first buffer row beyond the extent of this side's text.
   */
  visitTheirSide(position, bannerRow, textRowStart, textRowEnd) {
    this.theirs = this.markSide(position, THEIRS, bannerRow, textRowStart, textRowEnd);
  }

  markSide(position, source, bannerRow, textRowStart, textRowEnd) {
    const description = this.sideDescription(bannerRow);
    const bannerMarker = this.editor.markBufferRange([[bannerRow, 0], [bannerRow + 1, 0]], MARKER_OPTIONS);
    const banner = new Banner(bannerMarker, description);

    const textRange = [[textRowStart, 0], [textRowEnd, 0]];
    const sideMarker = this.editor.markBufferRange(textRange, MARKER_OPTIONS);
    const originalText = this.editor.getTextInBufferRange(textRange);

    return new Side(sideMarker, source, position, banner, originalText);
  }

  /*
   * Parse the banner description for the current side from a banner row.
   *
   * bannerRow - [Integer] buffer row containing the <, |, or > marker
   */
  sideDescription(bannerRow) {
    return this.editor.lineTextForBufferRow(bannerRow).match(/^[<|>]{7} (.*)$/)[1];
  }

  conflict() {
    return new Conflict(this.ours, this.separator, this.base, this.theirs);
  }

}

/*
 * Private: parseConflict discovers a git conflict marker in a corpus of text and constructs a Conflict instance that
 * marks the correct lines.
 *
 * editor [TextEditor] - editor on the buffer suspected to contain conflict markers.
 * startRow [Integer] - buffer row to begin scanning for conflict markers.
 * isRebase [Boolean] - true if the current merge is occurring as part of a rebase, false if it is not.
 * visitor [Visitor] - NoopVisitor or ConflictVisitor to visit row ranges of the conflict.
 *
 * Returns [Integer] the buffer row after the final <<<<<< boundary.
 */
const parseConflict = function(editor, startRow, isRebase, visitor) {
  let currentRow = startRow;
  let lastBoundary = null;

  // Visit a side that begins with a banner and description as its first line.
  const visitHeaderSide = (position, visitMethod) => {
    const sideRowStart = currentRow;
    currentRow++;
    advanceToBoundary('|=');
    const sideRowEnd = currentRow;

    visitor[visitMethod](position, sideRowStart, sideRowStart + 1, sideRowEnd);
  };

  // Visit the base side from diff3 output, if one is present, then visit the separator.
  const visitBaseAndSeparator = () => {
    if (lastBoundary === '|') {
      visitBaseSide();
    }

    visitSeparator();
  };

  // Visit a base side from diff3 output.
  const visitBaseSide = () => {
    const sideRowStart = currentRow;
    currentRow++;

    let b = advanceToBoundary('<=');
    while (b === '<') {
      // Embedded recursive conflict within a base side, caused by a criss-cross merge.
      // Advance beyond it without marking anything.
      currentRow = parseConflict(editor, currentRow, new NoopVisitor());
      b = advanceToBoundary('<=');
    }

    const sideRowEnd = currentRow;

    visitor.visitBaseSide(sideRowStart, sideRowStart + 1, sideRowEnd);
  };

  // Visit a "========" separator.
  const visitSeparator = () => {
    const sepRowStart = currentRow;
    currentRow++;
    const sepRowEnd = currentRow;

    visitor.visitSeparator(sepRowStart, sepRowEnd);
  };

  // Visit a side with a banner and description as its last line.
  const visitFooterSide = (position, visitMethod) => {
    const sideRowStart = currentRow;
    advanceToBoundary('>');
    currentRow++;
    const sideRowEnd = currentRow;

    visitor[visitMethod](position, sideRowEnd - 1, sideRowStart, sideRowEnd - 1);
  };

  // Determine if the current row is a side boundary.
  //
  // boundaryKinds - [String] any combination of <, |, =, or > to limit the kinds of boundary detected.
  //
  // Returns the matching boundaryKinds character, or `null` if none match.
  const isAtBoundary = (boundaryKinds = '<|=>') => {
    const line = editor.lineTextForBufferRow(currentRow);
    for (let i = 0; i < boundaryKinds.length; i++) {
      const b = boundaryKinds[i];
      if (line.startsWith(b.repeat(7))) {
        return b;
      }
    }
    return null;
  };

  // Increment the current row until the current line matches one of the provided boundary kinds, or until there are no
  // more lines in the editor.
  //
  // boundaryKinds - [String] any combination of <, |, =, or > to limit the kinds of boundaries that halt the
  //   progression.
  //
  // Returns the matching boundaryKinds character, or 'null' if there are no matches to the end of the editor.
  const advanceToBoundary = (boundaryKinds = '<|=>') => {
    let b = isAtBoundary(boundaryKinds);
    while (b === null) {
      currentRow++;
      if (currentRow > editor.getLastBufferRow()) {
        const e = new Error('Unterminated conflict side');
        e.parserState = true;
        throw e;
      }
      b = isAtBoundary(boundaryKinds);
    }

    lastBoundary = b;
    return b;
  };

  if (isRebase) {
    visitHeaderSide(TOP, 'visitTheirSide');
    visitBaseAndSeparator();
    visitFooterSide(BOTTOM, 'visitOurSide');
  } else {
    visitHeaderSide(TOP, 'visitOurSide');
    visitBaseAndSeparator();
    visitFooterSide(BOTTOM, 'visitTheirSide');
  }

  return currentRow;
};

export default class Conflict {

  constructor(ours, separator, base, theirs) {
    this.ours = ours;
    this.separator = separator;
    this.theirs = theirs;
    this.base = base;
  }

  /*
   * Public: Parse any conflict markers in a TextEditor's buffer and return a Conflict that contains markers
   * corresponding to each.
   *
   * editor [TextEditor] The editor to search.
   * return [Array<Conflict>] A (possibly empty) collection of parsed Conflicts.
   */
  static all(editor, isRebase) {
    const conflicts = [];
    let lastRow = -1;

    editor.getBuffer().scan(CONFLICT_START_REGEX, m => {
      const conflictStartRow = m.range.start.row;
      if (conflictStartRow < lastRow) {
        // Match within an already-parsed conflict.
        return;
      }

      const visitor = new ConflictVisitor(editor);

      try {
        lastRow = parseConflict(editor, conflictStartRow, isRebase, visitor);
        conflicts.push(visitor.conflict());
      } catch (e) {
        if (!e.parserState) {
          throw e;
        }

        if (!atom.inSpecMode()) {
          console.error(`Unable to parse conflict: ${e.message}\n${e.stack}`); // eslint-disable-line no-console
        }
      }
    });

    return conflicts;
  }

}
<commit_msg>Include isRebase parameter in recursive call<commit_after>/** @babel */

import {TOP, MIDDLE, BOTTOM} from './position';
import {OURS, THEIRS, BASE} from './source';
import Side from './side';
import Banner from './banner';
import Separator from './separator';

// Regular expression that matches the beginning of a potential conflict.
const CONFLICT_START_REGEX = /^<{7} (.+)\r?\n/g;

// Options used to create markers
const MARKER_OPTIONS = {invalidate: 'never'};

/*
 * Private: conflict parser visitor that ignores all events.
 */
class NoopVisitor {

  visitOurSide(position, bannerRow, textRowStart, textRowEnd) { }

  visitBaseSide(position, bannerRow, textRowStart, textRowEnd) { }

  visitSeparator(sepRowStart, sepRowEnd) { }

  visitTheirSide(position, bannerRow, textRowStart, textRowEnd) { }

}

/*
 * Private: conflict parser visitor that marks each buffer range and assembles a Conflict from the
 * pieces.
 */
class ConflictVisitor {

  /*
   * editor - [TextEditor] displaying the conflicting text.
   */
  constructor(editor) {
    this.editor = editor;

    this.ours = null;
    this.base = null;
    this.separator = null;
    this.theirs = null;
  }

  /*
   * position - [Position] one of TOP or BOTTOM.
   * bannerRow - [Integer] of the buffer row that contains our side's banner.
   * textRowStart - [Integer] of the first buffer row that contain this side's text.
   * textRowEnd - [Integer] of the first buffer row beyond the extend of this side's text.
   */
  visitOurSide(position, bannerRow, textRowStart, textRowEnd) {
    this.ours = this.markSide(position, OURS, bannerRow, textRowStart, textRowEnd);
  }

  /*
   * bannerRow - [Integer] the buffer row that contains our side's banner.
   * textRowStart - [Integer] first buffer row that contain this side's text.
   * textRowEnd - [Integer] first buffer row beyond the extend of this side's text.
   */
  visitBaseSide(bannerRow, textRowStart, textRowEnd) {
    this.base = this.markSide(MIDDLE, BASE, bannerRow, textRowStart, textRowEnd);
  }

  /*
   * sepRowStart - [Integer] buffer row that contains the "=======" separator.
   * sepRowEnd - [Integer] the buffer row after the separator.
   */
  visitSeparator(sepRowStart, sepRowEnd) {
    const marker = this.editor.markBufferRange([[sepRowStart, 0], [sepRowEnd, 0]], MARKER_OPTIONS);
    this.separator = new Separator(marker);
  }

  /*
   * position - [Position] alignment within the conflict marker: TOP or BOTTOM.
   * bannerRow - [Integer] the buffer row that contains our side's banner.
   * textRowStart - [Integer] first buffer row that contain this side's text.
   * textRowEnd - [Integer] first buffer row beyond the extent of this side's text.
   */
  visitTheirSide(position, bannerRow, textRowStart, textRowEnd) {
    this.theirs = this.markSide(position, THEIRS, bannerRow, textRowStart, textRowEnd);
  }

  markSide(position, source, bannerRow, textRowStart, textRowEnd) {
    const description = this.sideDescription(bannerRow);
    const bannerMarker = this.editor.markBufferRange([[bannerRow, 0], [bannerRow + 1, 0]], MARKER_OPTIONS);
    const banner = new Banner(bannerMarker, description);

    const textRange = [[textRowStart, 0], [textRowEnd, 0]];
    const sideMarker = this.editor.markBufferRange(textRange, MARKER_OPTIONS);
    const originalText = this.editor.getTextInBufferRange(textRange);

    return new Side(sideMarker, source, position, banner, originalText);
  }

  /*
   * Parse the banner description for the current side from a banner row.
   *
   * bannerRow - [Integer] buffer row containing the <, |, or > marker
   */
  sideDescription(bannerRow) {
    return this.editor.lineTextForBufferRow(bannerRow).match(/^[<|>]{7} (.*)$/)[1];
  }

  conflict() {
    return new Conflict(this.ours, this.separator, this.base, this.theirs);
  }

}

/*
 * Private: parseConflict discovers a git conflict marker in a corpus of text and constructs a Conflict instance that
 * marks the correct lines.
 *
 * editor [TextEditor] - editor on the buffer suspected to contain conflict markers.
 * startRow [Integer] - buffer row to begin scanning for conflict markers.
 * isRebase [Boolean] - true if the current merge is occurring as part of a rebase, false if it is not.
 * visitor [Visitor] - NoopVisitor or ConflictVisitor to visit row ranges of the conflict.
 *
 * Returns [Integer] the buffer row after the final <<<<<< boundary.
 */
const parseConflict = function(editor, startRow, isRebase, visitor) {
  let currentRow = startRow;
  let lastBoundary = null;

  // Visit a side that begins with a banner and description as its first line.
  const visitHeaderSide = (position, visitMethod) => {
    const sideRowStart = currentRow;
    currentRow++;
    advanceToBoundary('|=');
    const sideRowEnd = currentRow;

    visitor[visitMethod](position, sideRowStart, sideRowStart + 1, sideRowEnd);
  };

  // Visit the base side from diff3 output, if one is present, then visit the separator.
  const visitBaseAndSeparator = () => {
    if (lastBoundary === '|') {
      visitBaseSide();
    }

    visitSeparator();
  };

  // Visit a base side from diff3 output.
  const visitBaseSide = () => {
    const sideRowStart = currentRow;
    currentRow++;

    let b = advanceToBoundary('<=');
    while (b === '<') {
      // Embedded recursive conflict within a base side, caused by a criss-cross merge.
      // Advance beyond it without marking anything.
      currentRow = parseConflict(editor, currentRow, isRebase, new NoopVisitor());
      b = advanceToBoundary('<=');
    }

    const sideRowEnd = currentRow;

    visitor.visitBaseSide(sideRowStart, sideRowStart + 1, sideRowEnd);
  };

  // Visit a "========" separator.
  const visitSeparator = () => {
    const sepRowStart = currentRow;
    currentRow++;
    const sepRowEnd = currentRow;

    visitor.visitSeparator(sepRowStart, sepRowEnd);
  };

  // Visit a side with a banner and description as its last line.
  const visitFooterSide = (position, visitMethod) => {
    const sideRowStart = currentRow;
    advanceToBoundary('>');
    currentRow++;
    const sideRowEnd = currentRow;

    visitor[visitMethod](position, sideRowEnd - 1, sideRowStart, sideRowEnd - 1);
  };

  // Determine if the current row is a side boundary.
  //
  // boundaryKinds - [String] any combination of <, |, =, or > to limit the kinds of boundary detected.
  //
  // Returns the matching boundaryKinds character, or `null` if none match.
  const isAtBoundary = (boundaryKinds = '<|=>') => {
    const line = editor.lineTextForBufferRow(currentRow);
    for (let i = 0; i < boundaryKinds.length; i++) {
      const b = boundaryKinds[i];
      if (line.startsWith(b.repeat(7))) {
        return b;
      }
    }
    return null;
  };

  // Increment the current row until the current line matches one of the provided boundary kinds, or until there are no
  // more lines in the editor.
  //
  // boundaryKinds - [String] any combination of <, |, =, or > to limit the kinds of boundaries that halt the
  //   progression.
  //
  // Returns the matching boundaryKinds character, or 'null' if there are no matches to the end of the editor.
  const advanceToBoundary = (boundaryKinds = '<|=>') => {
    let b = isAtBoundary(boundaryKinds);
    while (b === null) {
      currentRow++;
      if (currentRow > editor.getLastBufferRow()) {
        const e = new Error('Unterminated conflict side');
        e.parserState = true;
        throw e;
      }
      b = isAtBoundary(boundaryKinds);
    }

    lastBoundary = b;
    return b;
  };

  if (isRebase) {
    visitHeaderSide(TOP, 'visitTheirSide');
    visitBaseAndSeparator();
    visitFooterSide(BOTTOM, 'visitOurSide');
  } else {
    visitHeaderSide(TOP, 'visitOurSide');
    visitBaseAndSeparator();
    visitFooterSide(BOTTOM, 'visitTheirSide');
  }

  return currentRow;
};

export default class Conflict {

  constructor(ours, separator, base, theirs) {
    this.ours = ours;
    this.separator = separator;
    this.theirs = theirs;
    this.base = base;
  }

  /*
   * Public: Parse any conflict markers in a TextEditor's buffer and return a Conflict that contains markers
   * corresponding to each.
   *
   * editor [TextEditor] The editor to search.
   * return [Array<Conflict>] A (possibly empty) collection of parsed Conflicts.
   */
  static all(editor, isRebase) {
    const conflicts = [];
    let lastRow = -1;

    editor.getBuffer().scan(CONFLICT_START_REGEX, m => {
      const conflictStartRow = m.range.start.row;
      if (conflictStartRow < lastRow) {
        // Match within an already-parsed conflict.
        return;
      }

      const visitor = new ConflictVisitor(editor);

      try {
        lastRow = parseConflict(editor, conflictStartRow, isRebase, visitor);
        conflicts.push(visitor.conflict());
      } catch (e) {
        if (!e.parserState) {
          throw e;
        }

        if (!atom.inSpecMode()) {
          console.error(`Unable to parse conflict: ${e.message}\n${e.stack}`); // eslint-disable-line no-console
        }
      }
    });

    return conflicts;
  }

}
<|endoftext|>