commit
f6587585ba
|
@ -803,7 +803,7 @@ DELETE /idX/delete HTTP/1.1 -> Returns 404
|
|||
2. HTTP/1.1 支持管线化处理
|
||||
3. HTTP/1.1 支持虚拟主机
|
||||
4. HTTP/1.1 新增状态码 100
|
||||
5. HTTP/1.1 只是分块传输编码
|
||||
5. HTTP/1.1 支持分块传输编码
|
||||
6. HTTP/1.1 新增缓存处理指令 max-age
|
||||
|
||||
具体内容见上文
|
||||
|
@ -828,7 +828,7 @@ HTTP/1.1 的解析是基于文本的,而 HTTP/2.0 采用二进制格式。
|
|||
|
||||
# 参考资料
|
||||
|
||||
- 上野宣. 图解 HTTP[M]. Ren min you dian chu ban she, 2014.
|
||||
- 上野宣. 图解 HTTP[M]. 人民邮电出版社, 2014.
|
||||
- [MDN : HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP)
|
||||
- [Are http:// and www really necessary?](https://www.webdancers.com/are-http-and-www-necesary/)
|
||||
- [HTTP (HyperText Transfer Protocol)](https://www.ntu.edu.sg/home/ehchua/programming/webprogramming/HTTP_Basics.html)
|
||||
|
|
|
@ -44,11 +44,11 @@ java.awt.Desktop#getDesktop()
|
|||
|
||||
## 2. 简单工厂模式
|
||||
|
||||
在不对用户暴露对象内部逻辑的前提下创建对象;使用通用的接口来创建对象;
|
||||
在不对用户暴露对象内部逻辑的前提下创建对象。
|
||||
|
||||
## 3. 工厂方法模式
|
||||
|
||||
定义创建对象的接口,但是让子类来决定应该使用哪个类来创建;使用通用的接口来创建对象;
|
||||
定义创建对象的接口,但是让子类来决定应该使用哪个类来创建。
|
||||
|
||||
```java
|
||||
java.lang.Proxy#newProxyInstance()
|
||||
|
@ -120,7 +120,7 @@ javax.swing.Action
|
|||
## 3. 解释器模式
|
||||
|
||||
为语言创建解释器,通常由语言的语法和语法分析来定义。
|
||||
|
||||
|
||||
```java
|
||||
java.util.Pattern
|
||||
java.text.Normalizer
|
||||
|
@ -229,7 +229,7 @@ JDBC
|
|||
|
||||
## 3. 组合模式
|
||||
|
||||
将对象组合成树形结构来表示整理-部分层次关系,允许用户以相同的方式处理单独对象和组合对象。
|
||||
将对象组合成树形结构来表示整体-部分层次关系,允许用户以相同的方式处理单独对象和组合对象。
|
||||
|
||||
```java
|
||||
javax.swing.JComponent#add(Component)
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
* [访问权限](#访问权限)
|
||||
* [抽象类与接口](#抽象类与接口)
|
||||
* [super](#super)
|
||||
* [重载与重写](#重载与重写)
|
||||
* [覆盖与重载](#覆盖与重载)
|
||||
* [五、String](#五string)
|
||||
* [String, StringBuffer and StringBuilder](#string,-stringbuffer-and-stringbuilder)
|
||||
* [String 不可变的原因](#string-不可变的原因)
|
||||
|
@ -55,7 +55,7 @@ y.a = 1;
|
|||
|
||||
声明方法不能被子类覆盖。
|
||||
|
||||
private 方法隐式地被指定为 final,如果在子类中定义的方法和基类中的一个 private 方法签名相同,此时子类的方法不是覆盖基类方法,而是重载了。
|
||||
private 方法隐式地被指定为 final,如果在子类中定义的方法和基类中的一个 private 方法签名相同,此时子类的方法不是覆盖基类方法,而是在子类中定义了一个新的方法。
|
||||
|
||||
**3. 类**
|
||||
|
||||
|
@ -255,9 +255,9 @@ public class EqualExample {
|
|||
|
||||
## hashCode()
|
||||
|
||||
hasCode() 返回散列值,而 equals() 是用来判断两个实例是否相等。相等的两个实例散列值一定要相同,但是散列值相同的两个实例不一定相等。
|
||||
hasCode() 返回散列值,而 equals() 是用来判断两个实例是否等价。等价的两个实例散列值一定要相同,但是散列值相同的两个实例不一定等价。
|
||||
|
||||
在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证相等的两个实例散列值也相等。
|
||||
在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证相等的两个实例散列值也等价。
|
||||
|
||||
下面的代码中,新建了两个等价的实例,并将它们添加到 HashSet 中。我们希望将这两个实例当成一样的,只在集合中添加一个实例,但是因为 EqualExample 没有实现 hasCode() 方法,因此这两个实例的散列值是不同的,最终导致集合添加了两个等价的实例。
|
||||
|
||||
|
@ -313,7 +313,7 @@ ToStringExample@4554617c
|
|||
|
||||
**1. cloneable**
|
||||
|
||||
clone() 是 Object 的受保护方法,这意味着,如果一个类不显式去重载 clone() 就没有这个方法。
|
||||
clone() 是 Object 的受保护方法,这意味着,如果一个类不显式去覆盖 clone() 就没有这个方法。
|
||||
|
||||
```java
|
||||
public class CloneExample {
|
||||
|
@ -327,7 +327,7 @@ CloneExample e1 = new CloneExample();
|
|||
CloneExample e2 = e1.clone(); // 'clone()' has protected access in 'java.lang.Object'
|
||||
```
|
||||
|
||||
接下来重载 Object 的 clone() 得到以下实现:
|
||||
接下来覆盖 Object 的 clone() 得到以下实现:
|
||||
|
||||
```java
|
||||
public class CloneExample {
|
||||
|
@ -595,7 +595,7 @@ ac2.func1();
|
|||
|
||||
从 Java 8 开始,接口也可以拥有默认的方法实现,这是因为不支持默认方法的接口的维护成本太高了。在 Java 8 之前,如果一个接口想要添加新的方法,那么要修改所有实现了该接口的类。
|
||||
|
||||
接口也可以包含域,并且这些域隐式都是 static 和 final 的。
|
||||
接口也可以包含字段,并且这些字段隐式都是 static 和 final 的。
|
||||
|
||||
接口中的方法默认都是 public 的,并且不允许定义为 private 或者 protected。
|
||||
|
||||
|
@ -636,7 +636,7 @@ System.out.println(InterfaceExample.x);
|
|||
|
||||
- 从设计层面上看,抽象类提供了一种 IS-A 关系,那么就必须满足里式替换原则,即子类对象必须能够替换掉所有父类对象。而接口更像是一种 LIKE-A 关系,它只是提供一种方法实现契约,并不要求子类和父类具有 IS-A 关系;
|
||||
- 从使用上来看,一个类可以实现多个接口,但是不能继承多个抽象类。
|
||||
- 接口的域只能是 static 和 final 类型的,而抽象类的域可以有多种访问权限。
|
||||
- 接口的字段只能是 static 和 final 类型的,而抽象类的域可以有多种访问权限。
|
||||
- 接口的方法只能是 public 的,而抽象类的方法可以由多种访问权限。
|
||||
|
||||
**4. 使用选择**
|
||||
|
@ -706,11 +706,11 @@ SuperExtendExample.func()
|
|||
|
||||
> [Using the Keyword super](https://docs.oracle.com/javase/tutorial/java/IandI/super.html)
|
||||
|
||||
## 重载与重写
|
||||
## 覆盖与重载
|
||||
|
||||
- 重写存在于继承体系中,指子类实现了一个与父类在方法声明上完全相同的一个方法;
|
||||
- 覆盖(Override)存在于继承体系中,指子类实现了一个与父类在方法声明上完全相同的一个方法;
|
||||
|
||||
- 重载即存在于继承体系中,也存在于同一个类中,指一个方法与已经存在的方法或者父类的方法名称上相同,但是参数类型、个数、顺序至少有一个不同。应该注意的是,返回值不同,其它都相同不算是重载。
|
||||
- 重载(Overload)存在于同一个类中,指一个方法与已经存在的方法名称上相同,但是参数类型、个数、顺序至少有一个不同。应该注意的是,返回值不同,其它都相同不算是重载。
|
||||
|
||||
# 五、String
|
||||
|
||||
|
@ -739,7 +739,7 @@ SuperExtendExample.func()
|
|||
|
||||
如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。
|
||||
|
||||
<div align="center"> <img src="../pics//f76067a5-7d5f-4135-9549-8199c77d8f1c.jpg"/> </div><br>
|
||||
<div align="center"> <img src="../pics//f76067a5-7d5f-4135-9549-8199c77d8f1c.jpg" width=""/> </div><br>
|
||||
|
||||
**3. 安全性**
|
||||
|
||||
|
@ -773,7 +773,7 @@ String s5 = "bbb";
|
|||
System.out.println(s4 == s5); // true
|
||||
```
|
||||
|
||||
Java 虚拟机将堆划分成新生代、老年代和永久代(PermGen Space)。在 Java 6 之前,字符串常量池被放在永久代中,而在 Java 7 时,它被放在堆的其它位置。这是因为永久代的空间有限,如果大量使用字符串的场景下会导致 OutOfMemoryError 错误。
|
||||
Java 虚拟机将堆划分成新生代、老年代和永久代(PermGen Space)。在 Java 7 之前,字符串常量池被放在永久代中,而在 Java 7,它被放在堆的其它位置。这是因为永久代的空间有限,如果大量使用字符串的场景下会导致 OutOfMemoryError 错误。
|
||||
|
||||
> [What is String interning?](https://stackoverflow.com/questions/10578984/what-is-string-interning) </br> [深入解析 String#intern](https://tech.meituan.com/in_depth_understanding_string_intern.html)
|
||||
|
||||
|
@ -946,7 +946,7 @@ Throwable 可以用来表示任何可以作为异常抛出的类,分为两种
|
|||
1. **受检异常** :需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复;
|
||||
2. **非受检异常** :是程序运行时错误,例如除 0 会引发 Arithmetic Exception,此时程序奔溃并且无法恢复。
|
||||
|
||||
<div align="center"> <img src="../pics//PPjwP.png"/> </div><br>
|
||||
<div align="center"> <img src="../pics//PPjwP.png" width="600"/> </div><br>
|
||||
|
||||
> [Java 入门之异常处理](https://www.tianmaying.com/tutorial/Java-Exception) </br> [Java 异常的面试问题及答案 -Part 1](http://www.importnew.com/7383.html)
|
||||
|
||||
|
|
|
@ -567,7 +567,7 @@ static final int DEFAULT_CONCURRENCY_LEVEL = 16;
|
|||
|
||||
<div align="center"> <img src="../pics//image005.jpg"/> </div><br>
|
||||
|
||||
### 2. HashEntery 的不可变性
|
||||
### 2. HashEntry 的不可变性
|
||||
|
||||
HashEntry 中的 key,hash,next 都声明为 final 型。这意味着,不能把节点添加到链接的中间和尾部,也不能在链接的中间和尾部删除节点。这个特性可以保证:在访问某个节点时,这个节点之后的链接不会被改变。这个特性可以大大降低处理链表时的复杂性。
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@
|
|||
|
||||
## 无限期等待(Waiting)
|
||||
|
||||
等待其它线程显示地唤醒,否则不会被分配 CPU 时间片。
|
||||
等待其它线程显式地唤醒,否则不会被分配 CPU 时间片。
|
||||
|
||||
| 进入方法 | 退出方法 |
|
||||
| --- | --- |
|
||||
|
@ -794,9 +794,10 @@ public class SemaphoreExample {
|
|||
try {
|
||||
semaphore.acquire();
|
||||
System.out.print(semaphore.availablePermits() + " ");
|
||||
semaphore.release();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
semaphore.release();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1413,7 +1414,7 @@ ABA :如果一个变量 V 初次读取的时候是 A 值,它的值被改成
|
|||
|
||||
**(二)栈封闭**
|
||||
|
||||
多个线程方法同一个方法的局部变量时,不会出现线程安全问题,因为局部变量存储在栈中,属于线程私有的。
|
||||
多个线程访问同一个方法的局部变量时,不会出现线程安全问题,因为局部变量存储在栈中,属于线程私有的。
|
||||
|
||||
```java
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
|
|
@ -40,7 +40,7 @@ InnoDB 是 MySQL 默认的事务型存储引擎,只有在需要 InnoDB 不支
|
|||
|
||||
## MyISAM
|
||||
|
||||
MyISAM 提供了大量的特性,包括全文索引、压缩、空间函数(GIS)等。但 MyISAM 不支持事务和行级锁,而且崩溃后无法安全恢复。
|
||||
MyISAM 提供了大量的特性,包括全文索引、压缩、空间函数(GIS)等。但 MyISAM 不支持事务和行级锁,而且崩溃后无法安全恢复。应该注意的是,MySQL5.6.4 添加了对 InnoDB 引擎的全文索引支持。
|
||||
|
||||
只能对整张表加锁,而不是针对行。
|
||||
|
||||
|
@ -62,7 +62,7 @@ MyISAM 设计简单,数据以紧密格式存储,所以在某些场景下性
|
|||
2. 备份:InnoDB 支持在线热备份。
|
||||
3. 崩溃恢复:MyISAM 崩溃后发生损坏的概率比 InnoDB 高很多,而且恢复的速度也更慢。
|
||||
4. 并发:MyISAM 只支持表级锁,而 InnoDB 还支持行级锁。
|
||||
5. 其它特性:MyISAM 支持全文索引,地理空间索引。
|
||||
5. 其它特性:MyISAM 支持,地理空间索引。
|
||||
|
||||
# 二、数据类型
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@
|
|||
|
||||
**一致性哈希**
|
||||
|
||||
Distributed Hash Table(DHT):对于哈希空间 0\~2<sup>n</sup>,将该哈希空间看成一个哈希环,将每个节点都配置到哈希环上。每个数据对象通过哈希取模得到哈希值之后,存放到哈希环中顺时针方向第一个大于等于该哈希值的节点上。
|
||||
Distributed Hash Table(DHT):对于哈希空间 [0, 2<sup>n</sup>-1],将该哈希空间看成一个哈希环,将每个节点都配置到哈希环上。每个数据对象通过哈希取模得到哈希值之后,存放到哈希环中顺时针方向第一个大于等于该哈希值的节点上。
|
||||
|
||||
<div align="center"> <img src="../pics//d2d34239-e7c1-482b-b33e-3170c5943556.jpg"/> </div><br>
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@
|
|||
|
||||
# 2. 实现 Singleton
|
||||
|
||||
> [单例模式](https://github.com/CyC2018/Interview- Notebook/blob/master/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md)
|
||||
> [单例模式](https://github.com/CyC2018/Interview-Notebook/blob/master/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md)
|
||||
|
||||
# 3. 数组中重复的数字
|
||||
|
||||
|
@ -1142,7 +1142,7 @@ public ListNode Merge(ListNode list1, ListNode list2) {
|
|||
ListNode head = new ListNode(-1);
|
||||
ListNode cur = head;
|
||||
while (list1 != null && list2 != null) {
|
||||
if (list1.val < list2.val) {
|
||||
if (list1.val <= list2.val) {
|
||||
cur.next = list1;
|
||||
list1 = list1.next;
|
||||
} else {
|
||||
|
@ -1409,7 +1409,7 @@ public ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
|
|||
|
||||
## 题目描述
|
||||
|
||||
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。
|
||||
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。假设输入的数组的任意两个数字都互不相同。
|
||||
|
||||
例如,下图是后序遍历序列 3,1,2 所对应的二叉搜索树。
|
||||
|
||||
|
@ -1673,36 +1673,30 @@ public ArrayList<Integer> GetLeastNumbers_Solution(int[] nums, int k) {
|
|||
int kthSmallest = findKthSmallest(nums, k - 1);
|
||||
ArrayList<Integer> ret = new ArrayList<>();
|
||||
for (int val : nums) {
|
||||
if (val <= kthSmallest && ret.size() < k) ret.add(val);
|
||||
if (val <= kthSmallest && ret.size() < k) {
|
||||
ret.add(val);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public int findKthSmallest(int[] nums, int k) {
|
||||
int l = 0;
|
||||
int h = nums.length - 1;
|
||||
int l = 0, h = nums.length - 1;
|
||||
while (l < h) {
|
||||
int j = partition(nums, l, h);
|
||||
if (j < k) {
|
||||
l = j + 1;
|
||||
} else if (j > k) {
|
||||
h = j - 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
if (j == k) break;
|
||||
if (j > k) h = j - 1;
|
||||
else l = j + 1;
|
||||
}
|
||||
return nums[k];
|
||||
}
|
||||
|
||||
private int partition(int[] nums, int l, int h) {
|
||||
int i = l;
|
||||
int j = h + 1;
|
||||
int i = l, j = h + 1;
|
||||
while (true) {
|
||||
while (i < h && nums[++i] < nums[l]) ;
|
||||
while (j > l && nums[l] < nums[--j]) ;
|
||||
if (i >= j) {
|
||||
break;
|
||||
}
|
||||
if (i >= j) break;
|
||||
swap(nums, i, j);
|
||||
}
|
||||
swap(nums, l, j);
|
||||
|
@ -1710,9 +1704,7 @@ private int partition(int[] nums, int l, int h) {
|
|||
}
|
||||
|
||||
private void swap(int[] nums, int i, int j) {
|
||||
int t = nums[i];
|
||||
nums[i] = nums[j];
|
||||
nums[j] = t;
|
||||
int t = nums[i]; nums[i] = nums[j]; nums[j] = t;
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -1882,7 +1874,7 @@ private int getAmountOfDigit(int digit) {
|
|||
}
|
||||
|
||||
/**
|
||||
* 在 digit 位数组成的字符串中,第 index 为的数
|
||||
* 在 digit 位数组成的字符串中,第 index 个数
|
||||
*/
|
||||
private int digitAtIndex(int index, int digit) {
|
||||
int number = beginNumber(digit) + index / digit;
|
||||
|
@ -1994,6 +1986,7 @@ public int longestSubStringWithoutDuplication(String str) {
|
|||
int curLen = 0;
|
||||
int maxLen = 0;
|
||||
int[] indexs = new int[26];
|
||||
Arrays.fill(indexs, -1);
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
int c = str.charAt(i) - 'a';
|
||||
int preIndex = indexs[c];
|
||||
|
@ -2018,21 +2011,19 @@ public int longestSubStringWithoutDuplication(String str) {
|
|||
## 解题思路
|
||||
|
||||
```java
|
||||
public int GetUglyNumber_Solution(int N) {
|
||||
if (N <= 6) return N;
|
||||
public int GetUglyNumber_Solution(int index) {
|
||||
if (index <= 6) return index;
|
||||
int i2 = 0, i3 = 0, i5 = 0;
|
||||
int cnt = 1;
|
||||
int[] dp = new int[N];
|
||||
int[] dp = new int[index];
|
||||
dp[0] = 1;
|
||||
while (cnt < N) {
|
||||
for (int i = 1; i < index; i++) {
|
||||
int n2 = dp[i2] * 2, n3 = dp[i3] * 3, n5 = dp[i5] * 5;
|
||||
int min = Math.min(n2, Math.min(n3, n5));
|
||||
dp[cnt++] = min;
|
||||
if (min == n2) i2++;
|
||||
if (min == n3) i3++;
|
||||
if (min == n5) i5++;
|
||||
dp[i] = Math.min(n2, Math.min(n3, n5));
|
||||
if (dp[i] == n2) i2++;
|
||||
if (dp[i] == n3) i3++;
|
||||
if (dp[i] == n5) i5++;
|
||||
}
|
||||
return dp[N - 1];
|
||||
return dp[index - 1];
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -307,7 +307,7 @@ InnoDB 的 MVCC 使用到的快照存储在 Undo 日志中,该日志通过回
|
|||
|
||||
### 4. UPDATE
|
||||
|
||||
将系统版本号作为更新后的数据行快照的创建版本号,同时将系统版本号作为作为更新前的数据行快照的删除版本号。可以理解为先执行 DELETE 后执行 INSERT。
|
||||
将系统版本号作为更新后的数据行快照的创建版本号,同时将系统版本号作为更新前的数据行快照的删除版本号。可以理解为先执行 DELETE 后执行 INSERT。
|
||||
|
||||
## 快照读与当前读
|
||||
|
||||
|
@ -401,7 +401,7 @@ SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;
|
|||
|
||||
1. 冗余数据,例如学生-2 出现了两次。
|
||||
2. 修改异常,修改了一个记录中的信息,但是另一个记录中相同的信息却没有被修改。
|
||||
3. 删除异常,删除一个信息,那么也会丢失其它信息。例如如果删除了课程-1,需要删除第二行和第三行,那么学生-1 的信息就会丢失。
|
||||
3. 删除异常,删除一个信息,那么也会丢失其它信息。例如如果删除了课程-1,需要删除第一行和第三行,那么学生-1 的信息就会丢失。
|
||||
4. 插入异常,例如想要插入一个学生的信息,如果这个学生还没选课,那么就无法插入。
|
||||
|
||||
## 范式
|
||||
|
|
|
@ -1439,7 +1439,7 @@ public class Transaction{
|
|||
|
||||
### 3. 基于线性探测法的散列表
|
||||
|
||||
线性探测法使用空位来解决冲突,当冲突发生时,向前探测一个空位来存储冲突的键。使用线程探测法,数组的大小 M 应当大于键的个数 N(M>N)。
|
||||
线性探测法使用空位来解决冲突,当冲突发生时,向前探测一个空位来存储冲突的键。使用线性探测法,数组的大小 M 应当大于键的个数 N(M>N)。
|
||||
|
||||
<div align="center"> <img src="../pics//dbb8516d-37ba-4e2c-b26b-eefd7de21b45.png" width="400"/> </div><br>
|
||||
|
||||
|
|
|
@ -276,13 +276,12 @@ public class ConcreteFactory2 extends Factory {
|
|||
|
||||
抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来。而工厂模式只是用于创建一个对象,这和抽象工厂模式有很大不同。
|
||||
|
||||
抽象工厂模式用到了工厂模式来创建单一对象,在类图左部,AbstractFactory 中的 createProductA 和 createProductB 方法都是让子类来实现,这两个方法单独来看就是在创建一个对象,这符合工厂模式的定义。
|
||||
抽象工厂模式用到了工厂模式来创建单一对象,AbstractFactory 中的 createProductA 和 createProductB 方法都是让子类来实现,这两个方法单独来看就是在创建一个对象,这符合工厂模式的定义。
|
||||
|
||||
至于创建对象的家族这一概念是在 Client 体现,Client 要通过 AbstractFactory 同时调用两个方法来创建出两个对象,在这里这两个对象就有很大的相关性,Client 需要同时创建出这两个对象。
|
||||
|
||||
从高层次来看,抽象工厂使用了组合,即 Cilent 组合了 AbstractFactory,而工厂模式使用了继承。
|
||||
|
||||
|
||||
## 代码实现
|
||||
|
||||
```java
|
||||
|
|
Loading…
Reference in New Issue
Block a user