Init nand2tetris
This commit is contained in:
27
projects/09/Average/Main.jack
Normal file
27
projects/09/Average/Main.jack
Normal file
@@ -0,0 +1,27 @@
|
||||
// This file is part of www.nand2tetris.org
|
||||
// and the book "The Elements of Computing Systems"
|
||||
// by Nisan and Schocken, MIT Press.
|
||||
// File name: projects/09/Average/Main.jack
|
||||
|
||||
// Inputs some numbers and computes their average
|
||||
class Main {
|
||||
function void main() {
|
||||
var Array a;
|
||||
var int length;
|
||||
var int i, sum;
|
||||
|
||||
let length = Keyboard.readInt("How many numbers? ");
|
||||
let a = Array.new(length); // constructs the array
|
||||
|
||||
let i = 0;
|
||||
while (i < length) {
|
||||
let a[i] = Keyboard.readInt("Enter a number: ");
|
||||
let sum = sum + a[i];
|
||||
let i = i + 1;
|
||||
}
|
||||
|
||||
do Output.printString("The average is ");
|
||||
do Output.printInt(sum / length);
|
||||
return;
|
||||
}
|
||||
}
|
||||
200
projects/09/BitmapEditor/BitmapEditor.html
Normal file
200
projects/09/BitmapEditor/BitmapEditor.html
Normal file
@@ -0,0 +1,200 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Sokoban Bitmap Editor</title>
|
||||
<script type="text/javascript">
|
||||
var grid = new Array(0);
|
||||
|
||||
function Init() {
|
||||
grid = InitGrid();
|
||||
DisplayGrid();
|
||||
}
|
||||
|
||||
function InitGrid() {
|
||||
var _grid = new Array(16);
|
||||
for (i=0; i<16; i++) {
|
||||
_grid[i] = new Array(16);
|
||||
for (j=0; j<16; j++) {
|
||||
_grid[i][j]=false;
|
||||
}
|
||||
}
|
||||
return _grid;
|
||||
}
|
||||
|
||||
function RotateBitmapRight() {
|
||||
var _grid = InitGrid();
|
||||
|
||||
for (i=0; i<16; i++) {
|
||||
for (j=0; j<16; j++) {
|
||||
_grid[j][15-i]=grid[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
grid = _grid;
|
||||
DisplayGrid();
|
||||
}
|
||||
|
||||
function MirrorBitmap() {
|
||||
var _grid = InitGrid();
|
||||
|
||||
for (i=0; i<16; i++) {
|
||||
for (j=0; j<16; j++) {
|
||||
_grid[i][15-j]=grid[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
grid = _grid;
|
||||
DisplayGrid();
|
||||
}
|
||||
|
||||
function DisplayGrid() {
|
||||
var str = "<table border=1 cellspacing=0>";
|
||||
var i,j, backgroundColor;
|
||||
for (i=-1; i<16; i++) {
|
||||
str=str+"<tr>";
|
||||
for (j=-1; j<16; j++) {
|
||||
if (i == -1 && j != -1) {
|
||||
str=str+"<td>" + (j+1) + "</td>";
|
||||
} else if (i != -1 && j == -1) {
|
||||
str=str+"<td>" + (i+1) + "</td>";
|
||||
} else if (i ==-1 && j == -1) {
|
||||
str=str+"<td/>";
|
||||
} else {
|
||||
|
||||
if (grid[i][j] == true)
|
||||
backgroundColor = "black";
|
||||
else
|
||||
backgroundColor = "white";
|
||||
|
||||
str=str+"<td onclick=\"OnCellClicked(this)\" id="; str=str+(i*16+j); str=str+" width=16 height=16 bgcolor=" + backgroundColor + "></td>";
|
||||
}
|
||||
}
|
||||
str=str+"</tr>";
|
||||
}
|
||||
str=str+"</table>"
|
||||
|
||||
gridElement = document.getElementById('grid');
|
||||
gridElement.innerHTML = str;
|
||||
GenerateBitMap() ;
|
||||
}
|
||||
|
||||
function OnCellClicked(cell) {
|
||||
var i = cell.id / 16 |0;
|
||||
var j = cell.id - i*16;
|
||||
grid[i][j] = !grid[i][j];
|
||||
if (grid[i][j])
|
||||
cell.style.backgroundColor = "black";
|
||||
else
|
||||
cell.style.backgroundColor = "white";
|
||||
GenerateBitMap();
|
||||
}
|
||||
|
||||
function GenerateBitMap() {
|
||||
var i, j;
|
||||
var value;
|
||||
|
||||
var functionTypeSelect = document.getElementById('functionType');
|
||||
methodType = functionTypeSelect.options[functionTypeSelect.selectedIndex].value;
|
||||
|
||||
generateCode = document.getElementById('generatedCode');
|
||||
generateCode.value = methodType + " void " +
|
||||
document.getElementById('functionName').value +
|
||||
"(int location) {\n\tlet memAddress = 16384+location;\n";
|
||||
|
||||
for (i=0; i<16; i++) {
|
||||
//get grid binary representation
|
||||
binary = "";
|
||||
for (j=0; j<16; j++) {
|
||||
if (grid[i][j])
|
||||
binary = "1" + binary;
|
||||
else
|
||||
binary = "0" + binary;
|
||||
}
|
||||
|
||||
isNegative = false;
|
||||
//if number is negative, get its one's complement
|
||||
if (binary[0] == "1") {
|
||||
isNegative = true;
|
||||
oneComplement = "";
|
||||
for (k=0; k<16; k++) {
|
||||
if (binary[k] == "1")
|
||||
oneComplement = oneComplement + "0";
|
||||
else
|
||||
oneComplement = oneComplement + "1";
|
||||
}
|
||||
binary = oneComplement;
|
||||
}
|
||||
|
||||
//calculate one's complement decimal value
|
||||
value = 0;
|
||||
for (k=0; k<16; k++) {
|
||||
value = value * 2;
|
||||
if (binary[k] == "1")
|
||||
value=value+1;
|
||||
}
|
||||
|
||||
//two's complement value if it is a negative value
|
||||
if (isNegative == true)
|
||||
value = -(value + 1)
|
||||
|
||||
generateCode.value = generateCode.value + GenerateCodeLine(i, value);
|
||||
}
|
||||
|
||||
generateCode.value = generateCode.value + "\treturn;\n}";
|
||||
}
|
||||
|
||||
function GenerateCodeLine(row, value) {
|
||||
str = "\tdo Memory.poke(memAddress+" + row*32 + ", " + value + ");\n";
|
||||
return str;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="Init();">
|
||||
<h4><i>IDC Herzliya / Efi Arazi School of Computer Science / Digital Systems Construction, Spring 2011 / Project 09 / Golan Parashi</i></h4>
|
||||
<h1>Sokoban Bitmap Editor</h1>
|
||||
<p>This javascript applicaiton is used to generate highly optimized jack code for drawing a 16x16 bitmap to the screen.</p>
|
||||
<p>Using the mouse, click the desired cell to mark/unmark it. You may use 90 degrees rotation and vertical mirroring by<br>
|
||||
clicking the appropriate buttons.</p>
|
||||
<p>When you are finished drawing, you may select function type and enter function's name.</p>
|
||||
<p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left">Bitmap</th>
|
||||
<th align="left"></th>
|
||||
<th align="left">Generated Jack Code</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td><div id="grid"/></td>
|
||||
<td>
|
||||
<form action="javascript:GenerateBitMap();">
|
||||
<table>
|
||||
<tr><td align="left">Function Type:</td></tr>
|
||||
<tr><td align="center">
|
||||
<select id="functionType" onChange="GenerateBitMap()">
|
||||
<option value="function" selected="selected">function</option>
|
||||
<option value="method">method</option>
|
||||
</select>
|
||||
</td></tr>
|
||||
<tr><td align="left">Function Name:</td></tr>
|
||||
<tr><td align="left"><input type="text" value="draw" id="functionName" onkeyup="GenerateBitMap()"/></td></tr>
|
||||
<tr><td></td></tr>
|
||||
<tr><td align="center"><input type="button" value="Generate Code >>" onclick="GenerateBitMap()"/></td></tr>
|
||||
</table>
|
||||
</form>
|
||||
</td>
|
||||
<td><textarea id="generatedCode" cols="50" rows="20" readonly="read-only"></textarea></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center"><input type="button" value="Rotate right" onclick="RotateBitmapRight()"/></td>
|
||||
<td align="center"><input type="button" value="Vertical Mirror" onclick="MirrorBitmap()"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
10
projects/09/BitmapEditor/BitmapEditor.iml
Normal file
10
projects/09/BitmapEditor/BitmapEditor.iml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
65
projects/09/Fraction/Fraction.jack
Normal file
65
projects/09/Fraction/Fraction.jack
Normal file
@@ -0,0 +1,65 @@
|
||||
// This file is part of www.nand2tetris.org
|
||||
// and the book "The Elements of Computing Systems"
|
||||
// by Nisan and Schocken, MIT Press.
|
||||
// File name: projects/09/Fraction/Fraction.jack
|
||||
|
||||
/** Represents the Fraction type and related operations. */
|
||||
class Fraction {
|
||||
field int numerator, denominator; // field = property = member variable.
|
||||
|
||||
/** Constructs a (reduced) fraction from the given numerator and denominator. */
|
||||
constructor Fraction new(int x, int y) {
|
||||
let numerator = x;
|
||||
let denominator = y;
|
||||
do reduce(); // reduces the fraction
|
||||
return this; // a constructor is expected to return a reference to the new object
|
||||
}
|
||||
|
||||
// Reduces this fraction.
|
||||
method void reduce() {
|
||||
var int g;
|
||||
let g = Fraction.gcd(numerator, denominator);
|
||||
if (g > 1) {
|
||||
let numerator = numerator / g;
|
||||
let denominator = denominator / g;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/** Accessors. */
|
||||
method int getNumerator() { return numerator; }
|
||||
method int getDenominator() { return denominator; }
|
||||
|
||||
/** Returns the sum of this fraction and the other one. */
|
||||
method Fraction plus(Fraction other) {
|
||||
var int sum;
|
||||
let sum = (numerator * other.getDenominator()) + (other.getNumerator() * denominator);
|
||||
return Fraction.new(sum, denominator * other.getDenominator());
|
||||
}
|
||||
|
||||
// More fraction-related methods (minus, times, div, etc.) can be added here.
|
||||
|
||||
/** Disposes this fraction. */
|
||||
method void dispose() {
|
||||
do Memory.deAlloc(this); // uses an OS routine to recycle the memory held by the object
|
||||
return;
|
||||
}
|
||||
|
||||
/** Prints this fraction in the format x/y. */
|
||||
method void print() {
|
||||
do Output.printInt(numerator);
|
||||
do Output.printString("/");
|
||||
do Output.printInt(denominator);
|
||||
return;
|
||||
}
|
||||
|
||||
// Computes the greatest common divisor of the given integers.
|
||||
function int gcd(int a, int b) {
|
||||
var int r;
|
||||
while (~(b = 0)) { // applies Euclid's algorithm
|
||||
let r = a - (b * (a / b)); // r = remainder of the integer division a/b
|
||||
let a = b; let b = r;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
16
projects/09/Fraction/Main.jack
Normal file
16
projects/09/Fraction/Main.jack
Normal file
@@ -0,0 +1,16 @@
|
||||
// This file is part of www.nand2tetris.org
|
||||
// and the book "The Elements of Computing Systems"
|
||||
// by Nisan and Schocken, MIT Press.
|
||||
// File name: projects/09/Fraction/Main.jack
|
||||
|
||||
// Computes the sum of 2/3 and 1/5.
|
||||
class Main {
|
||||
function void main() {
|
||||
var Fraction a, b, c;
|
||||
let a = Fraction.new(2,3);
|
||||
let b = Fraction.new(1,5);
|
||||
let c = a.plus(b); // Computes c = a + b
|
||||
do c.print(); // Prints "13/15"
|
||||
return;
|
||||
}
|
||||
}
|
||||
14
projects/09/HelloWorld/Main.jack
Normal file
14
projects/09/HelloWorld/Main.jack
Normal file
@@ -0,0 +1,14 @@
|
||||
// This file is part of www.nand2tetris.org
|
||||
// and the book "The Elements of Computing Systems"
|
||||
// by Nisan and Schocken, MIT Press.
|
||||
// File name: projects/09/HelloWorld/Main.jack
|
||||
|
||||
/** Hello World program. */
|
||||
class Main {
|
||||
function void main() {
|
||||
/* Prints some text using the standard library. */
|
||||
do Output.printString("Hello world!");
|
||||
do Output.println(); // New line
|
||||
return;
|
||||
}
|
||||
}
|
||||
BIN
projects/09/Jack OS API.pdf
Normal file
BIN
projects/09/Jack OS API.pdf
Normal file
Binary file not shown.
46
projects/09/List/List.jack
Normal file
46
projects/09/List/List.jack
Normal file
@@ -0,0 +1,46 @@
|
||||
// This file is part of www.nand2tetris.org
|
||||
// and the book "The Elements of Computing Systems"
|
||||
// by Nisan and Schocken, MIT Press.
|
||||
// File name: projects/09/List/List.jack
|
||||
|
||||
/** Represents a linked list of integers. */
|
||||
class List {
|
||||
field int data; // a list consists of a data field,
|
||||
field List next; // followed by a list
|
||||
|
||||
/* Creates a List. */
|
||||
constructor List new(int car, List cdr) {
|
||||
let data = car; // the identifiers car and cdr are used in
|
||||
let next = cdr; // memory of the Lisp programming language
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Accessors. */
|
||||
method int getData() { return data; }
|
||||
method int getNext() { return next; }
|
||||
|
||||
/** Prints this list. */
|
||||
method void print() {
|
||||
var List current; // initializes current to the first item
|
||||
let current = this; // of this list
|
||||
while (~(current = null)) {
|
||||
do Output.printInt(current.getData());
|
||||
do Output.printChar(32); // prints a space
|
||||
let current = current.getNext();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/** Disposes this List by recursively disposing its tail. */
|
||||
method void dispose() {
|
||||
if (~(next = null)) {
|
||||
do next.dispose();
|
||||
}
|
||||
// Uses an OS routine to recycle this object.
|
||||
do Memory.deAlloc(this);
|
||||
return;
|
||||
}
|
||||
|
||||
// More list processing methods can come here.
|
||||
|
||||
}
|
||||
17
projects/09/List/Main.jack
Normal file
17
projects/09/List/Main.jack
Normal file
@@ -0,0 +1,17 @@
|
||||
// This file is part of www.nand2tetris.org
|
||||
// and the book "The Elements of Computing Systems"
|
||||
// by Nisan and Schocken, MIT Press.
|
||||
// File name: projects/09/List/Main.jack
|
||||
|
||||
/** Demonstrates the use of the List abstraction. */
|
||||
class Main {
|
||||
function void main() {
|
||||
// Creates and uses the list (2,3,5).
|
||||
var List v;
|
||||
let v = List.new(5,null);
|
||||
let v = List.new(2,List.new(3,v));
|
||||
do v.print(); // prints 2 3 5
|
||||
do v.dispose(); // disposes the list
|
||||
return;
|
||||
}
|
||||
}
|
||||
15
projects/09/Square/Main.jack
Normal file
15
projects/09/Square/Main.jack
Normal file
@@ -0,0 +1,15 @@
|
||||
// This file is part of www.nand2tetris.org
|
||||
// and the book "The Elements of Computing Systems"
|
||||
// by Nisan and Schocken, MIT Press.
|
||||
// File name: projects/09/Square/Main.jack
|
||||
|
||||
/** Initializes a new Square Dance game and starts running it. */
|
||||
class Main {
|
||||
function void main() {
|
||||
var SquareGame game;
|
||||
let game = SquareGame.new();
|
||||
do game.run();
|
||||
do game.dispose();
|
||||
return;
|
||||
}
|
||||
}
|
||||
108
projects/09/Square/Square.jack
Normal file
108
projects/09/Square/Square.jack
Normal file
@@ -0,0 +1,108 @@
|
||||
// This file is part of www.nand2tetris.org
|
||||
// and the book "The Elements of Computing Systems"
|
||||
// by Nisan and Schocken, MIT Press.
|
||||
// File name: projects/09/Square/Square.jack
|
||||
|
||||
/** Implements a graphical square. */
|
||||
class Square {
|
||||
|
||||
field int x, y; // screen location of the square's top-left corner
|
||||
field int size; // length of this square, in pixels
|
||||
|
||||
/** Constructs a new square with a given location and size. */
|
||||
constructor Square new(int Ax, int Ay, int Asize) {
|
||||
let x = Ax;
|
||||
let y = Ay;
|
||||
let size = Asize;
|
||||
do draw();
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Disposes this square. */
|
||||
method void dispose() {
|
||||
do Memory.deAlloc(this);
|
||||
return;
|
||||
}
|
||||
|
||||
/** Draws the square on the screen. */
|
||||
method void draw() {
|
||||
do Screen.setColor(true);
|
||||
do Screen.drawRectangle(x, y, x + size, y + size);
|
||||
return;
|
||||
}
|
||||
|
||||
/** Erases the square from the screen. */
|
||||
method void erase() {
|
||||
do Screen.setColor(false);
|
||||
do Screen.drawRectangle(x, y, x + size, y + size);
|
||||
return;
|
||||
}
|
||||
|
||||
/** Increments the square size by 2 pixels. */
|
||||
method void incSize() {
|
||||
if (((y + size) < 254) & ((x + size) < 510)) {
|
||||
do erase();
|
||||
let size = size + 2;
|
||||
do draw();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/** Decrements the square size by 2 pixels. */
|
||||
method void decSize() {
|
||||
if (size > 2) {
|
||||
do erase();
|
||||
let size = size - 2;
|
||||
do draw();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/** Moves the square up by 2 pixels. */
|
||||
method void moveUp() {
|
||||
if (y > 1) {
|
||||
do Screen.setColor(false);
|
||||
do Screen.drawRectangle(x, (y + size) - 1, x + size, y + size);
|
||||
let y = y - 2;
|
||||
do Screen.setColor(true);
|
||||
do Screen.drawRectangle(x, y, x + size, y + 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/** Moves the square down by 2 pixels. */
|
||||
method void moveDown() {
|
||||
if ((y + size) < 254) {
|
||||
do Screen.setColor(false);
|
||||
do Screen.drawRectangle(x, y, x + size, y + 1);
|
||||
let y = y + 2;
|
||||
do Screen.setColor(true);
|
||||
do Screen.drawRectangle(x, (y + size) - 1, x + size, y + size);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/** Moves the square left by 2 pixels. */
|
||||
method void moveLeft() {
|
||||
if (x > 1) {
|
||||
do Screen.setColor(false);
|
||||
do Screen.drawRectangle((x + size) - 1, y, x + size, y + size);
|
||||
let x = x - 2;
|
||||
do Screen.setColor(true);
|
||||
do Screen.drawRectangle(x, y, x + 1, y + size);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/** Moves the square right by 2 pixels. */
|
||||
method void moveRight() {
|
||||
if ((x + size) < 510) {
|
||||
do Screen.setColor(false);
|
||||
do Screen.drawRectangle(x, y, x + 1, y + size);
|
||||
let x = x + 2;
|
||||
do Screen.setColor(true);
|
||||
do Screen.drawRectangle((x + size) - 1, y, x + size, y + size);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
79
projects/09/Square/SquareGame.jack
Normal file
79
projects/09/Square/SquareGame.jack
Normal file
@@ -0,0 +1,79 @@
|
||||
// This file is part of www.nand2tetris.org
|
||||
// and the book "The Elements of Computing Systems"
|
||||
// by Nisan and Schocken, MIT Press.
|
||||
// File name: projects/09/Square/SquareGame.jack
|
||||
|
||||
/**
|
||||
* Implements the Square Dance game.
|
||||
* This simple game allows the user to move a black square around
|
||||
* the screen, and change the square's size during the movement.
|
||||
* When the game starts, a square of 30 by 30 pixels is shown at the
|
||||
* top-left corner of the screen. The user controls the square as follows.
|
||||
* The 4 arrow keys are used to move the square up, down, left, and right.
|
||||
* The 'z' and 'x' keys are used, respectively, to decrement and increment
|
||||
* the square's size. The 'q' key is used to quit the game.
|
||||
*/
|
||||
|
||||
class SquareGame {
|
||||
field Square square; // the square of this game
|
||||
field int direction; // the square's current direction:
|
||||
// 0=none, 1=up, 2=down, 3=left, 4=right
|
||||
|
||||
/** Constructs a new Square Game. */
|
||||
constructor SquareGame new() {
|
||||
// Creates a 30 by 30 pixels square and positions it at the top-left
|
||||
// of the screen.
|
||||
let square = Square.new(0, 0, 30);
|
||||
let direction = 0; // initial state is no movement
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Disposes this game. */
|
||||
method void dispose() {
|
||||
do square.dispose();
|
||||
do Memory.deAlloc(this);
|
||||
return;
|
||||
}
|
||||
|
||||
/** Moves the square in the current direction. */
|
||||
method void moveSquare() {
|
||||
if (direction = 1) { do square.moveUp(); }
|
||||
if (direction = 2) { do square.moveDown(); }
|
||||
if (direction = 3) { do square.moveLeft(); }
|
||||
if (direction = 4) { do square.moveRight(); }
|
||||
do Sys.wait(5); // delays the next movement
|
||||
return;
|
||||
}
|
||||
|
||||
/** Runs the game: handles the user's inputs and moves the square accordingly */
|
||||
method void run() {
|
||||
var char key; // the key currently pressed by the user
|
||||
var boolean exit;
|
||||
let exit = false;
|
||||
|
||||
while (~exit) {
|
||||
// waits for a key to be pressed
|
||||
while (key = 0) {
|
||||
let key = Keyboard.keyPressed();
|
||||
do moveSquare();
|
||||
}
|
||||
if (key = 81) { let exit = true; } // q key
|
||||
if (key = 90) { do square.decSize(); } // z key
|
||||
if (key = 88) { do square.incSize(); } // x key
|
||||
if (key = 131) { let direction = 1; } // up arrow
|
||||
if (key = 133) { let direction = 2; } // down arrow
|
||||
if (key = 130) { let direction = 3; } // left arrow
|
||||
if (key = 132) { let direction = 4; } // right arrow
|
||||
|
||||
// waits for the key to be released
|
||||
while (~(key = 0)) {
|
||||
let key = Keyboard.keyPressed();
|
||||
do moveSquare();
|
||||
}
|
||||
} // while
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user