UI Updates
* Browser now has tabs * Fixed a callback issue
This commit is contained in:
		@@ -9,15 +9,16 @@ import Ethereum 1.0
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Rectangle {
 | 
					Rectangle {
 | 
				
			||||||
	id: window
 | 
						id: window
 | 
				
			||||||
	objectName: "browserView"
 | 
					 | 
				
			||||||
	anchors.fill: parent
 | 
						anchors.fill: parent
 | 
				
			||||||
	color: "#00000000"
 | 
						color: "#00000000"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	property var title: "Browser"
 | 
						property var title: "DApps"
 | 
				
			||||||
	property var iconSource: "../browser.png"
 | 
						property var iconSource: "../browser.png"
 | 
				
			||||||
	property var menuItem
 | 
						property var menuItem
 | 
				
			||||||
 | 
					    property var hideUrl: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	property alias url: webview.url
 | 
						property alias url: webview.url
 | 
				
			||||||
 | 
					    property alias windowTitle: webview.title
 | 
				
			||||||
	property alias webView: webview
 | 
						property alias webView: webview
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	property var cleanPath: false
 | 
						property var cleanPath: false
 | 
				
			||||||
@@ -66,8 +67,7 @@ Rectangle {
 | 
				
			|||||||
		webview.url = "http://etherian.io"
 | 
							webview.url = "http://etherian.io"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	signal messages(var messages, int id);
 | 
					    function messages(messages, id) {
 | 
				
			||||||
	onMessages: {
 | 
					 | 
				
			||||||
		// Bit of a cheat to get proper JSON
 | 
							// Bit of a cheat to get proper JSON
 | 
				
			||||||
		var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
 | 
							var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
 | 
				
			||||||
		webview.postEvent("eth_changed", id, m);
 | 
							webview.postEvent("eth_changed", id, m);
 | 
				
			||||||
@@ -164,22 +164,10 @@ Rectangle {
 | 
				
			|||||||
				id: webview
 | 
									id: webview
 | 
				
			||||||
				anchors.fill: parent
 | 
									anchors.fill: parent
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				function injectJs(js) {
 | 
					 | 
				
			||||||
					webview.experimental.navigatorQtObjectEnabled = true;
 | 
					 | 
				
			||||||
					webview.experimental.evaluateJavaScript(js)
 | 
					 | 
				
			||||||
					webview.experimental.javascriptEnabled = true;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				function sendMessage(data) {
 | 
									function sendMessage(data) {
 | 
				
			||||||
					webview.experimental.postMessage(JSON.stringify(data))
 | 
										webview.experimental.postMessage(JSON.stringify(data))
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				Component.onCompleted: {
 | 
					 | 
				
			||||||
					for (var i in experimental.preferences) {
 | 
					 | 
				
			||||||
						console.log(i)
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				experimental.preferences.javascriptEnabled: true
 | 
									experimental.preferences.javascriptEnabled: true
 | 
				
			||||||
				experimental.preferences.webAudioEnabled: true
 | 
									experimental.preferences.webAudioEnabled: true
 | 
				
			||||||
				experimental.preferences.pluginsEnabled: true
 | 
									experimental.preferences.pluginsEnabled: true
 | 
				
			||||||
@@ -219,8 +207,7 @@ Rectangle {
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
				experimental.userScripts: ["../ext/q.js", "../ext/ethereum.js/lib/web3.js", "../ext/ethereum.js/lib/qt.js", "../ext/setup.js"]
 | 
									experimental.userScripts: ["../ext/q.js", "../ext/ethereum.js/lib/web3.js", "../ext/ethereum.js/lib/qt.js", "../ext/setup.js"]
 | 
				
			||||||
				experimental.onMessageReceived: {
 | 
									experimental.onMessageReceived: {
 | 
				
			||||||
					console.log("[onMessageReceived]: ", message.data)
 | 
										//console.log("[onMessageReceived]: ", message.data)
 | 
				
			||||||
					// TODO move to messaging.js
 | 
					 | 
				
			||||||
					var data = JSON.parse(message.data)
 | 
										var data = JSON.parse(message.data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					try {
 | 
										try {
 | 
				
			||||||
@@ -350,13 +337,13 @@ Rectangle {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
							case "eth_newFilterString":
 | 
												case "eth_newFilterString":
 | 
				
			||||||
							require(1)
 | 
												require(1)
 | 
				
			||||||
							var id = eth.newFilterString(data.args[0])
 | 
												var id = eth.newFilterString(data.args[0], window)
 | 
				
			||||||
							postData(data._id, id);
 | 
												postData(data._id, id);
 | 
				
			||||||
							break;
 | 
												break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							case "eth_newFilter":
 | 
												case "eth_newFilter":
 | 
				
			||||||
							require(1)
 | 
												require(1)
 | 
				
			||||||
							var id = eth.newFilter(data.args[0])
 | 
												var id = eth.newFilter(data.args[0], window)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							postData(data._id, id);
 | 
												postData(data._id, id);
 | 
				
			||||||
							break;
 | 
												break;
 | 
				
			||||||
@@ -425,11 +412,9 @@ Rectangle {
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
				function post(seed, data) {
 | 
									function post(seed, data) {
 | 
				
			||||||
					postData(data._id, data)
 | 
										postData(data._id, data)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					 | 
				
			||||||
				function require(args, num) {
 | 
									function require(args, num) {
 | 
				
			||||||
					if(args.length < num) {
 | 
										if(args.length < num) {
 | 
				
			||||||
						throw("required argument count of "+num+" got "+args.length);
 | 
											throw("required argument count of "+num+" got "+args.length);
 | 
				
			||||||
@@ -441,12 +426,10 @@ Rectangle {
 | 
				
			|||||||
				function postEvent(event, id, data) {
 | 
									function postEvent(event, id, data) {
 | 
				
			||||||
					webview.experimental.postMessage(JSON.stringify({data: data, _id: id, _event: event}))
 | 
										webview.experimental.postMessage(JSON.stringify({data: data, _id: id, _event: event}))
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					 | 
				
			||||||
				function onWatchedCb(data, id) {
 | 
									function onWatchedCb(data, id) {
 | 
				
			||||||
					var messages = JSON.parse(data)
 | 
										var messages = JSON.parse(data)
 | 
				
			||||||
					postEvent("watched:"+id, messages)
 | 
										postEvent("watched:"+id, messages)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					 | 
				
			||||||
				function onNewBlockCb(block) {
 | 
									function onNewBlockCb(block) {
 | 
				
			||||||
					postEvent("block:new", block)
 | 
										postEvent("block:new", block)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@@ -460,7 +443,6 @@ Rectangle {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
		Rectangle {
 | 
							Rectangle {
 | 
				
			||||||
			id: sizeGrip
 | 
								id: sizeGrip
 | 
				
			||||||
			color: "gray"
 | 
								color: "gray"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,6 @@ ApplicationWindow {
 | 
				
			|||||||
	id: root
 | 
						id: root
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	property var ethx : Eth.ethx
 | 
						property var ethx : Eth.ethx
 | 
				
			||||||
	property var browser
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	width: 1200
 | 
						width: 1200
 | 
				
			||||||
	height: 820
 | 
						height: 820
 | 
				
			||||||
@@ -21,6 +20,7 @@ ApplicationWindow {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	title: "Mist"
 | 
						title: "Mist"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
	// This signal is used by the filter API. The filter API connects using this signal handler from
 | 
						// This signal is used by the filter API. The filter API connects using this signal handler from
 | 
				
			||||||
	// the different QML files and plugins.
 | 
						// the different QML files and plugins.
 | 
				
			||||||
	signal messages(var messages, int id);
 | 
						signal messages(var messages, int id);
 | 
				
			||||||
@@ -30,6 +30,7 @@ ApplicationWindow {
 | 
				
			|||||||
		messages(data, receiverSeed);
 | 
							messages(data, receiverSeed);
 | 
				
			||||||
		root.browser.view.messages(data, receiverSeed);
 | 
							root.browser.view.messages(data, receiverSeed);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	TextField {
 | 
						TextField {
 | 
				
			||||||
		id: copyElementHax
 | 
							id: copyElementHax
 | 
				
			||||||
@@ -45,8 +46,6 @@ ApplicationWindow {
 | 
				
			|||||||
	// Takes care of loading all default plugins
 | 
						// Takes care of loading all default plugins
 | 
				
			||||||
	Component.onCompleted: {
 | 
						Component.onCompleted: {
 | 
				
			||||||
		var wallet = addPlugin("./views/wallet.qml", {noAdd: true, close: false, section: "ethereum", active: true});
 | 
							var wallet = addPlugin("./views/wallet.qml", {noAdd: true, close: false, section: "ethereum", active: true});
 | 
				
			||||||
		var browser = addPlugin("./browser.qml", {noAdd: true, close: false, section: "ethereum", active: true});
 | 
					 | 
				
			||||||
		root.browser = browser;
 | 
					 | 
				
			||||||
		addPlugin("./views/miner.qml", {noAdd: true, close: false, section: "ethereum", active: true});
 | 
							addPlugin("./views/miner.qml", {noAdd: true, close: false, section: "ethereum", active: true});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		addPlugin("./views/transaction.qml", {noAdd: true, close: false, section: "legacy"});
 | 
							addPlugin("./views/transaction.qml", {noAdd: true, close: false, section: "legacy"});
 | 
				
			||||||
@@ -55,17 +54,17 @@ ApplicationWindow {
 | 
				
			|||||||
		addPlugin("./views/pending_tx.qml", {noAdd: true, close: false, section: "legacy"});
 | 
							addPlugin("./views/pending_tx.qml", {noAdd: true, close: false, section: "legacy"});
 | 
				
			||||||
		addPlugin("./views/info.qml", {noAdd: true, close: false, section: "legacy"});
 | 
							addPlugin("./views/info.qml", {noAdd: true, close: false, section: "legacy"});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		addPlugin("./views/jeffcoin/jeffcoin.qml", {noAdd: true, close: false, section: "apps"})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		mainSplit.setView(wallet.view, wallet.menuItem);
 | 
							mainSplit.setView(wallet.view, wallet.menuItem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        newBrowserTab("http://etherian.io");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Command setup
 | 
							// Command setup
 | 
				
			||||||
		gui.sendCommand(0)
 | 
							gui.sendCommand(0)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	function activeView(view, menuItem) {
 | 
						function activeView(view, menuItem) {
 | 
				
			||||||
		mainSplit.setView(view, menuItem)
 | 
							mainSplit.setView(view, menuItem)
 | 
				
			||||||
		if (view.objectName === "browserView") {
 | 
					        if (view.hideUrl) {
 | 
				
			||||||
			urlPane.visible = false;
 | 
								urlPane.visible = false;
 | 
				
			||||||
			mainView.anchors.top = rootView.top
 | 
								mainView.anchors.top = rootView.top
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
@@ -119,6 +118,13 @@ ApplicationWindow {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function newBrowserTab(url) {
 | 
				
			||||||
 | 
							var window = addPlugin("./browser.qml", {noAdd: true, close: true, section: "apps", active: true});
 | 
				
			||||||
 | 
					        window.view.url = url;
 | 
				
			||||||
 | 
					        window.menuItem.title = "Browser Tab";
 | 
				
			||||||
 | 
					        activeView(window.view, window.menuItem);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	menuBar: MenuBar {
 | 
						menuBar: MenuBar {
 | 
				
			||||||
		Menu {
 | 
							Menu {
 | 
				
			||||||
			title: "File"
 | 
								title: "File"
 | 
				
			||||||
@@ -130,13 +136,6 @@ ApplicationWindow {
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/*
 | 
					 | 
				
			||||||
			 MenuItem {
 | 
					 | 
				
			||||||
				 text: "Browser"
 | 
					 | 
				
			||||||
				 onTriggered: eth.openBrowser()
 | 
					 | 
				
			||||||
			 }
 | 
					 | 
				
			||||||
			 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			MenuItem {
 | 
								MenuItem {
 | 
				
			||||||
				text: "Add plugin"
 | 
									text: "Add plugin"
 | 
				
			||||||
				onTriggered: {
 | 
									onTriggered: {
 | 
				
			||||||
@@ -146,6 +145,14 @@ ApplicationWindow {
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            MenuItem {
 | 
				
			||||||
 | 
					                text: "New tab"
 | 
				
			||||||
 | 
					                shortcut: "Ctrl+t"
 | 
				
			||||||
 | 
					                onTriggered: {
 | 
				
			||||||
 | 
					                    newBrowserTab("http://etherian.io");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			MenuSeparator {}
 | 
								MenuSeparator {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			MenuItem {
 | 
								MenuItem {
 | 
				
			||||||
@@ -205,21 +212,6 @@ ApplicationWindow {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			MenuSeparator {}
 | 
								MenuSeparator {}
 | 
				
			||||||
 | 
					 | 
				
			||||||
			/*
 | 
					 | 
				
			||||||
			 MenuItem {
 | 
					 | 
				
			||||||
				 id: miningSpeed
 | 
					 | 
				
			||||||
				 text: "Mining: Turbo"
 | 
					 | 
				
			||||||
				 onTriggered: {
 | 
					 | 
				
			||||||
					 gui.toggleTurboMining()
 | 
					 | 
				
			||||||
					 if(text == "Mining: Turbo") {
 | 
					 | 
				
			||||||
						 text = "Mining: Normal";
 | 
					 | 
				
			||||||
					 } else {
 | 
					 | 
				
			||||||
						 text = "Mining: Turbo";
 | 
					 | 
				
			||||||
					 }
 | 
					 | 
				
			||||||
				 }
 | 
					 | 
				
			||||||
			 }
 | 
					 | 
				
			||||||
			 */
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Menu {
 | 
							Menu {
 | 
				
			||||||
@@ -350,9 +342,6 @@ ApplicationWindow {
 | 
				
			|||||||
				views[i].menuItem.setSelection(false)
 | 
									views[i].menuItem.setSelection(false)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			view.visible = true
 | 
								view.visible = true
 | 
				
			||||||
 | 
					 | 
				
			||||||
			//menu.border.color = "#CCCCCC"
 | 
					 | 
				
			||||||
			//menu.color = "#FFFFFFFF"
 | 
					 | 
				
			||||||
			menu.setSelection(true)
 | 
								menu.setSelection(true)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -512,7 +501,15 @@ ApplicationWindow {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
						 this.view.destroy()
 | 
											 this.view.destroy()
 | 
				
			||||||
						 this.destroy()
 | 
											 this.destroy()
 | 
				
			||||||
 | 
					                         for (var i = 0; i < mainSplit.views.length; i++) {
 | 
				
			||||||
 | 
					                             var view = mainSplit.views[i];
 | 
				
			||||||
 | 
					                             if (view.menuItem === this) {
 | 
				
			||||||
 | 
					                                 mainSplit.views.splice(i, 1);
 | 
				
			||||||
 | 
					                                 break;
 | 
				
			||||||
 | 
					                             }
 | 
				
			||||||
 | 
					                         }
 | 
				
			||||||
						 gui.removePlugin(this.path)
 | 
											 gui.removePlugin(this.path)
 | 
				
			||||||
 | 
					                         activeView(mainSplit.views[0].view, mainSplit.views[0].menuItem);
 | 
				
			||||||
					 }
 | 
										 }
 | 
				
			||||||
				 }
 | 
									 }
 | 
				
			||||||
			 }
 | 
								 }
 | 
				
			||||||
@@ -576,7 +573,7 @@ ApplicationWindow {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				 Text {
 | 
									 Text {
 | 
				
			||||||
					 text: "APPS"
 | 
										 text: "NET"
 | 
				
			||||||
					 font.bold: true
 | 
										 font.bold: true
 | 
				
			||||||
					 anchors {
 | 
										 anchors {
 | 
				
			||||||
						 left: parent.left
 | 
											 left: parent.left
 | 
				
			||||||
@@ -653,7 +650,7 @@ ApplicationWindow {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
					  Keys.onReturnPressed: {
 | 
										  Keys.onReturnPressed: {
 | 
				
			||||||
						  if(/^https?/.test(this.text)) {
 | 
											  if(/^https?/.test(this.text)) {
 | 
				
			||||||
							  activeView(root.browser.view, root.browser.menuItem);
 | 
					                              newBrowserTab(this.text);
 | 
				
			||||||
						  } else {
 | 
											  } else {
 | 
				
			||||||
							  addPlugin(this.text, {close: true, section: "apps"})
 | 
												  addPlugin(this.text, {close: true, section: "apps"})
 | 
				
			||||||
						  }
 | 
											  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,6 @@ Rectangle {
 | 
				
			|||||||
	property var identity: ""
 | 
						property var identity: ""
 | 
				
			||||||
	Component.onCompleted: {
 | 
						Component.onCompleted: {
 | 
				
			||||||
		identity = shh.newIdentity()
 | 
							identity = shh.newIdentity()
 | 
				
			||||||
		console.log("New identity:", identity)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var t = shh.watch({}, root)
 | 
							var t = shh.watch({}, root)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -316,20 +316,15 @@ func (self *UiLib) NewFilter(object map[string]interface{}, view *qml.Common) (i
 | 
				
			|||||||
	filter := qt.NewFilterFromMap(object, self.eth)
 | 
						filter := qt.NewFilterFromMap(object, self.eth)
 | 
				
			||||||
	filter.MessageCallback = func(messages state.Messages) {
 | 
						filter.MessageCallback = func(messages state.Messages) {
 | 
				
			||||||
		view.Call("messages", xeth.ToJSMessages(messages), id)
 | 
							view.Call("messages", xeth.ToJSMessages(messages), id)
 | 
				
			||||||
		//self.win.Root().Call("invokeFilterCallback", xeth.ToJSMessages(messages), id)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	id = self.filterManager.InstallFilter(filter)
 | 
						id = self.filterManager.InstallFilter(filter)
 | 
				
			||||||
	return id
 | 
						return id
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self *UiLib) NewFilterString(typ string) (id int) {
 | 
					func (self *UiLib) NewFilterString(typ string, view *qml.Common) (id int) {
 | 
				
			||||||
	filter := core.NewFilter(self.eth)
 | 
						filter := core.NewFilter(self.eth)
 | 
				
			||||||
	filter.BlockCallback = func(block *types.Block) {
 | 
						filter.BlockCallback = func(block *types.Block) {
 | 
				
			||||||
		if self.win != nil && self.win.Root() != nil {
 | 
							view.Call("messages", "{}", id)
 | 
				
			||||||
			self.win.Root().Call("invokeFilterCallback", "{}", id)
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			fmt.Println("QML is lagging")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	id = self.filterManager.InstallFilter(filter)
 | 
						id = self.filterManager.InstallFilter(filter)
 | 
				
			||||||
	return id
 | 
						return id
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -81,7 +81,7 @@ func (self *peer) broadcast(envelopes []*Envelope) error {
 | 
				
			|||||||
		if err := self.ws.WriteMsg(msg); err != nil {
 | 
							if err := self.ws.WriteMsg(msg); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		self.peer.Infoln("broadcasted", i, "message(s)")
 | 
							self.peer.DebugDetailln("broadcasted", i, "message(s)")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user