text:
/*globals define, _, WebGMEGlobal*/
/*jshint browser: true*/
/**
 * @author rkereskenyi / https://github.com/rkereskenyi
 */

define(['js/logger',
    'js/RegistryKeys',
    'js/Constants',
    './CrosscutConstants',
    'js/DragDrop/DragHelper',
    'js/Utils/GMEConcepts',
    'js/Panels/ControllerBase/DiagramDesignerWidgetMultiTabMemberListControllerBase',
    'js/Panels/MetaEditor/MetaRelations',
    'js/NodePropertyNames'
], function (Logger,
             REGISTRY_KEYS,
             CONSTANTS,
             CrosscutConstants,
             DragHelper,
             GMEConcepts,
             DiagramDesignerWidgetMultiTabMemberListControllerBase,
             MetaRelations,
             nodePropertyNames) {

    'use strict';

    var CrosscutController,
        DEFAULT_DECORATOR = 'ModelDecorator',
        WIDGET_NAME = 'DiagramDesigner',
        CONNECTION_DECORATOR = 'CircleDecorator';

    CrosscutController = function (options) {
        options = options || {};
        options.loggerName = 'gme:Panels:CrossCut:CrosscutController';

        DiagramDesignerWidgetMultiTabMemberListControllerBase.call(this, options);

        this._filteredOutConnTypes = [];
        this._filteredOutConnectionDescriptors = {};

        this.logger.debug('CrosscutController ctor finished');
    };

    _.extend(CrosscutController.prototype, DiagramDesignerWidgetMultiTabMemberListControllerBase.prototype);

    CrosscutController.prototype._attachDiagramDesignerWidgetEventHandlers = function () {
        var self = this;

        //cal base classes _attachDiagramDesignerWidgetEventHandlers
        DiagramDesignerWidgetMultiTabMemberListControllerBase.prototype
            ._attachDiagramDesignerWidgetEventHandlers.call(this);

        //add own event handlers

        this._widget.onFilterNewConnectionDroppableEnds = function (params) {
            return self._onFilterNewConnectionDroppableEnds(params);
        };

        this._widget.onCreateNewConnection = function (params) {
            self._onCreateNewConnection(params);
        };
    };

    //enable every node
    CrosscutController.prototype._validateNodeId = function (nodeId) {
        return nodeId;
    };

    CrosscutController.prototype._canAddTab = function () {
        var memberListContainerID = this._memberListContainerID;

        return (memberListContainerID || memberListContainerID === CONSTANTS.PROJECT_ROOT_ID);
    };

    CrosscutController.prototype._updateSelectedMemberListMembersTerritoryPatterns = function () {
        var currentlyDisplayedMembers = (this._selectedMemberListMembers || []).slice(0),
            actualMembers = (this._memberListMembers[this._selectedMemberListID] || []).slice(0),
            diff,
            len,
            territoryChanged = false,
            territoryId = this._selectedMemberListMembersTerritoryId,
            territoryPatterns = this._selectedMemberListMembersTerritoryPatterns,
            client = this._client;

        //let's see who has been deleted
        diff = _.difference(currentlyDisplayedMembers, actualMembers);
        len = diff.length;
        while (len--) {
            delete territoryPatterns[diff[len]];
            territoryChanged = true;
        }

        //let's see who has been added
        diff = _.difference(actualMembers, currentlyDisplayedMembers);
        len = diff.length;
        while (len--) {
            territoryPatterns[diff[len]] = {children: 0};
            territoryChanged = true;
        }

        //let's update the one that has not been changed but their position might have
        diff = _.intersection(actualMembers, currentlyDisplayedMembers);
        len = diff.length;
        this._widget.beginUpdate();
        while (len--) {
            this._onUpdate(diff[len]);
        }
        this._widget.endUpdate();

        //save current list of members
        this._selectedMemberListMembers = actualMembers;

        if (territoryChanged) {
            setTimeout(function () {
                client.updateTerritory(territoryId, territoryPatterns);
            }, 10);
        }
    };

    CrosscutController.prototype._initializeSelectedMemberList = function () {
        this._nodePointers = {};
        this._nodeSets = {};

        this._connectionListByType = {};

        DiagramDesignerWidgetMultiTabMemberListControllerBase.prototype._initializeSelectedMemberList.call(this);
    };

    CrosscutController.prototype._memberListTerritoryCallback = function (events) {
        var decoratorsToDownload = [DEFAULT_DECORATOR],
            len = events.length,
            obj,
            objDecorator,
            client = this._client,
            self = this;

        while (len--) {
            if ((events[len].etype === CONSTANTS.TERRITORY_EVENT_LOAD) ||
                (events[len].etype === CONSTANTS.TERRITORY_EVENT_UPDATE)) {

                obj = client.getNode(events[len].eid);

                events[len].desc = {isConnection: GMEConcepts.isConnection(events[len].eid)};

                if (obj) {
                    //if it is a connection find src and dst and do not care about decorator
                    if (events[len].desc.isConnection === true) {
                        objDecorator = CONNECTION_DECORATOR;
                        events[len].desc.isConnection = false;
                        events[len].desc.decoratorParams = {displayName: false};
                    } else {
                        objDecorator = obj.getRegistry(REGISTRY_KEYS.DECORATOR);
                    }

                    if (!objDecorator ||
                        objDecorator === '') {
                        objDecorator = DEFAULT_DECORATOR;
                    }

                    if (decoratorsToDownload.indexOf(objDecorator) === -1) {
                        decoratorsToDownload.pushUnique(objDecorator);
                    }

                    events[len].desc.decorator = objDecorator;
                }
            }
        }

        client.decoratorManager.download(decoratorsToDownload, WIDGET_NAME, function () {
            self._dispatchEvents(events);
        });
    };

    CrosscutController.prototype.getOrderedMemberListInfo = function (/* memberListContainerObject */) {
        var result = [],
            memberListContainerID = this._memberListContainerID,
            crosscutsRegistry = GMEConcepts.getCrosscuts(memberListContainerID),
            len = crosscutsRegistry.length;

        while (len--) {
            result.push({
                memberListID: crosscutsRegistry[len].SetID,
                title: crosscutsRegistry[len].title,
                enableDeleteTab: true,
                enableRenameTab: true
            });
        }

        result.sort(function (a, b) {
            if (a.order < b.order) {
                return -1;
            } else {
                return 1;
            }
        });

        return result;
    };

    CrosscutController.prototype.getMemberListSetsRegistryKey = function () {
        return REGISTRY_KEYS.CROSSCUTS;
    };

    CrosscutController.prototype.getNewSetNamePrefixDesc = function () {
        return {
            SetID: CrosscutConstants.CROSSCUT_NAME_PREFIX,
            Title: 'Crosscut '
        };
    };

    /*
     * Overwrite 'no tab' warning message to the user
     */
    CrosscutController.prototype.displayNoTabMessage = function () {
        this._widget.setBackgroundText('No crosscuts defined yet. Press the + button in the top-left corner to ' +
        'create one...');
    };

    /**********************************************************/
    /*         HANDLE OBJECT DRAG & DROP ACCEPTANCE           */
    /**********************************************************/
    CrosscutController.prototype._onBackgroundDroppableAccept = function (event, dragInfo) {
        var gmeIDList = DragHelper.getDragItems(dragInfo),
            accept = DiagramDesignerWidgetMultiTabMemberListControllerBase.prototype._onBackgroundDroppableAccept.call(
                this, event, dragInfo);

        if (accept === true) {
            //if based on the DiagramDesignerWidgetMultiTabMemberListControllerBase check it could be accepted,
            // ie items are not members of the set so far
            //we need to see if we can accept them based on the META rules
            accept = GMEConcepts.isValidChildrenTypeInCrossCut(this._memberListContainerID, gmeIDList);
        }

        return accept;
    };
    /**********************************************************/
    /*  END OF --- HANDLE OBJECT DRAG & DROP ACCEPTANCE       */
    /**********************************************************/

    CrosscutController.prototype._dispatchEvents = function (events) {
        var i,
            e,
            territoryChanged = false;

        this.logger.debug('_dispatchEvents "' + events.length + '" items: ' + JSON.stringify(events));

        this._widget.beginUpdate();

        this._notifyPackage = {};

        //item insert/update/unload & connection unload
        for (i = 0; i < events.length; i += 1) {
            e = events[i];
            switch (e.etype) {
                case CONSTANTS.TERRITORY_EVENT_LOAD:
                    territoryChanged = this._onLoad(e.eid, e.desc) || territoryChanged;
                    break;
                case CONSTANTS.TERRITORY_EVENT_UPDATE:
                    this._onUpdate(e.eid);
                    break;
                case CONSTANTS.TERRITORY_EVENT_UNLOAD:
                    territoryChanged = this._onUnload(e.eid) || territoryChanged;
                    break;
                default:
                    break;
            }
        }

        this._handleDecoratorNotification();

        this._widget.endUpdate();

        this._widget.hideProgressbar();

        //update the territory
        if (territoryChanged) {
            this.logger.debug('Updating territory with ruleset from decorators: ' + JSON.stringify(this._selfPatterns));

            this._client.updateTerritory(this._selectedMemberListMembersTerritoryId,
                this._selectedMemberListMembersTerritoryPatterns);
        }

        this.logger.debug('_dispatchEvents "' + events.length + '" items - DONE');
    };

    CrosscutController.prototype._onLoad = function (gmeID, desc) {
        var territoryChanged;

        desc.isConnection = false;

        territoryChanged = DiagramDesignerWidgetMultiTabMemberListControllerBase.prototype._onLoad.call(this,
            gmeID,
            desc);

        //process new node to display containment / pointers / inheritance / sets as connections
        this._processNodePointers(gmeID, false);
        this._processNodePointers(gmeID, true);

        //check all the waiting pointers (whose SRC/DST is already displayed and waiting for the DST/SRC to show up)
        //it might be this new node
        this._processConnectionWaitingList(gmeID);

        return territoryChanged;
    };

    CrosscutController.prototype._onUpdate = function (gmeID, desc) {
        //component updated
        desc = desc || {};
        desc.isConnection = false;

        //we are interested in the load of member items and their custom territory involvement
        if (this._selectedMemberListMembers.indexOf(gmeID) !== -1 &&
            this._GMEID2ComponentID[gmeID]) {
            DiagramDesignerWidgetMultiTabMemberListControllerBase.prototype._onUpdate.call(this, gmeID, desc);

            //process new node to display containment / pointers / inheritance / sets as connections
            this._processNodePointers(gmeID, false);
            this._processNodePointers(gmeID, true);

            //check all the waiting pointers (whose SRC/DST is already displayed and waiting for the DST/SRC to show up)
            //it might be this new node
            this._processConnectionWaitingList(gmeID);
        }
    };

    CrosscutController.prototype._onUnload = function (gmeID) {
        var componentID,
            len,
            territoryChanged = false,
            aConns,
            connectionID,
            pointerName,
            otherEnd;

        if (this._GMEID2ComponentID.hasOwnProperty(gmeID)) {

            //gather all the information that is stored in this node's META

            //POINTERS
            len = this._nodePointers[gmeID].combinedNames.length;
            while (len--) {
                pointerName = this._nodePointers[gmeID].combinedNames[len];
                otherEnd = this._nodePointers[gmeID][pointerName].target;
                pointerName = this._nodePointers[gmeID][pointerName].name;
                this._removeConnection(gmeID, otherEnd, MetaRelations.META_RELATIONS.POINTER, pointerName);
            }

            //POINTER LISTS
            len = this._nodeSets[gmeID].combinedNames.length;
            while (len--) {
                pointerName = this._nodeSets[gmeID].combinedNames[len];
                otherEnd = this._nodeSets[gmeID][pointerName].target;
                pointerName = this._nodeSets[gmeID][pointerName].name;
                this._removeConnection(gmeID, otherEnd, MetaRelations.META_RELATIONS.SET, pointerName);
            }

            len = this._GMEID2ComponentID[gmeID].length;
            while (len--) {
                componentID = this._GMEID2ComponentID[gmeID][len];

                if (this._widget.itemIds.indexOf(componentID) !== -1) {
                    territoryChanged = territoryChanged ||
                    this._updateDecoratorTerritoryQuery(
                        this._widget.items[componentID]._decoratorInstance, true);
                }

                this._widget.deleteComponent(componentID);

                delete this._ComponentID2GMEID[componentID];
            }

            delete this._GMEID2ComponentID[gmeID];
        }

        //check if one of the decorators' is dependent on this
        this._checkComponentDependency(gmeID, CONSTANTS.TERRITORY_EVENT_UNLOAD);

        //check if there is any more connection present that's associated with this object
        //typically the connection end is this guy
        //if so, remove but save to savedList
        aConns = this._getAssociatedConnections(gmeID);
        len = aConns.src.length;
        while (len--) {
            connectionID = aConns.src[len];
            //save the connection to the waiting list, since the destination is still there
            this._saveConnectionToWaitingList(this._connectionListByID[connectionID].GMESrcId,
                this._connectionListByID[connectionID].GMEDstId,
                this._connectionListByID[connectionID].type,
                this._connectionListByID[connectionID].connTexts);
            this._removeConnection(this._connectionListByID[connectionID].GMESrcId,
                this._connectionListByID[connectionID].GMEDstId,
                this._connectionListByID[connectionID].type);
        }

        len = aConns.dst.length;
        while (len--) {
            connectionID = aConns.dst[len];
            if (this._connectionListByID[connectionID]) {
                //save the connection to the waiting list, since the destination is still there
                this._saveConnectionToWaitingList(this._connectionListByID[connectionID].GMESrcId,
                    this._connectionListByID[connectionID].GMEDstId,
                    this._connectionListByID[connectionID].type,
                    this._connectionListByID[connectionID].connTexts);
                this._removeConnection(this._connectionListByID[connectionID].GMESrcId,
                    this._connectionListByID[connectionID].GMEDstId,
                    this._connectionListByID[connectionID].type);
            }
        }

        //check the waiting list and remove any connection that was waiting and this end was present
        for (otherEnd in this._connectionWaitingListBySrcGMEID) {
            if (this._connectionWaitingListBySrcGMEID.hasOwnProperty(otherEnd)) {
                delete this._connectionWaitingListBySrcGMEID[otherEnd][gmeID];

                if (_.isEmpty(this._connectionWaitingListBySrcGMEID[otherEnd])) {
                    delete this._connectionWaitingListBySrcGMEID[otherEnd];
                }
            }
        }

        for (otherEnd in this._connectionWaitingListByDstGMEID) {
            if (this._connectionWaitingListByDstGMEID.hasOwnProperty(otherEnd)) {
                delete this._connectionWaitingListByDstGMEID[otherEnd][gmeID];

                if (_.isEmpty(this._connectionWaitingListByDstGMEID[otherEnd])) {
                    delete this._connectionWaitingListByDstGMEID[otherEnd];
                }
            }
        }

        //keep up accounting
        delete this._nodePointers[gmeID];
        delete this._nodeSets[gmeID];

        return territoryChanged;
    };

    CrosscutController.prototype._getAssociatedConnections = function (objectID) {
        var result = {src: [], dst: []},
            otherID,
            connType,
            len,
            cID,
            checkConnections;

        checkConnections = function (cList, res) {
            //check objectID as source
            if (cList.hasOwnProperty(objectID)) {
                for (otherID in cList[objectID]) {
                    if (cList[objectID].hasOwnProperty(otherID)) {
                        for (connType in cList[objectID][otherID]) {
                            if (cList[objectID][otherID].hasOwnProperty(connType)) {
                                len = cList[objectID][otherID][connType].length;
                                while (len--) {
                                    cID = cList[objectID][otherID][connType][len];
                                    if (res.indexOf(cID) === -1) {
                                        res.push(cID);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        };

        checkConnections(this._connectionListBySrcGMEID, result.src);
        checkConnections(this._connectionListByDstGMEID, result.dst);

        return result;
    };

    /*******************************************************************************/
    /*  DISPLAY META POINTER RELATIONS AS A CONNECTION FROM CONTAINER TO CONTAINED */
    /*******************************************************************************/
    CrosscutController.prototype._processNodePointers = function (gmeID, isSet) {
        var node = this._client.getNode(gmeID),
            pointerNames = isSet === true ? node.getSetNames() : node.getPointerNames(),
            pointerTo,
            len,
            oldPointers,
            newPointers = {names: [], combinedNames: []},
            diff,
            pointerTarget,
            pointerName,
            idx,
            combinedName,
            ptrType = isSet === true ? MetaRelations.META_RELATIONS.SET : MetaRelations.META_RELATIONS.POINTER;

        if (isSet === true) {
            this._nodeSets[gmeID] = this._nodeSets[gmeID] || {names: [], combinedNames: []};
            oldPointers = this._nodeSets[gmeID];
        } else {
            this._nodePointers[gmeID] = this._nodePointers[gmeID] || {names: [], combinedNames: []};
            oldPointers = this._nodePointers[gmeID];
        }

        len = pointerNames.length;
        while (len--) {
            if (pointerNames[len] !== CONSTANTS.POINTER_BASE) {
                pointerTo = node.getPointer(pointerNames[len]).to;

                if (pointerTo) {
                    combinedName = gmeID + '_' + pointerNames[len] + '_' + pointerTo;

                    newPointers.names.push(pointerNames[len]);

                    newPointers.combinedNames.push(combinedName);

                    newPointers[combinedName] = {
                        name: pointerNames[len],
                        target: pointerTo
                    };
                }
            }
        }

        //base and parent are special relations and they also needs to be added when not checked for sets
        if (!isSet) {
            pointerTo = node.getParentId();
            if (typeof pointerTo === 'string') {
                combinedName = gmeID + '_' + CONSTANTS.RELATION_CONTAINMENT + '_' + pointerTo;
                newPointers.names.push(CONSTANTS.RELATION_CONTAINMENT);
                newPointers.combinedNames.push(combinedName);
                newPointers[combinedName] = {name: CONSTANTS.RELATION_CONTAINMENT, target: pointerTo};
            }

            pointerTo = node.getBaseId();
            if (typeof pointerTo === 'string') {
                combinedName = gmeID + '_' + CONSTANTS.POINTER_BASE + '_' + pointerTo;
                newPointers.names.push(CONSTANTS.POINTER_BASE);
                newPointers.combinedNames.push(combinedName);
                newPointers[combinedName] = {name: CONSTANTS.POINTER_BASE, target: pointerTo};
            }
        }

        //compute deleted pointers
        diff = _.difference(oldPointers.combinedNames, newPointers.combinedNames);
        len = diff.length;
        while (len--) {
            combinedName = diff[len];
            pointerName = oldPointers[combinedName].name;
            pointerTarget = oldPointers[combinedName].target;

            this._removeConnection(gmeID, pointerTarget, ptrType, pointerName);

            idx = oldPointers.combinedNames.indexOf(combinedName);
            oldPointers.combinedNames.splice(idx, 1);
            delete oldPointers[combinedName];
        }

        //compute added pointers
        diff = _.difference(newPointers.combinedNames, oldPointers.combinedNames);
        len = diff.length;
        while (len--) {
            combinedName = diff[len];
            pointerName = newPointers[combinedName].name;
            pointerTarget = newPointers[combinedName].target;

            oldPointers.names.push(pointerName);
            oldPointers.combinedNames.push(combinedName);
            oldPointers[combinedName] = {
                name: newPointers[combinedName].name,
                target: newPointers[combinedName].target
            };

            this._createConnection(gmeID, pointerTarget, ptrType, {name: pointerName});
        }
    };
    /******************************************************************************************/
    /*  END OF --- DISPLAY META POINTER RELATIONS AS A CONNECTION FROM CONTAINER TO CONTAINED */
    /******************************************************************************************/

    CrosscutController.prototype._processConnectionWaitingList = function (gmeID) {
        var len,
            gmeSrcID,
            gmeDstID,
            connType,
            connTexts,
            c = [];

        //check for possible endpoint as gmeID
        gmeDstID = gmeID;
        if (this._connectionWaitingListByDstGMEID && this._connectionWaitingListByDstGMEID.hasOwnProperty(gmeDstID)) {
            for (gmeSrcID in this._connectionWaitingListByDstGMEID[gmeDstID]) {
                if (this._connectionWaitingListByDstGMEID[gmeDstID].hasOwnProperty(gmeSrcID)) {
                    len = this._connectionWaitingListByDstGMEID[gmeDstID][gmeSrcID].length;
                    while (len--) {
                        connType = this._connectionWaitingListByDstGMEID[gmeDstID][gmeSrcID][len][0];
                        connTexts = this._connectionWaitingListByDstGMEID[gmeDstID][gmeSrcID][len][1];
                        c.push({
                            gmeSrcID: gmeSrcID,
                            gmeDstID: gmeDstID,
                            connType: connType,
                            connTexts: connTexts
                        });
                    }
                }
            }

            delete this._connectionWaitingListByDstGMEID[gmeDstID];
        }

        //check for possible source as gmeID
        gmeSrcID = gmeID;
        if (this._connectionWaitingListBySrcGMEID && this._connectionWaitingListBySrcGMEID.hasOwnProperty(gmeSrcID)) {
            for (gmeDstID in this._connectionWaitingListBySrcGMEID[gmeSrcID]) {
                if (this._connectionWaitingListBySrcGMEID[gmeSrcID].hasOwnProperty(gmeDstID)) {
                    len = this._connectionWaitingListBySrcGMEID[gmeSrcID][gmeDstID].length;
                    while (len--) {
                        connType = this._connectionWaitingListBySrcGMEID[gmeSrcID][gmeDstID][len][0];
                        connTexts = this._connectionWaitingListBySrcGMEID[gmeSrcID][gmeDstID][len][1];
                        c.push({
                            gmeSrcID: gmeSrcID,
                            gmeDstID: gmeDstID,
                            connType: connType,
                            connTexts: connTexts
                        });
                    }
                }
            }

            delete this._connectionWaitingListBySrcGMEID[gmeSrcID];
        }

        len = c.length;
        while (len--) {
            gmeSrcID = c[len].gmeSrcID;
            gmeDstID = c[len].gmeDstID;
            connType = c[len].connType;
            connTexts = c[len].connTexts;
            this._createConnection(gmeSrcID, gmeDstID, connType, connTexts);
        }
    };
    /**************************************************************************/
    /*  END OF --- HANDLE OBJECT LOAD DISPLAY IT WITH ALL THE POINTERS / ...  */
    /**************************************************************************/

    /****************************************************************************/
    /*  CREATE A SPECIFIC TYPE OF CONNECTION BETWEEN 2 GME OBJECTS              */
    /****************************************************************************/
    CrosscutController.prototype._createConnection = function (gmeSrcId, gmeDstId, connType, connTexts) {
        var connDesc,
            connComponent,
            visualType;
        //need to check if the src and dst objects are displayed or not
        //if YES, create connection
        //if NO, store information in a waiting queue

        if (this._GMEID2ComponentID[gmeSrcId] && this._GMEID2ComponentID[gmeSrcId].length > 0 &&
            this._GMEID2ComponentID[gmeDstId] && this._GMEID2ComponentID[gmeDstId].length > 0) {
            //source and destination is displayed

            if (this._filteredOutConnTypes.indexOf(connType) === -1) {
                //connection type is not filtered out
                connDesc = {
                    srcObjId: this._GMEID2ComponentID[gmeSrcId][0],
                    srcSubCompId: undefined,
                    dstObjId: this._GMEID2ComponentID[gmeDstId][0],
                    dstSubCompId: undefined,
                    reconnectable: false,
                    name: '',
                    nameEdit: false
                };

                //set visual properties
                visualType = connType;
                if (connTexts) {
                    switch (connTexts.name) {
                        case CONSTANTS.POINTER_BASE:
                            visualType = MetaRelations.META_RELATIONS.INHERITANCE;
                            //TODO here the inheritance relations drawn in opposite direction
                            // TODO so we have to switch src and dst to be able to use the same visual style
                            connDesc.srcObjId = this._GMEID2ComponentID[gmeDstId][0];
                            connDesc.dstObjId = this._GMEID2ComponentID[gmeSrcId][0];
                            break;
                        case CONSTANTS.RELATION_CONTAINMENT:
                            visualType = MetaRelations.META_RELATIONS.CONTAINMENT;
                            connDesc.srcObjId = this._GMEID2ComponentID[gmeDstId][0];
                            connDesc.dstObjId = this._GMEID2ComponentID[gmeSrcId][0];
                            break;
                        default:
                            break;
                    }
                }

                _.extend(connDesc, MetaRelations.getLineVisualDescriptor(visualType));

                //fill out texts
                if (connTexts) {
                    _.extend(connDesc, connTexts);
                }

                connComponent = this._widget.createConnection(connDesc);

                this._saveConnection(gmeSrcId, gmeDstId, connType, connComponent.id, connTexts);
            } else {
                //connection type is filtered out
                this._filteredOutConnectionDescriptors[connType].push([gmeSrcId, gmeDstId, connTexts]);
            }
        } else {
            //source or destination is not displayed, store it in a queue
            this._saveConnectionToWaitingList(gmeSrcId, gmeDstId, connType, connTexts);
        }
    };

    CrosscutController.prototype._saveConnectionToWaitingList = function (gmeSrcId, gmeDstId, connType, connTexts) {
        var scrDisplayed = this._GMEID2ComponentID[gmeSrcId] && this._GMEID2ComponentID[gmeSrcId].length > 0,
            dstDisplayed = this._GMEID2ComponentID[gmeDstId] && this._GMEID2ComponentID[gmeDstId].length > 0;

        if (scrDisplayed && !dstDisplayed) {
            //#1 - the destination object is missing from the screen
            this._connectionWaitingListByDstGMEID[gmeDstId] = this._connectionWaitingListByDstGMEID[gmeDstId] || {};

            this._connectionWaitingListByDstGMEID[gmeDstId][gmeSrcId] =
                this._connectionWaitingListByDstGMEID[gmeDstId][gmeSrcId] || [];

            this._connectionWaitingListByDstGMEID[gmeDstId][gmeSrcId].push([connType, connTexts]);
        } else if (!scrDisplayed && dstDisplayed) {
            //#2 -  the source object is missing from the screen
            this._connectionWaitingListBySrcGMEID[gmeSrcId] = this._connectionWaitingListBySrcGMEID[gmeSrcId] || {};

            this._connectionWaitingListBySrcGMEID[gmeSrcId][gmeDstId] =
                this._connectionWaitingListBySrcGMEID[gmeSrcId][gmeDstId] || [];

            this._connectionWaitingListBySrcGMEID[gmeSrcId][gmeDstId].push([connType, connTexts]);
        } else {
            //#3 - both gmeSrcId and gmeDstId is missing from the screen
            //NOTE: this should never happen!!!
            //this.logger.error('_saveConnectionToWaitingList both gmeSrcId and gmeDstId is undefined...');
        }
    };

    CrosscutController.prototype._saveConnection = function (gmeSrcId, gmeDstId, connType, connComponentId, connTexts) {
        //save by SRC
        this._connectionListBySrcGMEID[gmeSrcId] = this._connectionListBySrcGMEID[gmeSrcId] || {};
        this._connectionListBySrcGMEID[gmeSrcId][gmeDstId] = this._connectionListBySrcGMEID[gmeSrcId][gmeDstId] || {};

        this._connectionListBySrcGMEID[gmeSrcId][gmeDstId][connType] =
            this._connectionListBySrcGMEID[gmeSrcId][gmeDstId][connType] || [];
        this._connectionListBySrcGMEID[gmeSrcId][gmeDstId][connType].push(connComponentId);

        //save by DST
        this._connectionListByDstGMEID[gmeDstId] = this._connectionListByDstGMEID[gmeDstId] || {};
        this._connectionListByDstGMEID[gmeDstId][gmeSrcId] = this._connectionListByDstGMEID[gmeDstId][gmeSrcId] || {};

        this._connectionListByDstGMEID[gmeDstId][gmeSrcId][connType] =
            this._connectionListByDstGMEID[gmeDstId][gmeSrcId][connType] || [];

        this._connectionListByDstGMEID[gmeDstId][gmeSrcId][connType].push(connComponentId);

        //save by type
        this._connectionListByType[connType] = this._connectionListByType[connType] || [];
        this._connectionListByType[connType].push(connComponentId);

        //save by connectionID
        this._connectionListByID[connComponentId] = {
            GMESrcId: gmeSrcId,
            GMEDstId: gmeDstId,
            type: connType,
            name: (connTexts && connTexts.name) ? connTexts.name : undefined,
            connTexts: connTexts
        };
    };
    /****************************************************************************/
    /*  END OF --- CREATE A SPECIFIC TYPE OF CONNECTION BETWEEN 2 GME OBJECTS   */
    /****************************************************************************/

    /****************************************************************************/
    /*  REMOVES A SPECIFIC TYPE OF CONNECTION FROM 2 GME OBJECTS                */
    /****************************************************************************/
    CrosscutController.prototype._removeConnection = function (gmeSrcId, gmeDstId, connType, pointerName) {
        var connectionID,
            idx,
            len,
            connectionPresent = false;

        //only bother if
        //- both the source and destination is present on the screen
        //the connection in question is drawn
        if (this._connectionListBySrcGMEID[gmeSrcId] &&
            this._connectionListBySrcGMEID[gmeSrcId][gmeDstId] &&
            this._connectionListBySrcGMEID[gmeSrcId][gmeDstId][connType]) {
            connectionPresent = true;
        }

        if (!connectionPresent) {
            return;
        }

        len = this._connectionListBySrcGMEID[gmeSrcId][gmeDstId][connType].length;

        while (len--) {
            connectionID = this._connectionListBySrcGMEID[gmeSrcId][gmeDstId][connType][len];

            //if a pointer with a specific name should be removed
            //clear out the connectionID if this connection is not the representation of that pointer
            if (connType === MetaRelations.META_RELATIONS.POINTER &&
                pointerName &&
                pointerName !== '' &&
                this._connectionListByID[connectionID].name !== pointerName) {
                connectionID = undefined;
            }

            //if the connectionID is still valid
            if (connectionID) {
                this._widget.deleteComponent(connectionID);

                //clean up accounting
                delete this._connectionListByID[connectionID];

                idx = this._connectionListByType[connType].indexOf(connectionID);
                this._connectionListByType[connType].splice(idx, 1);

                idx = this._connectionListBySrcGMEID[gmeSrcId][gmeDstId][connType].indexOf(connectionID);
                this._connectionListBySrcGMEID[gmeSrcId][gmeDstId][connType].splice(idx, 1);

                idx = this._connectionListByDstGMEID[gmeDstId][gmeSrcId][connType].indexOf(connectionID);
                this._connectionListByDstGMEID[gmeDstId][gmeSrcId][connType].splice(idx, 1);
            }
        }
    };
    /****************************************************************************/
    /*  END OF --- REMOVES A SPECIFIC TYPE OF CONNECTION FROM 2 GME OBJECTS     */
    /****************************************************************************/

    /*************************************************************/
    /*  HANDLE OBJECT / CONNECTION DELETION IN THE ASPECT ASPECT */
    /*************************************************************/
    CrosscutController.prototype._onSelectionDelete = function (idList) {
        var client = this._client,
            memberListContainerID = this._memberListContainerID,
            memberListToRemoveFrom = this._selectedMemberListID,
            len,
            gmeID,
            gmeObj,
            componentId,
            NON_DELETABLE_POINTERS = [CONSTANTS.POINTER_SOURCE, CONSTANTS.POINTER_TARGET, CONSTANTS.POINTER_BASE],
            lineDesc,
            canDeletePointer,
            logger = this.logger;

        client.startTransaction();

        len = idList.length;
        while (len--) {
            componentId = idList[len];
            gmeID = this._ComponentID2GMEID[componentId];

            //#1: deleting an item --> deleting a member
            //  #1/a: if deleting a connection whose hierarchical parent is the membershipContainer,
            //          delete the connection from the hierarchy too
            //#2:  deleting a line --> deleting a pointer
            //  #2/a: do not let the user delete an src/dst pointer??

            if (gmeID) {
                //deleting a box --> remove from crosscut's set
                logger.debug('removeMember memberListContainerID: ' + memberListContainerID + ', gmeID: ' + gmeID +
                ', memberListToRemoveFrom: ' + memberListToRemoveFrom);
                //_client.removeMember(memberListContainerID, gmeID, memberListToRemoveFrom);

                //check if this GME object is a connection and whether it's parent is the crosscut container
                gmeObj = client.getNode(gmeID);
                if (GMEConcepts.isConnection(gmeID) && gmeObj.getParentId() === memberListContainerID) {
                    if (GMEConcepts.canDeleteNode(gmeID)) {
                        logger.debug('deleting connection from crosscut hierarchy too gmeID: ' + gmeID);
                        client.delMoreNodes([gmeID]);
                    } else {
                        client.removeMember(memberListContainerID, gmeID, memberListToRemoveFrom);
                    }
                } else {
                    client.removeMember(memberListContainerID, gmeID, memberListToRemoveFrom);
                }
            } else {
                //deleting a line
                lineDesc = this._connectionListByID[componentId];
                if (lineDesc) {
                    canDeletePointer = true;
                    //  #2/a: do not let the user delete an src/dst pointer??
                    if (lineDesc.type === MetaRelations.META_RELATIONS.POINTER &&
                        NON_DELETABLE_POINTERS.indexOf(lineDesc.name) !== -1) {
                        canDeletePointer = false;
                    }

                    if (canDeletePointer) {
                        logger.debug('deleting pointer from: ' + lineDesc.GMESrcId + ', type: ' + lineDesc.name);
                        //it's a pointer that's allowed to be deleted
                        client.delPointer(lineDesc.GMESrcId, lineDesc.name);
                    } else {
                        logger.warn('can not delete pointer from: ' + lineDesc.GMESrcId + ', type: ' + lineDesc.name);
                    }
                }
            }
        }

        client.completeTransaction();
    };
    /************************************************************************/
    /*  END OF --- HANDLE OBJECT / CONNECTION DELETION IN THE ASPECT ASPECT */
    /************************************************************************/

    CrosscutController.prototype._onFilterNewConnectionDroppableEnds = function (params) {
        var availableConnectionEnds = params.availableConnectionEnds,
            result = [],
            i,
            sourceId,
            targetId,
            j,
            client = this._client,
            validPointerTargetTypes,
            validSetTargetTypes,
            validConnectionEndTypes,
            validConnectionTypes,
            validEndTypes,
            parentId = this._memberListContainerID,
            pointerMetaDescriptor,
            p;

        if (params.srcSubCompId === undefined) {
            sourceId = this._ComponentID2GMEID[params.srcId];
        } else {
            sourceId = this._Subcomponent2GMEID[params.srcId][params.srcSubCompId];
        }

        //need to figure out who are the potential end items for a 'connection'
        //#1: all the items are potential 'connection' destination that could be a pointer target from this source
        //#2: all the items are potential 'connection' destination that could be a set (pointerlist) target
        //      from this source
        //#3: all the items are potential 'connection' destination where a WebGME-connection can be created
        // between this source and that target and the connection can be created in this parent based on the META rules

        //check #1:
        validPointerTargetTypes = GMEConcepts.getValidPointerTargetTypesFromSource(sourceId, false);

        //check #2:
        validSetTargetTypes = GMEConcepts.getValidPointerTargetTypesFromSource(sourceId, true);

        //check #3:
        validConnectionTypes = GMEConcepts.getValidConnectionTypesFromSourceInAspect(sourceId,
            parentId,
            CONSTANTS.ASPECT_ALL);
        validConnectionEndTypes = [];

        //filter them to see which of those can actually be created as a child of the parent
        //check what endpoint could be a potential endpoint of any of the connection types
        i = validConnectionTypes.length;
        while (i--) {
            if (GMEConcepts.canCreateChild(parentId, validConnectionTypes[i])) {
                pointerMetaDescriptor = this._client.getValidTargetItems(validConnectionTypes[i],
                    CONSTANTS.POINTER_TARGET);
                if (pointerMetaDescriptor && pointerMetaDescriptor.length > 0) {
                    j = pointerMetaDescriptor.length;
                    while (j--) {
                        if (validConnectionEndTypes.indexOf(pointerMetaDescriptor[j].id) === -1) {
                            validConnectionEndTypes.push(pointerMetaDescriptor[j].id);
                        }
                    }
                }
            }
        }

        //filter out the items on the screen
        validEndTypes = _.union(validPointerTargetTypes, validSetTargetTypes, validConnectionEndTypes);
        this.logger.debug('validEndTypes: ' + validEndTypes);

        i = availableConnectionEnds.length;
        while (i--) {
            p = availableConnectionEnds[i];
            if (p.dstSubCompID === undefined) {
                targetId = this._ComponentID2GMEID[p.dstItemID];
            } else {
                targetId = this._Subcomponent2GMEID[p.dstItemID][p.dstSubCompID];
            }

            j = validEndTypes.length;
            while (j--) {
                if (client.isTypeOf(targetId, validEndTypes[j])) {
                    result.push(availableConnectionEnds[i]);
                    break;
                }
            }
        }

        return result;
    };

    CrosscutController.prototype._onCreateNewConnection = function (params) {
        var sourceId,
            targetId,
            parentId = this._memberListContainerID,
            client = this._client,
            CONTEXT_POS_OFFSET = 10,
            menuItems = {},
            i,
            sourceObj,
            targetObj,
            connObj,
            ptrAction = 'PTR',
            setAction = 'SET',
            connectionAction = 'CONN',
            createPointer,
            addToSet,
            createConnection,
            logger = this.logger,
            aspect = this._selectedMemberListID,
            dstPosition = this._widget.items[params.dst].getBoundingBox(),
            srcPosition = this._widget.items[params.src].getBoundingBox(),

            validPointerTypes,
            validSetTypes,
            validConnectionTypes,
            sourceObjName,
            targetObjName,
            connObjName;

        createPointer = function (srcId, dstId, ptrName) {
            logger.debug('createPointer srcId: ' + srcId + ', dstId: ' + dstId + ', ptrName: ' + ptrName);
            client.makePointer(srcId, ptrName, dstId);
        };

        addToSet = function (containerId, objId, setName) {
            logger.debug('addToSet containerId: ' + containerId + ', objId: ' + objId + ', ptrName: ' + setName);
            client.addMember(containerId, objId, setName);
        };

        createConnection = function (srcId, dstId, connType) {
            var newConnID,
                dx,
                dy;

            logger.debug('createConnection srcId: ' + srcId + ', dstId: ' + dstId + ', connType: ' + connType);
            client.startTransaction();

            //create new object
            newConnID = client.createChild({parentId: parentId, baseId: connType});

            //set source and target pointers
            client.makePointer(newConnID, CONSTANTS.POINTER_SOURCE, srcId);
            client.makePointer(newConnID, CONSTANTS.POINTER_TARGET, dstId);

            //add new object to the current aspect ans store coordinate
            client.addMember(parentId, newConnID, aspect);
            dx = dstPosition.x - srcPosition.x;
            dy = dstPosition.y - srcPosition.y;
            dx = srcPosition.x + dx / 2;
            dy = srcPosition.y + dy / 2;
            client.setMemberRegistry(parentId, newConnID, aspect, REGISTRY_KEYS.POSITION, {x: dx, y: dy});

            client.completeTransaction();
        };

        if (params.srcSubCompId === undefined) {
            sourceId = this._ComponentID2GMEID[params.src];
        } else {
            sourceId = this._Subcomponent2GMEID[params.src][params.srcSubCompId];
        }

        if (params.dstSubCompId === undefined) {
            targetId = this._ComponentID2GMEID[params.dst];
        } else {
            targetId = this._Subcomponent2GMEID[params.dst][params.dstSubCompId];
        }

        //need to figure out what this 'connection' could be
        //#1: a pointer from the source to this target
        //#2: a set membership where the source is the membership container and the target is the member
        //#3: a new WebGME connection between the source and the target created in this parent

        //#1: pointers
        validPointerTypes = GMEConcepts.getValidPointerTypesFromSourceToTarget(sourceId, targetId);

        //#2: sets
        validSetTypes = GMEConcepts.getValidSetTypesFromContainerToMember(sourceId, targetId);

        //#3: WebGME-connections
        validConnectionTypes = GMEConcepts.getValidConnectionTypesInAspect(sourceId,
            targetId,
            parentId,
            CONSTANTS.ASPECT_ALL);

        //if there is any option at all
        if (validPointerTypes.length + validSetTypes.length + validConnectionTypes.length > 0) {
            //if only 1 option, figure out automatically
            if (validPointerTypes.length + validSetTypes.length + validConnectionTypes.length === 1) {
                //thre is only one possible choice, go with that
                if (validPointerTypes.length === 1) {
                    //create pointer from source to target
                    createPointer(sourceId, targetId, validPointerTypes[0]);
                } else if (validSetTypes.length === 1) {
                    //add target to the set of source
                    addToSet(sourceId, targetId, validSetTypes[0]);
                } else if (validConnectionTypes.length === 1) {
                    //create connection between source and target in this parent
                    createConnection(sourceId, targetId, validConnectionTypes[0]);
                }
            } else {
                //more options, show context menu
                //show available pointers/sets/connection types to the user to select one
                sourceObj = client.getNode(sourceId);
                targetObj = client.getNode(targetId);

                sourceObjName = sourceObj.getAttribute(nodePropertyNames.Attributes.name);
                targetObjName = targetObj.getAttribute(nodePropertyNames.Attributes.name);

                //'Create pointer'
                for (i = 0; i < validPointerTypes.length; i += 1) {
                    menuItems[ptrAction + validPointerTypes[i]] = {
                        name: 'Create pointer \'' + validPointerTypes[i] + '\' from \'' + sourceObjName + '\' to \'' +
                        targetObjName + '\'',
                        icon: 'glyphicon glyphicon-share',
                        action: ptrAction,
                        type: validPointerTypes[i]
                    };
                }

                //'Add to set'
                for (i = 0; i < validSetTypes.length; i += 1) {
                    menuItems[setAction + validSetTypes[i]] = {
                        name: 'Add \'' + targetObjName + '\' to set \'' + validSetTypes[i] + '\' of \'' +
                        sourceObjName + '\'',
                        icon: false,
                        action: setAction,
                        type: validSetTypes[i]
                    };
                }

                //'Create connection' in crosscut container
                connObjName = '';
                for (i = 0; i < validConnectionTypes.length; i += 1) {
                    connObj = client.getNode(validConnectionTypes[i]);

                    if (connObj) {
                        connObjName = connObj.getAttribute(nodePropertyNames.Attributes.name);
                    } else {
                        connObjName = validConnectionTypes[i];
                    }

                    menuItems[connectionAction + validConnectionTypes[i]] = {
                        name: 'Create connection \'' + connObjName + '\' from \'' + sourceObjName + '\' to \'' +
                        targetObjName + '\'',
                        icon: 'glyphicon glyphicon-resize-horizontal',
                        action: connectionAction,
                        type: validConnectionTypes[i]
                    };
                }

                //show context menu
                this._widget.createMenu(menuItems, function (key) {
                        var menuItem = menuItems[key],
                            type = menuItem.type,
                            action = menuItem.action;

                        switch (action) {
                            case ptrAction:
                                createPointer(sourceId, targetId, type);
                                break;
                            case setAction:
                                addToSet(sourceId, targetId, type);
                                break;
                            case connectionAction:
                                createConnection(sourceId, targetId, type);
                                break;
                            default:
                                break;
                        }
                    },

                    this._widget.posToPageXY(dstPosition.x - CONTEXT_POS_OFFSET,
                        dstPosition.y - CONTEXT_POS_OFFSET)
                );
            }
        }
    };

    CrosscutController.prototype._getDragItems = function (selectedElements) {
        var res = [],
            i = selectedElements.length;

        while (i--) {
            if (this._ComponentID2GMEID[selectedElements[i]]) {
                res.push(this._ComponentID2GMEID[selectedElements[i]]);
            }
        }

        return res;
    };

    CrosscutController.prototype._attachClientEventListeners = function () {
        DiagramDesignerWidgetMultiTabMemberListControllerBase.prototype._attachClientEventListeners.call(this);
        WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_CROSSCUT, this._stateActiveCrosscutChanged, this);
    };

    CrosscutController.prototype._detachClientEventListeners = function () {
        DiagramDesignerWidgetMultiTabMemberListControllerBase.prototype._detachClientEventListeners.call(this);
        WebGMEGlobal.State.off('change:' + CONSTANTS.STATE_ACTIVE_CROSSCUT, this._stateActiveCrosscutChanged);
    };

    CrosscutController.prototype._stateActiveCrosscutChanged = function (model, activeCrosscutId) {
        var tabKeys = Object.keys(this._tabIDMemberListID),
            len = tabKeys.length,
            tabToSelect;

        while (len--) {
            if (this._tabIDMemberListID[tabKeys[len]] === activeCrosscutId) {
                tabToSelect = tabKeys[len];
                break;
            }
        }

        WebGMEGlobal.State.unset(CONSTANTS.STATE_ACTIVE_CROSSCUT, {silent: true});
        if (tabToSelect) {
            this._widget.selectTab(tabToSelect);
        }
    };

    return CrosscutController;
});


text:
RUBY_VER=2.6.1
echo "================= Installing Ruby $RUBY_VER ==================="
rvm requirements
rvm install "$RUBY_VER" --disable-binary
rvm use "$RUBY_VER"

# Install ruby gems
gem install bundler

redpajama_set_name: RedPajamaGithub


text:
#import <Foundation/Foundation.h>

#import "MGLFoundation.h"
#import "MGLForegroundStyleLayer.h"

NS_ASSUME_NONNULL_BEGIN

/**
 `MGLVectorStyleLayer` is an abstract superclass for style layers whose content
 is defined by an `MGLShapeSource` or `MGLVectorSource` object.

 Do not create instances of this class directly, and do not create your own
 subclasses of this class. Instead, create instances of the following concrete
 subclasses: `MGLCircleStyleLayer`, `MGLFillStyleLayer`, `MGLLineStyleLayer`,
 and `MGLSymbolStyleLayer`.
 */
MGL_EXPORT
@interface MGLVectorStyleLayer : MGLForegroundStyleLayer

#pragma mark Refining a Style Layer's Content

/**
 Identifier of the layer within the source identified by the `sourceIdentifier`
 property from which the receiver obtains the data to style.
 */
@property (nonatomic, nullable) NSString *sourceLayerIdentifier;

/**
 The style layer's predicate.

 Use the style layer's predicate to include only the features in the source
 layer that satisfy a condition that you define. If the style layer initially
 comes from the style, its predicate corresponds to the
 `filter`
 property in the style JSON.

 The following comparison operators are supported.

NSEqualToPredicateOperatorType (=, ==)

NSGreaterThanOrEqualToPredicateOperatorType (>=, =>)

NSLessThanOrEqualToPredicateOperatorType (<=, =<)

NSGreaterThanPredicateOperatorType (>)

NSLessThanPredicateOperatorType (<)

NSNotEqualToPredicateOperatorType (!=, <>)

NSBetweenPredicateOperatorType (BETWEEN)

 The following compound operators are supported:

NSAndPredicateType (AND, &&)

NSOrPredicateType (OR, ||)

NSNotPredicateType (NOT, !)

 The following aggregate operators are supported:

NSInPredicateOperatorType (IN)

NSContainsPredicateOperatorType (CONTAINS)

 To test whether a feature has or lacks a specific attribute, compare the
 attribute to `NULL` or `NIL`. Predicates created using the
 `+[NSPredicate predicateWithValue:]` method are also supported. String
 operators and custom operators are not supported.

 For details about the predicate format string syntax, consult the "Predicate
 Format String Syntax" chapter of the
 "Predicate Programming Guide"
 in Apple developer documentation.

 The predicate's left-hand expression must be a string that identifies a feature
 attribute or, alternatively, one of the following special attributes:

Attribute	Meaning

    $id

        A value that uniquely identifies the feature in the containing source.
        For details on the types of values that may be associated with this key,
        consult the documentation for the MGLFeature protocol's
        identifier property.

    $type

        The type of geometry represented by the feature. A feature's type is
        guaranteed to be one of the following strings:

                Point for point features, corresponding to the
                MGLPointAnnotation class

                LineString for polyline features, corresponding to
                the MGLPolyline class

                Polygon for polygon features, corresponding to the
                MGLPolygon class

    point_count
    The number of point features in a given cluster.

 The predicate's right-hand expression must be an `NSString` (to match strings)
 or `NSNumber` (to match numbers, including Boolean values) or an array of
 `NSString`s or `NSNumber`s, depending on the operator and the type of values
 expected for the attribute being tested. For floating-point values, use
 `-[NSNumber numberWithDouble:]` instead of `-[NSNumber numberWithFloat:]`
 to avoid precision issues.

 Automatic type casting is not performed. Therefore, a feature only matches this
 predicate if its value for the attribute in question is of the same type as the
 value specified in the predicate. Also, operator modifiers such as `c` (for
 case insensitivity), `d` (for diacritic insensitivity), and `l` (for locale
 sensitivity) are unsupported for comparison and aggregate operators that are
 used in the predicate.

 It is possible to create expressions that contain special characters in the
 predicate format syntax. This includes the `$` in the `$id` and `$type` special
 style attributes and also `hyphen-minus` and `tag:subtag`. However, you must use
 `%K` in the format string to represent these variables:
 `@"%K == 'LineString'", @"$type"`.

 ### Example

 To filter the layer to include only the features whose `index` attribute is 5
 or 10 and whose `ele` attribute is at least 1,500, you could create an
 `NSCompoundPredicate` along these lines:

 ```swift
 let layer = MGLLineStyleLayer(identifier: "contour", source: terrain)
 layer.sourceLayerIdentifier = "contours"
 layer.predicate = NSPredicate(format: "(index == 5 || index == 10) && ele >= 1500.0")
 mapView.style?.addLayer(layer)
 ```
 */
@property (nonatomic, nullable) NSPredicate *predicate;

@end

NS_ASSUME_NONNULL_END


text:
#include "native_client/src/trusted/validator_arm/inst_classes.h"

/*
 * Implementations of instruction classes, for those not completely defined in
 * the header.
 */

namespace nacl_arm_dec {

/*
 * A utility function: given a modified-immediate-form instruction, extracts
 * the immediate value.  This is used to analyze BIC and TST.
 *
 * This encoding is described in Section A5.2.4.
 */
static uint32_t get_modified_immediate(Instruction i) {
  int rotation = i.bits(11, 8) * 2;
  uint32_t value = i.bits(7, 0);

  if (rotation == 0) return value;

  return (value >> rotation) | (value << (32 - rotation));
}

/*
 * Breakpoint
 */

bool Breakpoint::is_literal_pool_head(const Instruction i) const {
  return i.condition() == Instruction::AL
      && i.bits(19, 8) == 0x777
      && i.bits(3, 0) == 0x7;
}

/*
 * Data processing and arithmetic
 */

SafetyLevel DataProc::safety(const Instruction i) const {
  if (defs(i)[kRegisterPc]) {
    return FORBIDDEN_OPERANDS;
  }
  return MAY_BE_SAFE;
}

RegisterList DataProc::defs(const Instruction i) const {
  return i.reg(15, 12) + (i.bit(20)? kRegisterFlags : kRegisterNone);
}

RegisterList Test::defs(const Instruction i) const {
  return (i.bit(20)? kRegisterFlags : kRegisterNone);
}

bool TestImmediate::sets_Z_if_bits_clear(Instruction i,
                                         Register r,
                                         uint32_t mask) const {
  // Rn = 19:16 for TST(immediate) - section A8.6.230
  return i.reg(19, 16) == r
      && (get_modified_immediate(i) & mask) == mask
      && defs(i)[kRegisterFlags];
}

bool ImmediateBic::clears_bits(const Instruction i, uint32_t mask) const {
  return (get_modified_immediate(i) & mask) == mask;
}

SafetyLevel PackSatRev::safety(const Instruction i) const {
  if (defs(i)[kRegisterPc]) {
    return FORBIDDEN_OPERANDS;
  }
  return MAY_BE_SAFE;
}

RegisterList PackSatRev::defs(const Instruction i) const {
  return i.reg(15, 12) + kRegisterFlags;
}

SafetyLevel Multiply::safety(const Instruction i) const {
  if (defs(i)[kRegisterPc]) {
    return FORBIDDEN_OPERANDS;
  }
  return MAY_BE_SAFE;
}

RegisterList Multiply::defs(const Instruction i) const {
  return kRegisterFlags + i.reg(19, 16);
}

RegisterList LongMultiply::defs(const Instruction i) const {
  return Multiply::defs(i) + i.reg(15, 12);
}

RegisterList LongMultiply15_8::defs(const Instruction i) const {
  return kRegisterFlags + i.reg(15, 12) + i.reg(11, 8);
}

RegisterList SatAddSub::defs(const Instruction i) const {
  return DataProc::defs(i) + kRegisterFlags;
}

/*
 * MSR
 */

RegisterList MoveToStatusRegister::defs(const Instruction i) const {
  UNREFERENCED_PARAMETER(i);
  return kRegisterFlags;
}

/*
 * Stores
 */

SafetyLevel StoreImmediate::safety(const Instruction i) const {
  // Don't let addressing writeback alter PC.
  if (defs(i)[kRegisterPc]) return FORBIDDEN_OPERANDS;

  return MAY_BE_SAFE;
}

RegisterList StoreImmediate::defs(const Instruction i) const {
  return immediate_addressing_defs(i);
}

RegisterList StoreImmediate::immediate_addressing_defs(
    const Instruction i) const {
  bool p = i.bit(24);
  bool w = i.bit(21);
  if (!p) return base_address_register(i);
  if (w) return base_address_register(i);
  return kRegisterNone;
}

Register StoreImmediate::base_address_register(const Instruction i) const {
  return i.reg(19, 16);
}

SafetyLevel StoreRegister::safety(const Instruction i) const {
  bool pre_index = i.bit(24);
  if (pre_index) {
    // Computes base address by adding two registers -- cannot predict!
    return FORBIDDEN;
  }

  // Don't let addressing writeback alter PC.
  if (defs(i)[kRegisterPc]) return FORBIDDEN_OPERANDS;

  return MAY_BE_SAFE;
}

RegisterList StoreRegister::defs(const Instruction i) const {
  /*
   * Only one form of register-register store doesn't writeback its base:
   *   str rT, [rN, rM]
   * We ban this form.  Thus, every safe form alters its base address reg.
   */
  return base_address_register(i);
}

Register StoreRegister::base_address_register(const Instruction i) const {
  return i.reg(19, 16);
}

SafetyLevel StoreExclusive::safety(const Instruction i) const {
  // Don't let addressing writeback alter PC.
  if (defs(i)[kRegisterPc]) return FORBIDDEN_OPERANDS;

  return MAY_BE_SAFE;
}

RegisterList StoreExclusive::defs(const Instruction i) const {
  return i.reg(15, 12);
}

Register StoreExclusive::base_address_register(const Instruction i) const {
  return i.reg(19, 16);
}

/*
 * Loads
 */

bool AbstractLoad::writeback(const Instruction i) const {
  // Algorithm defined in pseudocode in ARM instruction set spec
  // Valid for LDR, LDR[BH], LDRD
  // Not valid for LDREX and kin
  bool p = i.bit(24);
  bool w = i.bit(21);
  return !p | w;
}

SafetyLevel AbstractLoad::safety(const Instruction i) const {
  if (defs(i)[kRegisterPc]) return FORBIDDEN_OPERANDS;

  return MAY_BE_SAFE;
}

RegisterList AbstractLoad::defs(const Instruction i) const {
  return i.reg(15, 12) + immediate_addressing_defs(i);
}

RegisterList LoadRegister::defs(const Instruction i) const {
  if (writeback(i)) {
    Register rn(i.bits(19, 16));
    return AbstractLoad::defs(i) + rn;
  } else {
    return AbstractLoad::defs(i);
  }
}

RegisterList LoadImmediate::immediate_addressing_defs(const Instruction i)
    const {
  if (writeback(i)) {
    Register rn(i.bits(19, 16));
    return rn;
  } else {
    return kRegisterNone;
  }
}

RegisterList LoadDoubleI::defs(const Instruction i) const {
  return LoadImmediate::defs(i) + Register(i.bits(15, 12) + 1);
}

RegisterList LoadDoubleR::defs(const Instruction i) const {
  return LoadRegister::defs(i) + Register(i.bits(15, 12) + 1);
}

RegisterList LoadDoubleExclusive::defs(const Instruction i) const {
  return LoadExclusive::defs(i) + Register(i.bits(15, 12) + 1);
}

SafetyLevel LoadMultiple::safety(const Instruction i) const {
  uint32_t rn = i.bits(19, 16);
  if (i.bit(21) && i.bit(rn)) {
    // In ARMv7, cannot update base register both by popping and by indexing.
    // (Pre-v7 this was still a weird thing to do.)
    return UNPREDICTABLE;
  }

  if (defs(i)[kRegisterPc]) {
    return FORBIDDEN_OPERANDS;
  }
  return MAY_BE_SAFE;
}

RegisterList LoadMultiple::defs(const Instruction i) const {
  return RegisterList(i.bits(15, 0)) + immediate_addressing_defs(i);
}

RegisterList LoadMultiple::immediate_addressing_defs(
    const Instruction i) const {
  return i.bit(21)? i.reg(19, 16) : kRegisterNone;
}

/*
 * Vector load/stores
 */

SafetyLevel VectorLoad::safety(Instruction i) const {
  if (defs(i)[kRegisterPc]) return FORBIDDEN_OPERANDS;

  return MAY_BE_SAFE;
}

RegisterList VectorLoad::defs(Instruction i) const {
  // Rm == PC indicates no address writeback.  Otherwise Rn is affected.
  if (i.reg(3, 0) != kRegisterPc) {
    return i.reg(19, 16);
  }

  return kRegisterNone;
}

RegisterList VectorLoad::immediate_addressing_defs(Instruction i) const {
  // Rm == SP indicates automatic update based on size of load.
  if (i.reg(3, 0) == kRegisterStack) {
    // Rn is updated by a small static displacement.
    return i.reg(19, 16);
  }

  // Any writeback is not treated as immediate otherwise.
  return kRegisterNone;
}

SafetyLevel VectorStore::safety(Instruction i) const {
  if (defs(i)[kRegisterPc]) return FORBIDDEN_OPERANDS;

  return MAY_BE_SAFE;
}

RegisterList VectorStore::defs(Instruction i) const {
  // Rm == PC indicates no address writeback.  Otherwise Rn is affected.
  if (i.reg(3, 0) != kRegisterPc) {
    return base_address_register(i);
  }

  return kRegisterNone;
}

RegisterList VectorStore::immediate_addressing_defs(Instruction i) const {
  // Rm == SP indicates automatic update based on size of store.
  if (i.reg(3, 0) == kRegisterStack) {
    // Rn is updated by a small static displacement.
    return base_address_register(i);
  }

  // Any writeback is not treated as immediate otherwise.
  return kRegisterNone;
}

bool VectorStore::writes_memory(Instruction i) const {
  UNREFERENCED_PARAMETER(i);
  return true;
}

Register VectorStore::base_address_register(Instruction i) const {
  return i.reg(19, 16);
}

/*
 * Coprocessors
 */

SafetyLevel CoprocessorOp::safety(Instruction i) const {
  if (defs(i)[kRegisterPc]) return FORBIDDEN_OPERANDS;
  uint32_t cpid = i.bits(11, 8);

  switch (cpid) {
    default: return FORBIDDEN;

    case 10:
    case 11:  // NEON/VFP
      return MAY_BE_SAFE;
  }
}

RegisterList LoadCoprocessor::defs(Instruction i) const {
  return immediate_addressing_defs(i);
}

RegisterList LoadCoprocessor::immediate_addressing_defs(Instruction i) const {
  return i.bit(21)? i.reg(19, 16) : kRegisterNone;
}

RegisterList StoreCoprocessor::defs(Instruction i) const {
  return immediate_addressing_defs(i);
}

RegisterList StoreCoprocessor::immediate_addressing_defs(Instruction i) const {
  return i.bit(21)? base_address_register(i) : kRegisterNone;
}

Register StoreCoprocessor::base_address_register(Instruction i) const {
  return i.reg(19, 16);
}

RegisterList MoveFromCoprocessor::defs(Instruction i) const {
  Register rd = i.reg(15, 12);
  if (rd == kRegisterPc) {
    // Per ARM ISA spec: r15 here is a synonym for the flags register!
    return kRegisterFlags;
  }
  return rd;
}

RegisterList MoveDoubleFromCoprocessor::defs(Instruction i) const {
  return i.reg(15, 12) + i.reg(19, 16);
}

/*
 * Control flow
 */

RegisterList BxBlx::defs(const Instruction i) const {
  return kRegisterPc + (i.bit(5)? kRegisterLink : kRegisterNone);
}

Register BxBlx::branch_target_register(const Instruction i) const {
  return i.reg(3, 0);
}

RegisterList Branch::defs(const Instruction i) const {
  return kRegisterPc + (i.bit(24)? kRegisterLink : kRegisterNone);
}

int32_t Branch::branch_target_offset(const Instruction i) const {
  // Sign extend and shift left 2:
  int32_t offset = (int32_t)(i.bits(23, 0) << 8) >> 6;
  return offset + 8;  // because r15 reads as 8 bytes ahead
}

}  // namespace


text:
module CMSScanner
  module Controller
    # InterestingFindings Controller
    class InterestingFindings < Base
      def cli_options
        [
          OptChoice.new(
            ['--interesting-findings-detection MODE',
             'Use the supplied mode for the interesting findings detection. '],
            choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
          )
        ]
      end

      def run
        mode = NS::ParsedCli.interesting_findings_detection || NS::ParsedCli.detection_mode
        findings = target.interesting_findings(mode: mode)

        output('findings', findings: findings) unless findings.empty?
      end
    end
  end
end


text:
'use strict'

/**
 * Module Dependencies
 * @ignore
 */
const Logger = require('./Logger')

/**
 * Exports
 */
module.exports = Logger


text:
eduauth
=======

Authentication Module of EDUIS


text:
var myApp = angular.module('myApp', ['ngRoute', 'deckBuilder', 'cardSearch', 'profile', 'ngAnimate']);

myApp.config(function ($routeProvider) {
  $routeProvider
    .when('/', {
      templateUrl: 'partials/landing.html'
    })
    .when('/login', {
      templateUrl: 'partials/login.html',
      controller: 'loginController',
      access: {restricted: false}
    })
    .when('/logout', {
      controller: 'logoutController',
      access: {restricted: true}
    })
    .when('/register', {
      templateUrl: 'partials/register.html',
      controller: 'registerController',
      access: {restricted: false}
    })
    .when('/card', {
      template: '<card-search></card-search>',
      access: {restricted: true}
    })
    .when('/deck', {
      template: '<deck-builder></deck-builder>',
      access: {restricted: true}
    })
    .when('/profile/:name', {
      templateUrl: 'partials/landing.html',
      access: {restricted: false}
    })
    .when('/profile', {
      template: '<profile></profile>',
      access: {restricted: true}
    })
    .when('/deckbuilder/edit/id=:id', {
      template: '<deck-builder></deck-builder>',
      access: {restricted: true},
      edit: 'true'
    })
    .otherwise({
      redirectTo: '/'
    });
});

myApp.run(function ($rootScope, $location, $route, AuthService) {
  $rootScope.$on('$routeChangeStart',
    function (event, next, current) {
      AuthService.getUserStatus()
      .then(function(){
        if (next.access.restricted && !AuthService.isLoggedIn()){
          $location.path('/login');
          $route.reload();
        }
      });
  });
});

myApp.directive('background', function() {
  var curId = Math.round(Math.random() * 9) + 1;
  $(".login-header").css("background-image", "url(../img/bg" + curId + ".jpg)");
  return {};
});


text:
\documentclass{scrartcl}

\title{Design of Embedded Systems\\Exercise 12}
\author{Erin van der Veen - s4431200}

\begin{document}

\maketitle

\section{Field}
The game consists of a field.
This field determines the size of the field in the Game of Life.
In turn, I have also removed the resize feature of the original Game of Life implementation.
An unfortunate consequence of this decision is that the GameofLife.java also needs to be generated.
I could have also chosen to rewite substantial parts of GameofLife.java, but that would have costed me too much time.

\section{Natural Language}
I tried to get as close to natural language as possible in my rules, with some structure.
I thought this might allow people who are very foreign to structures language models to still use the DSL.

\end{document}


text:
'use strict';

// MODULES //

var isTypedArray = require( 'validate.io-typed-array' );

// EVERY //

/**
* FUNCTION: every( fcn, value )
*	Validates each typed array element.
*
* @param {Function} fcn - function to apply
* @param {*} value - value to be validated
* @returns {Boolean} true if value is a typed array for which all elements pass; otherwise, false
*/
function every( fcn, value ) {
	if ( !isTypedArray( value ) ) {
		return false;
	}
	var len = value.length,
		i;
	if ( !len ) {
		return false;
	}
	for ( i = 0; i < len; i++ ) {
		if ( fcn( value[ i ] ) === false ) {
			return false;
		}
	}
	return true;
} // end FUNCTION every()

// EXPORTS //

module.exports = every;


text:
SYNONYM

#### According to
The Catalogue of Life, 3rd January 2011

#### Published in
Mycologia 25: 363 (1933)

#### Original name
Hydnum himantia Schwein., 1822

### Remarks
null


text:
  <button type="button" class="btn btn-success btn-xs dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
    Tindakan
  </button>

Edit

Sprint Lidik

Sprint Geledah

Dik-Mum

  Duis aute irure dolor in reprehenderi

		Kasus Posisi:
		inputLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
		tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
		quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
		consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
		cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
		proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

					@include('partials._tsk3')


text:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using Pilipala.FlightSimulator.Properties;

namespace Pilipala.FlightSimulator
{
    public class Location : ILocation
    {
        private readonly List<ICity> _cities = new List<ICity>();

        public Location()
        {
            using (var reader = new StringReader(Resources.Cities))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    _cities.Add(new City(line));
                }
            }
        }

        public TimeZoneInfo GetTimeZoneInfoForCity(string country, string city)
        {
            var cityDetails = _cities.FirstOrDefault(x => x.Country == country && x.Name == city);
            if (cityDetails == null)
            {
                throw new InvalidOperationException("City not found");
            }

            return cityDetails.TimeZoneInfo;
        }
    }
}


text:
<bill session="110" type="h" number="2811" updated="2009-01-08T22:42:06-05:00">
	<status><introduced date="1182398400" datetime="2007-06-21"/></status>

	<introduced date="1182398400" datetime="2007-06-21"/>
	<titles>
		<title type="short" as="introduced">Passenger Vehicle Loss Disclosure Act</title>
		<title type="official" as="introduced">To improve consumer access to passenger vehicle loss data held by insurers.</title>
	</titles>
	<sponsor id="400201"/>
	<cosponsors>
		<cosponsor id="400080" joined="2007-06-21"/>
	</cosponsors>
	<actions>
		<action date="1182398400" datetime="2007-06-21"><text>Referred to the Committee on Energy and Commerce, and in addition to the Committee on Financial Services, for a period to be subsequently determined by the Speaker, in each case for consideration of such provisions as fall within the jurisdiction of the committee concerned.</text></action>
		<action date="1182398400" datetime="2007-06-21"><text>Referred to House Energy and Commerce</text></action>
		<action date="1182398400" datetime="2007-06-21"><committee name="House Energy and Commerce"/><text>Referred to the Subcommittee on Commerce, Trade and Consumer Protection.</text></action>
		<action date="1182398400" datetime="2007-06-21"><text>Referred to House Financial Services</text></action>
	</actions>
	<committees>

	</committees>
	<relatedbills>

	</relatedbills>
	<subjects>

	</subjects>
	<amendments>

	</amendments>

	6/21/2007--Introduced.
Passenger Vehicle Loss Disclosure Act - Directs the Secretary of Transportation to require all insurers and self-insurers of passenger motor vehicles to disclose to the public, in a commercially reasonable, electronically accessible manner, for each passenger motor vehicle declared or determined to be a total loss: (1) the vehicle identification number and odometer reading; (2) the date of and primary reason for the total loss determination; and (3) whether the airbags deployed.

</bill>


text:
var reg = /var serverSiteUrl \= \"(?:.*?)\"/
var fs = require('fs');
const path = require('path');
var pathToScript = path.join(__dirname, '../src/scripts/xylole-client.js');
var script = fs.readFileSync(pathToScript).toString()
var newScript = script.replace(reg, function (match) {
  console.log(match);
  let newUrl = `var serverSiteUrl = "${'http://google.com'}"`
  return newUrl
})
// console.log(newScript);


text:
module.exports = {
    getVersion: () => jest.fn()
};


text:
using System;
using System.Collections.Generic;

namespace Light.Data
{
    internal class RelationMap : IMap
    {
        public DataEntityMapping RootMapping { get; }

        public Type Type => RootMapping.ObjectType;

        private ISelector selector;

        private readonly List<EntityJoinModel> models = new List<EntityJoinModel>();

        private readonly Dictionary<string, RelationItem> mapDict = new Dictionary<string, RelationItem>();

        private readonly Dictionary<string, DataFieldInfo[]> tableInfoDict = new Dictionary<string, DataFieldInfo[]>();

        private readonly Dictionary<string, DataFieldInfo> fieldInfoDict = new Dictionary<string, DataFieldInfo>();

        private readonly List<RelationLink> linkList = new List<RelationLink>();

        private readonly Dictionary<string, string> cycleDict = new Dictionary<string, string>();

        private readonly Dictionary<string, string[]> collectionDict = new Dictionary<string, string[]>();

        private readonly Dictionary<string, string[]> singleDict = new Dictionary<string, string[]>();

        private void LoadJoinRelate()
        {
            LoadEntityMapping(RootMapping, null);
            var joinSelector = new JoinSelector();
            var items = new List<RelationItem>();
            // var relationItemDict = new Dictionary<string, RelationItem>();
            var tIndex = 0;
            foreach (var link in linkList) {
                var sItems = link.GetRelationItems();
                foreach (var item in sItems) {
                    if (!items.Contains(item)) {
                        if (item.FieldMapping == null && tIndex != 0) {
                            continue;
                        }
                        item.AliasName = "T" + tIndex;
                        tIndex++;
                        items.Add(item);
                        // relationItemDict.Add(item.CurrentFieldPath, item);
                    }
                }
            }

            var rootItem = items[0];
            mapDict.Add(items[0].CurrentFieldPath, items[0]);
            var rootInfoList = new List<DataFieldInfo>();
            foreach (var field in RootMapping.DataEntityFields) {
                var info = new DataFieldInfo(field);
                var aliasName = $"{rootItem.AliasName}_{info.FieldName}";
                var alias = new AliasDataFieldInfo(info, aliasName, rootItem.AliasName);
                joinSelector.SetAliasDataField(alias);
                rootInfoList.Add(alias);
                fieldInfoDict.Add($"{items[0].CurrentFieldPath}.{field.IndexName}", alias);
            }
            tableInfoDict.Add(items[0].CurrentFieldPath, rootInfoList.ToArray());

            for (var i = 1; i < items.Count; i++) {
                var mItem = items[i];
                mapDict.Add(mItem.CurrentFieldPath, mItem);
                var fieldMapping = mItem.FieldMapping;
                var mapping = fieldMapping.RelateMapping;
                DataFieldExpression expression = null;

                var rItem = mapDict[mItem.PrevFieldPath];
                var mAlias = rItem.AliasName;
                var rAlias = mItem.AliasName;

                var relations = fieldMapping.CreateDataFieldInfoRelations(mAlias, rAlias);
                foreach (var relation in relations) {
                    var mInfo = relation.MasterInfo;
                    var rInfo = relation.RelateInfo;
                    var keyExpression = new DataFieldOnMatchExpression(mInfo, rInfo, QueryPredicate.Eq);
                    expression = DataFieldExpression.And(expression, keyExpression);
                }
                var infoList = new List<DataFieldInfo>();
                foreach (var field in mapping.DataEntityFields) {
                    var info = new DataFieldInfo(field);
                    var aliasName = $"{rAlias}_{info.FieldName}";
                    var alias = new AliasDataFieldInfo(info, aliasName, rAlias);
                    joinSelector.SetAliasDataField(alias);
                    infoList.Add(alias);
                    fieldInfoDict.Add($"{mItem.CurrentFieldPath}.{field.Name}", alias);
                }
                tableInfoDict.Add(mItem.CurrentFieldPath, infoList.ToArray());

                var connect = new JoinConnect(JoinType.LeftJoin, expression);
                var model = new EntityJoinModel(mapping, rAlias, connect, null, null, JoinSetting.None);
                selector = joinSelector;
                models.Add(model);
            }
        }

        private void LoadNormal()
        {
            var rootInfoList = new List<DataFieldInfo>();
            var dataSelector = new Selector();
            foreach (var fieldMapping in RootMapping.DataEntityFields) {
                if (fieldMapping != null) {
                    var field = new DataFieldInfo(fieldMapping);
                    fieldInfoDict.Add($"{string.Empty}.{fieldMapping.IndexName}", field);
                    rootInfoList.Add(field);
                    dataSelector.SetSelectField(field);
                }
            }
            tableInfoDict.Add(string.Empty, rootInfoList.ToArray());
            var path = string.Empty;
            foreach (var collectFieldMapping in RootMapping.CollectionRelationFieldMappings) {
                var kps = collectFieldMapping.GetKeyPairs();
                var masters = new string[kps.Length];
                for (var i = 0; i < kps.Length; i++) {
                    masters[i] = $"{path}.{kps[i].MasterKey}";
                }
                var collectField = $"{path}.{collectFieldMapping.FieldName}";
                collectionDict.Add(collectField, masters);
            }
            selector = dataSelector;
        }

        public RelationMap(DataEntityMapping rootMapping)
        {
            RootMapping = rootMapping;
            if (rootMapping.HasJoinRelateModel) {
                LoadJoinRelate();
            }
            else {
                LoadNormal();
            }
        }

        public List<IJoinModel> CreateJoinModels(QueryExpression query, OrderExpression order)
        {
            var joinModels = new List<IJoinModel>();
            var model1 = new EntityJoinModel(RootMapping, "T0", null, query, order, JoinSetting.None);
            joinModels.Add(model1);
            joinModels.AddRange(models);
            return joinModels;
        }

        private void LoadEntityMapping(DataEntityMapping mapping, RelationLink link)
        {
            var path = link != null ? link.LastFieldPath : string.Empty;
            foreach (var relateFieldMapping in mapping.SingleJoinTableRelationFieldMappings) {
                relateFieldMapping.InitialRelation();
                var add = false;
                if (link == null) {
                    var mLink = new RelationLink(relateFieldMapping, string.Empty);
                    linkList.Add(mLink);
                    LoadEntityMapping(relateFieldMapping.RelateMapping, mLink);
                    add = true;
                }
                else {
                    var fLink = link.Fork();
                    var linkType = fLink.TryAddField(relateFieldMapping);
                    if (linkType == RelationLinkType.NoMatch) {
                        //新开关系链分支加入链集合
                        var mLink = new RelationLink(relateFieldMapping, link.LastFieldPath);
                        linkList.Add(mLink);
                        LoadEntityMapping(relateFieldMapping.RelateMapping, mLink);
                        add = true;
                    }
                    else if (linkType == RelationLinkType.AddLink) {
                        //将原关系链追加后再加入链集合
                        linkList.Add(fLink);
                        LoadEntityMapping(relateFieldMapping.RelateMapping, fLink);
                        add = true;
                    }
                    else {
                        //原关系链已能形成闭环,不需修改
                        cycleDict.Add(fLink.LastFieldPath, fLink.CycleFieldPath);
                    }
                }
                if (add) {
                    var kps = relateFieldMapping.GetKeyPairs();
                    var relates = new string[kps.Length];
                    for (var i = 0; i < kps.Length; i++) {
                        relates[i] = $"{path}.{relateFieldMapping.FieldName}.{kps[i].RelateKey}";
                    }
                    var relate = $"{path}.{relateFieldMapping.FieldName}";
                    singleDict[relate] = relates;
                }
            }
            foreach (var collectFieldMapping in mapping.CollectionRelationFieldMappings) {
                var kps = collectFieldMapping.GetKeyPairs();
                var masters = new string[kps.Length];
                for (var i = 0; i < kps.Length; i++) {
                    masters[i] = $"{path}.{kps[i].MasterKey}";
                }
                var collectField = $"{path}.{collectFieldMapping.FieldName}";
                collectionDict[collectField] = masters;
            }
        }

        public bool CheckValid(string fieldPath, out string aliasName)
        {
            var ret = mapDict.TryGetValue(fieldPath, out var item);
            aliasName = ret ? item.AliasName : null;
            return ret;
        }

        public bool TryGetCycleFieldPath(string fieldPath, out string cycleFieldPath)
        {
            if (cycleDict.Count == 0) {
                cycleFieldPath = null;
                return false;
            }
            return cycleDict.TryGetValue(fieldPath, out cycleFieldPath);
        }

        public bool CheckIsField(string path)
        {
            return fieldInfoDict.ContainsKey(path);
        }

        public bool CheckIsRelateEntity(string path)
        {
            return tableInfoDict.ContainsKey(path);
        }

        public bool CheckIsEntityCollection(string path)
        {
            return collectionDict.ContainsKey(path);
        }

        public DataFieldInfo GetFieldInfoForPath(string path)
        {
            if (fieldInfoDict.TryGetValue(path, out var info)) {
                return info;
            }

            throw new LightDataException(string.Format(SR.CanNotFindTheSpecifiedFieldViaPath, path));
        }

        private DataFieldInfo GetFieldInfoForField(string path)
        {
            if (fieldInfoDict.TryGetValue(path, out var info)) {
                return info;
            }

            throw new LightDataException(string.Format(SR.CanNotFindTheSpecifiedFieldViaPath, path));
        }

        private DataFieldInfo[] GetFieldInfoForSingleField(string path)
        {
            if (singleDict.TryGetValue(path, out var fields)) {
                var infos = new DataFieldInfo[fields.Length];
                for (var i = 0; i < fields.Length; i++) {
                    infos[i] = GetFieldInfoForField(fields[i]);
                }
                return infos;
            }

            throw new LightDataException(string.Format(SR.CanNotFindTheSpecifiedFieldViaPath, path));
        }

        public ISelector GetDefaultSelector()
        {
            return selector;
        }

        private HashSet<string> RewritePaths(string[] paths)
        {
            var ss = new HashSet<string>(paths);
            if (collectionDict.Count > 0) {
                foreach (var path in paths) {
                    if (collectionDict.TryGetValue(path, out var arr)) {
                        foreach (var item in arr) {
                            ss.Add(item);
                        }
                    }
                }
            }
            return ss;
        }

        private HashSet<DataFieldInfo> GetInfos(string[] paths)
        {
            var ss = new HashSet<DataFieldInfo>();
            if (collectionDict.Count > 0) {
                foreach (var path in paths) {
                    if (tableInfoDict.TryGetValue(path, out var arr)) {
                        foreach (var item in arr) {
                            ss.Add(item);
                        }
                    }
                    if (fieldInfoDict.TryGetValue(path, out var field)) {
                        ss.Add(field);
                    }
                }
            }
            return ss;
        }

        public ISelector CreateSelector(string[] paths)
        {
            var allPaths = RewritePaths(paths);
            var hash = new HashSet<DataFieldInfo>();
            var stable = new HashSet<string>();
            foreach (var path in allPaths) {
                if (fieldInfoDict.TryGetValue(path, out var info)) {
                    if (!hash.Contains(info)) {
                        hash.Add(info);
                        var index = path.LastIndexOf('.');
                        if (index > 0) {
                            var t = path.Substring(0, index);
                            if (!stable.Contains(t)) {
                                stable.Add(t);
                                var sInfos = GetFieldInfoForSingleField(t);
                                foreach (var sInfo in sInfos) {
                                    if (!hash.Contains(sInfo)) {
                                        hash.Add(sInfo);
                                    }
                                }
                            }
                        }
                    }
                    continue;
                }
                if (tableInfoDict.TryGetValue(path, out var tInfos)) {
                    foreach (var tInfo in tInfos) {
                        stable.Add(path);
                        if (!hash.Contains(tInfo)) {
                            hash.Add(tInfo);
                        }
                    }
                    continue;
                }
                throw new LightDataException(string.Format(SR.CanNotFindTheSpecifiedFieldViaPath, path));
            }
            if (RootMapping.HasJoinRelateModel) {
                var jSelector = new JoinSelector();
                foreach (var dataFieldInfo in hash)
                {
                    var info = (AliasDataFieldInfo) dataFieldInfo;
                    jSelector.SetAliasDataField(info);
                }
                return jSelector;
            }

            var nSelector = new Selector();
            foreach (var item in hash) {
                nSelector.SetSelectField(item);
            }
            return nSelector;
        }

        public ISelector CreateExceptSelector(string[] paths)
        {
            var exceptInfo = GetInfos(paths);
            if (RootMapping.HasJoinRelateModel) {
                var jSelector = new JoinSelector();
                foreach (var kvs in fieldInfoDict) {
                    if (!exceptInfo.Contains(kvs.Value)) {
                        jSelector.SetAliasDataField(kvs.Value as AliasDataFieldInfo);
                    }
                }
                return jSelector;
            }

            var nSelector = new Selector();
            foreach (var kvs in fieldInfoDict) {
                if (!exceptInfo.Contains(kvs.Value)) {
                    nSelector.SetSelectField(kvs.Value);
                }
            }
            return nSelector;
        }
    }
}


text:
package com.gmail.valetolpegin.scoring_app;

import android.app.Activity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;

public class DriverControlledOptions extends android.app.DialogFragment {
    private EditText mCenterGoalHeight;
    private EditText mLargeGoalHeight;
    private EditText mMediumGoalHeight;
    private EditText mSmallGoalHeight;
    private EditText mNumberInParkingZone;
    private EditText mNumberInRamp;
    private EditText mCurrentTotal;

    private int currentTotal = 0;
    private int centerGoalHeight    = 0;
    private int largeGoalHeight     = 0;
    private int mediumGoalHeight    = 0;
    private int smallGoalHeight     = 0;
    private int numberInParkingZone = 0;
    private int numberInRamp        = 0;

    private getCurrentTotalListener currentTotalListener;

    public interface getCurrentTotalListener
    {
        public void getCurrentTotalDC( int value );
    }

    @Override
    public void onAttach( Activity activity )
    {
        super.onAttach( activity );

        currentTotalListener = (getCurrentTotalListener) activity;
    }

    @Override
    public void onDetach()
    {
        super.onDetach();

        currentTotalListener.getCurrentTotalDC( currentTotal );
    }

    @Override
    public void onCreate( Bundle savedInstanceState )
    {
        super.onCreate( savedInstanceState );
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
    {
        View v = inflater.inflate( R.layout.fragment_driver_controlled_options, parent );

        getDialog().setTitle( "Driver Controlled" );

        currentTotal = 0;

        mCenterGoalHeight = (EditText)v.findViewById( R.id.driver_controlled_centerGoal_count );
        mLargeGoalHeight = (EditText)v.findViewById( R.id.driver_controlled_largeGoal_count );
        mMediumGoalHeight = (EditText)v.findViewById( R.id.driver_controlled_mediumGoal_count );
        mSmallGoalHeight = (EditText)v.findViewById( R.id.driver_controlled_smallGoal_count );
        mNumberInParkingZone = (EditText)v.findViewById( R.id.driver_controlled_parkingZone );
        mNumberInRamp = (EditText)v.findViewById( R.id.driver_controlled_ramp );
        mCurrentTotal = (EditText)v.findViewById( R.id.driver_controlled_currentTotal );

        mCenterGoalHeight.addTextChangedListener( new TextWatcher() {
            public void onTextChanged( CharSequence c, int start, int before, int count )
            {
               //Add watcher code here
            }

            public void beforeTextChanged( CharSequence c, int start, int before, int count )
            {
                //Add watcher code here
            }

            public void afterTextChanged( Editable c )
            {
                try
                {
                    centerGoalHeight = 6 * Integer.parseInt(mCenterGoalHeight.getText().toString());
                    currentTotal = centerGoalHeight + largeGoalHeight + mediumGoalHeight + smallGoalHeight + numberInParkingZone + numberInRamp;
                    mCurrentTotal.setText("" + currentTotal);
                } catch ( NumberFormatException e )
                {
                    mCurrentTotal.setText( "ERROR! PLEASE ENTER A NUMBER, NOT:" + mCenterGoalHeight.getText().toString() );
                }
            }
        });

        mLargeGoalHeight.addTextChangedListener( new TextWatcher() {
            public void onTextChanged( CharSequence c, int start, int before, int count )
            {
                //Add watcher code here
            }

            public void beforeTextChanged( CharSequence c, int start, int before, int count )
            {
                //Add watcher code here
            }

            public void afterTextChanged( Editable c ) {
                try
                {
                    largeGoalHeight = 3 * Integer.parseInt(mLargeGoalHeight.getText().toString());
                    currentTotal = centerGoalHeight + largeGoalHeight + mediumGoalHeight + smallGoalHeight + numberInParkingZone + numberInRamp;
                    mCurrentTotal.setText("" + currentTotal);
                } catch ( NumberFormatException e )
                {
                    mCurrentTotal.setText( "ERROR! PLEASE ENTER A NUMBER, NOT:" + mLargeGoalHeight.getText().toString() );
                }
            }
        });

        mMediumGoalHeight.addTextChangedListener( new TextWatcher() {
            public void onTextChanged( CharSequence c, int start, int before, int count )
            {
                //Add watcher code here
            }

            public void beforeTextChanged( CharSequence c, int start, int before, int count )
            {
                //Add watcher code here
            }

            public void afterTextChanged( Editable c )
            {
                try
                {
                    mediumGoalHeight = 2 * Integer.parseInt(mMediumGoalHeight.getText().toString());
                    currentTotal = centerGoalHeight + largeGoalHeight + mediumGoalHeight + smallGoalHeight + numberInParkingZone + numberInRamp;
                    mCurrentTotal.setText("" + currentTotal);
                } catch ( NumberFormatException e )
                {
                    mCurrentTotal.setText( "ERROR! PLEASE ENTER A NUMBER, NOT:" + mMediumGoalHeight.getText().toString() );
                }
            }
        });

        mSmallGoalHeight.addTextChangedListener( new TextWatcher() {
            public void onTextChanged( CharSequence c, int start, int before, int count )
            {
                //Add watcher code here
            }

            public void beforeTextChanged( CharSequence c, int start, int before, int count )
            {
                //Add watcher code here
            }

            public void afterTextChanged( Editable c )
            {
                try
                {
                    smallGoalHeight = Integer.parseInt(mSmallGoalHeight.getText().toString());
                    currentTotal = centerGoalHeight + largeGoalHeight + mediumGoalHeight + smallGoalHeight + numberInParkingZone + numberInRamp;
                    mCurrentTotal.setText( "" + currentTotal );
                } catch ( NumberFormatException e )
                {
                    mCurrentTotal.setText( "ERROR! PLEASE ENTER A NUMBER, NOT:" + mSmallGoalHeight.getText().toString() );
                }
            }
        });

        mNumberInParkingZone.addTextChangedListener(new TextWatcher() {
            public void onTextChanged(CharSequence c, int start, int before, int count) {
                //Add watcher code here
            }

            public void beforeTextChanged(CharSequence c, int start, int before, int count) {
                //Add watcher code here
            }

            public void afterTextChanged(Editable c) {
                try
                {
                    numberInParkingZone = 10 * Integer.parseInt(mNumberInParkingZone.getText().toString());
                    currentTotal = centerGoalHeight + largeGoalHeight + mediumGoalHeight + smallGoalHeight + numberInParkingZone + numberInRamp;
                    mCurrentTotal.setText("" + currentTotal);
                } catch ( NumberFormatException e )
                {
                    mCurrentTotal.setText( "ERROR! PLEASE ENTER A NUMBER, NOT:" + mNumberInParkingZone.getText().toString() );
                }
            }
        });

        mNumberInRamp.addTextChangedListener( new TextWatcher() {
            public void onTextChanged( CharSequence c, int start, int before, int count )
            {
                //Add watcher code here
            }

            public void beforeTextChanged( CharSequence c, int start, int before, int count )
            {
                //Add watcher code here
            }

            public void afterTextChanged( Editable c )
            {
                try
                {
                    numberInRamp = 30 * Integer.parseInt( mNumberInRamp.getText().toString() );
                    currentTotal = centerGoalHeight + largeGoalHeight + mediumGoalHeight + smallGoalHeight + numberInParkingZone + numberInRamp;
                    mCurrentTotal.setText( "" + currentTotal );
                } catch ( NumberFormatException e )
                {
                    mCurrentTotal.setText( "ERROR! PLEASE ENTER A NUMBER, NOT:" + mNumberInRamp.getText().toString() );
                }
            }
        });

        return v;
    }
}