Compare commits
	
		
			20 Commits
		
	
	
		
			revert-571
			...
			cli
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					1ea23e53e7 | ||
| 
						 | 
					f6c66248c8 | ||
| 
						 | 
					9bffd0c5d5 | ||
| 
						 | 
					1ddfa671c7 | ||
| 
						 | 
					886ac8e859 | ||
| 
						 | 
					7e121dc647 | ||
| 
						 | 
					83ce018bef | ||
| 
						 | 
					3b6b4a5694 | ||
| 
						 | 
					f8e0dbd5b7 | ||
| 
						 | 
					af5449b78f | ||
| 
						 | 
					c9df2db962 | ||
| 
						 | 
					bc757c09d4 | ||
| 
						 | 
					7b3fe0e1dc | ||
| 
						 | 
					0609c7e0ac | ||
| 
						 | 
					1a802d1e7f | ||
| 
						 | 
					efd2c47a3f | ||
| 
						 | 
					45fb644658 | ||
| 
						 | 
					b0d72c49bc | ||
| 
						 | 
					e2b4c87c03 | ||
| 
						 | 
					f1f8439726 | 
							
								
								
									
										22
									
								
								ideas/cli/bundle.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								ideas/cli/bundle.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
{
 | 
			
		||||
    "extensions": {
 | 
			
		||||
        "routes": [
 | 
			
		||||
            {
 | 
			
		||||
                "when": "/cli",
 | 
			
		||||
                "templateUrl": "templates/cli.html"
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "controllers": [
 | 
			
		||||
            {
 | 
			
		||||
                "key": "CLIController",
 | 
			
		||||
                "implementation": "CLIController.js",
 | 
			
		||||
                "depends": [ "$scope", "navigationService", "objectService" ]
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "stylesheets": [
 | 
			
		||||
            {
 | 
			
		||||
                "stylesheetUrl": "stylesheets/cli.css"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										47
									
								
								ideas/cli/res/stylesheets/cli.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								ideas/cli/res/stylesheets/cli.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
.iw-container {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    bottom: 30px;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    right: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.iw-stdin {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    height: 30px;
 | 
			
		||||
    width: calc(100% - 8px);
 | 
			
		||||
    margin: 4px;
 | 
			
		||||
    font-family: monospace;
 | 
			
		||||
    font-size: 16px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.iw-stdout {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    left: 6px;
 | 
			
		||||
    right: 6px;
 | 
			
		||||
    top: 12px;
 | 
			
		||||
    bottom: 44px;
 | 
			
		||||
    border: 1px #211 solid;
 | 
			
		||||
    border-radius: 12px;
 | 
			
		||||
    padding: 8px;
 | 
			
		||||
    background: #302;
 | 
			
		||||
    overflow: auto;
 | 
			
		||||
    box-shadow: inset 0px 2px 8px 0px rgba(0, 0, 0, 0.5);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.iw-stdout span {
 | 
			
		||||
    display: block;
 | 
			
		||||
    font-family: monospace;
 | 
			
		||||
    color: #FD9;
 | 
			
		||||
    font-size: 16px;
 | 
			
		||||
    margin-top: 2px;
 | 
			
		||||
    margin-bottom: 2px;
 | 
			
		||||
    min-height: 1em;
 | 
			
		||||
    white-space: pre;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.iw-stdout span.iw-user-input {
 | 
			
		||||
    color: gray;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								ideas/cli/res/templates/cli.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								ideas/cli/res/templates/cli.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
<div class="abs holder-all browse-mode" ng-controller="CLIController">
 | 
			
		||||
    <div class="iw-container">
 | 
			
		||||
        <div class="iw-stdout" mct-scroll-y="stdoutScroll">
 | 
			
		||||
            <span ng-repeat="line in stdout track by $index"
 | 
			
		||||
                  class="{{line.cssClass}}"
 | 
			
		||||
                  ng-bind="line.text">
 | 
			
		||||
            </span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <form ng-submit="enter(stdin)">
 | 
			
		||||
            <input type="text" class="iw-stdin" ng-model="stdin" autofocus>
 | 
			
		||||
        </form>
 | 
			
		||||
    </div>
 | 
			
		||||
    <mct-include key="'bottombar'"></mct-include>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										177
									
								
								ideas/cli/src/CLIController.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								ideas/cli/src/CLIController.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,177 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*global define*/
 | 
			
		||||
 | 
			
		||||
define(function () {
 | 
			
		||||
    'use strict';
 | 
			
		||||
    return function CLIController($scope, navigationService, objectService) {
 | 
			
		||||
        var unlistenToMutation,
 | 
			
		||||
            currentComposition = [];
 | 
			
		||||
 | 
			
		||||
        function print(str, cssClass) {
 | 
			
		||||
            $scope.stdout.push({
 | 
			
		||||
                text: str,
 | 
			
		||||
                cssClass: cssClass
 | 
			
		||||
            });
 | 
			
		||||
            $scope.stdoutScroll = Number.MAX_VALUE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function pad(str, length) {
 | 
			
		||||
            while (str.length < length) {
 | 
			
		||||
                str += " ";
 | 
			
		||||
            }
 | 
			
		||||
            return str;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function summarize(domainObject) {
 | 
			
		||||
            var type = domainObject.getCapability("type"),
 | 
			
		||||
                typeName = type ? type.getName() : "Object",
 | 
			
		||||
                location = domainObject.getCapability('location'),
 | 
			
		||||
                isLink = (location && location.isLink()),
 | 
			
		||||
                suffix = isLink ? " (link)" : "";
 | 
			
		||||
            return "[" + typeName + "] " + domainObject.getModel().name + suffix;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function printComposition(domainObject) {
 | 
			
		||||
            return domainObject.useCapability("composition").then(function (c) {
 | 
			
		||||
                currentComposition = c;
 | 
			
		||||
                c.forEach(function (childObject, i) {
 | 
			
		||||
                    print(i + ") " + summarize(childObject));
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function printObject(domainObject, callback) {
 | 
			
		||||
            // Exclude the root object; nobody wants to see that
 | 
			
		||||
            if (domainObject.hasCapability("context")) {
 | 
			
		||||
                print(summarize(domainObject));
 | 
			
		||||
            }
 | 
			
		||||
            if (domainObject.hasCapability('composition')) {
 | 
			
		||||
                printComposition(domainObject).then(callback);
 | 
			
		||||
            } else {
 | 
			
		||||
                callback();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function unlisten() {
 | 
			
		||||
            if (unlistenToMutation) {
 | 
			
		||||
                unlistenToMutation();
 | 
			
		||||
                unlistenToMutation = undefined;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function navChange(domainObject) {
 | 
			
		||||
            unlisten();
 | 
			
		||||
            unlistenToMutation = domainObject.getCapability("mutation")
 | 
			
		||||
                .listen(function () { printObject(domainObject); });
 | 
			
		||||
            printObject(domainObject);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function findTarget(id) {
 | 
			
		||||
            if (id === "this") {
 | 
			
		||||
                return navigationService.getNavigation();
 | 
			
		||||
            } else {
 | 
			
		||||
                return currentComposition[parseInt(id, 10)];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function listActions(domainObject, index) {
 | 
			
		||||
            // Don't show actions for the root
 | 
			
		||||
            if (!domainObject.hasCapability('context')) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            domainObject.getCapability('action').getActions().forEach(function (a) {
 | 
			
		||||
                var metadata = a.getMetadata(),
 | 
			
		||||
                    desc = metadata.description,
 | 
			
		||||
                    suffix = index !== undefined ? (" " + index) : "";
 | 
			
		||||
                print(pad(metadata.key + suffix, 32) + (desc || ""));
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function performAction(domainObject, action) {
 | 
			
		||||
            domainObject.getCapability('action').perform(action);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function handleInput(input) {
 | 
			
		||||
            var parts = input.split(" "),
 | 
			
		||||
                targetObject;
 | 
			
		||||
 | 
			
		||||
            if (input.length === 0) {
 | 
			
		||||
                targetObject = navigationService.getNavigation();
 | 
			
		||||
                if (targetObject) {
 | 
			
		||||
                    printObject(targetObject, function () {
 | 
			
		||||
                        print("");
 | 
			
		||||
                        listActions(targetObject);
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
                return;
 | 
			
		||||
            } else if (parts.length === 1) {
 | 
			
		||||
                if (isNaN(parseInt(parts[0], 10))) {
 | 
			
		||||
                    targetObject = navigationService.getNavigation();
 | 
			
		||||
                    performAction(targetObject, parts[0]);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                targetObject = findTarget(parts[0]);
 | 
			
		||||
                if (targetObject) {
 | 
			
		||||
                    listActions(targetObject, parts[0]);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            } else if (parts.length === 2) {
 | 
			
		||||
                targetObject = findTarget(parts[1]);
 | 
			
		||||
                if (targetObject) {
 | 
			
		||||
                    performAction(targetObject, parts[0]);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Any parse-able input should have returned already.
 | 
			
		||||
            print("SYNTAX ERROR. READY.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!navigationService.getNavigation()) {
 | 
			
		||||
            objectService.getObjects(["ROOT"]).then(function (objects) {
 | 
			
		||||
                navigationService.setNavigation(objects.ROOT);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        navigationService.addListener(navChange);
 | 
			
		||||
 | 
			
		||||
        $scope.stdout = [];
 | 
			
		||||
        $scope.stdin = "";
 | 
			
		||||
        $scope.stdoutScroll = 0;
 | 
			
		||||
 | 
			
		||||
        $scope.enter = function (input) {
 | 
			
		||||
            $scope.stdin = "";
 | 
			
		||||
            print("");
 | 
			
		||||
            print(input, "iw-user-input");
 | 
			
		||||
            print("");
 | 
			
		||||
 | 
			
		||||
            handleInput(input);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        $scope.$on("$destroy", function () {
 | 
			
		||||
            navigationService.removeListener(navChange);
 | 
			
		||||
            unlisten();
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
});
 | 
			
		||||
@@ -105,9 +105,15 @@
 | 
			
		||||
        "actions": [
 | 
			
		||||
            {
 | 
			
		||||
                "key": "navigate",
 | 
			
		||||
                "description": "Browse to this object.",
 | 
			
		||||
                "implementation": "navigation/NavigateAction.js",
 | 
			
		||||
                "depends": [ "navigationService", "$q" ]
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "key": "back",
 | 
			
		||||
                "implementation": "navigation/BackAction.js",
 | 
			
		||||
                "description": "Navigate to the parent of this object."
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "key": "window",
 | 
			
		||||
                "name": "Open In New Tab",
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@
 | 
			
		||||
<a
 | 
			
		||||
   class='type-icon icon ui-symbol s-back'
 | 
			
		||||
   ng-show="context.getPath().length > 2"
 | 
			
		||||
   ng-click="context.getParent().getCapability('action').perform('navigate')">
 | 
			
		||||
   ng-click="domainObject.getCapability('action').perform('back')">
 | 
			
		||||
    {
 | 
			
		||||
</a>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -53,11 +53,12 @@ define(
 | 
			
		||||
         */
 | 
			
		||||
        function CreateAction(type, parent, context, dialogService, creationService, policyService) {
 | 
			
		||||
            this.metadata = {
 | 
			
		||||
                key: 'create',
 | 
			
		||||
                key: 'create.' + type.getKey(),
 | 
			
		||||
                glyph: type.getGlyph(),
 | 
			
		||||
                name: type.getName(),
 | 
			
		||||
                type: type.getKey(),
 | 
			
		||||
                description: type.getDescription(),
 | 
			
		||||
                category: [ 'creation' ],
 | 
			
		||||
                context: context
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -63,7 +63,10 @@ define(
 | 
			
		||||
            // domain object to serve as the container for the
 | 
			
		||||
            // newly-created object (although the user may later
 | 
			
		||||
            // make a different selection)
 | 
			
		||||
            if (key !== 'create' || !destination) {
 | 
			
		||||
            if (!destination) {
 | 
			
		||||
                return [];
 | 
			
		||||
            }
 | 
			
		||||
            if (context.category && context.category !== "creation") {
 | 
			
		||||
                return [];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ define(
 | 
			
		||||
            // Update the set of Create actions
 | 
			
		||||
            function refreshActions() {
 | 
			
		||||
                $scope.createActions = $scope.action ?
 | 
			
		||||
                        $scope.action.getActions('create') :
 | 
			
		||||
                        $scope.action.getActions({ category: "creation" }) :
 | 
			
		||||
                        [];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										68
									
								
								platform/commonUI/browse/src/navigation/BackAction.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								platform/commonUI/browse/src/navigation/BackAction.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*global define,Promise*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Module defining NavigateAction. Created by vwoeltje on 11/10/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
        "use strict";
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * The `back` action navigates to the contextual parent of a
 | 
			
		||||
         * specific domain object.
 | 
			
		||||
         * @memberof platform/commonUI/browse
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @implements {Action}
 | 
			
		||||
         */
 | 
			
		||||
        function BackAction(context) {
 | 
			
		||||
            this.domainObject = context.domainObject;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Navigate to the object described in the context.
 | 
			
		||||
         * @returns {Promise} a promise that is resolved once the
 | 
			
		||||
         *          navigation has been updated
 | 
			
		||||
         */
 | 
			
		||||
        BackAction.prototype.perform = function () {
 | 
			
		||||
            var parent = this.domainObject.getCapability("context")
 | 
			
		||||
                    .getParent();
 | 
			
		||||
            return parent.getCapability("action").perform("navigate");
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Navigate as an action is only applicable when a domain object
 | 
			
		||||
         * is described in the action context.
 | 
			
		||||
         * @param {ActionContext} context the context in which the action
 | 
			
		||||
         *        will be performed
 | 
			
		||||
         * @returns {boolean} true if applicable
 | 
			
		||||
         */
 | 
			
		||||
        BackAction.appliesTo = function (context) {
 | 
			
		||||
            return context.domainObject !== undefined &&
 | 
			
		||||
                    context.domainObject.hasCapability("context");
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return BackAction;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -53,9 +53,10 @@ define(
 | 
			
		||||
            // based on whether or not we are currently
 | 
			
		||||
            // full screen.
 | 
			
		||||
            var metadata = Object.create(FullscreenAction);
 | 
			
		||||
            metadata.key = "fullscreen";
 | 
			
		||||
            metadata.glyph = screenfull.isFullscreen ? "_" : "z";
 | 
			
		||||
            metadata.description = screenfull.isFullscreen ?
 | 
			
		||||
                EXIT_FULLSCREEN : ENTER_FULLSCREEN;
 | 
			
		||||
                    EXIT_FULLSCREEN : ENTER_FULLSCREEN;
 | 
			
		||||
            metadata.group = "windowing";
 | 
			
		||||
            metadata.context = this.context;
 | 
			
		||||
            return metadata;
 | 
			
		||||
 
 | 
			
		||||
@@ -49,17 +49,22 @@ define(
 | 
			
		||||
                var expr = attrs[attribute],
 | 
			
		||||
                    parsed = $parse(expr);
 | 
			
		||||
 | 
			
		||||
                // Set the element's scroll to match the scope's state
 | 
			
		||||
                function updateElement(value) {
 | 
			
		||||
                    element[0][property] = value;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Handle event; assign to scroll state to scope
 | 
			
		||||
                function updateScope() {
 | 
			
		||||
                    parsed.assign(scope, element[0][property]);
 | 
			
		||||
                    scope.$apply(expr);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Set the element's scroll to match the scope's state
 | 
			
		||||
                function updateElement(value) {
 | 
			
		||||
                    element[0][property] = value;
 | 
			
		||||
                    // Some values may be out of range for the scroll bar,
 | 
			
		||||
                    // so publish the real scroll value back into scope.
 | 
			
		||||
                    if (element[0][property] !== value) {
 | 
			
		||||
                        parsed.assign(scope, element[0][property]);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Initialize state in scope
 | 
			
		||||
                parsed.assign(scope, element[0][property]);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user