-
header.jsp
-
header.jsp에 jstl/core 경로를 taglib으로 잡아준다. (prefix이름을 c로 지정. jstl쓰기 위함)
-
userid 세션에 따라 헤더에 나타나는 메뉴를 다르게 잡아준다.
-
userid 세션이 비어있다면 로그인, 회원가입, 게시판 메뉴가 뜨도록한다.
-
그게 아니라면(로그인 되어있다면) 로그아웃, 정보변경, 게시판 메뉴가 뜨도록한다.
-
회원탈퇴 기능도 추가한다. 액션은 MemberDelete.java에서 처리한다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bootstrap Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
<script src="/project01/js/member.js"></script>
</head>
<body>
<nav class="navbar navbar-expand-sm bg-dark navbar-dark">
<!-- Brand/logo -->
<a class="navbar-brand" href="#">
<h3>LOGO</h3>
</a>
<!-- Links -->
<ul class="navbar-nav">
<c:choose>
<c:when test="${empty sessionScope.userid}">
<li class="nav-item">
<a class="nav-link" href="/project01/member/login.me">로그인</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/project01/member/insert.me">회원가입</a>
</li>
</c:when>
<c:otherwise>
<li class="nav-item">
<a class="nav-link" href="/project01/member/logout.me">로그아웃</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/project01/member/view.me">정보변경</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/project01/member/delete.me">회원탈퇴</a>
</li>
</c:otherwise>
</c:choose>
<li class="nav-item">
<a class="nav-link" href="/project01/board/board.me">게시판</a>
</li>
</ul>
<c:if test="${not empty sessionScope.userid}">
<span class="navbar-text">
${sessionScope.userid} 님 반갑습니다.
</span>
</c:if>
</nav>
-
MemberDelete.java: 탈퇴하기 서블릿
package com.member.action;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.member.model.MemberDTO;
import com.member.model.SMemberDAOImpl;
/**
* Servlet implementation class MemberDelete
*/
@WebServlet("/member/delete.me")
public class MemberDelete extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public MemberDelete() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session=request.getSession();
String userid=(String)session.getAttribute("userid");
SMemberDAOImpl dao=SMemberDAOImpl.getInstance();
dao.memberDel(userid);
session.invalidate();
response.sendRedirect("login.me");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
-
list.jsp: 관리자로 로그인 했을때 뜨는 회원리스트. list.jsp가 header.jsp를 포함하고 있으므로 jstl을 사용할 수 있다. 따라서 <c: forEach> 구문으로 회원 리스트를 불러올 수 있다.
-
회원 리스트는 list액션을 처리하는 MemberList에서 memberList()메소드를 이용하여 ArrayList형식으로 저장되어 있다. 그 ArrayList를 members이름으로 불러온다.
-
<c: forEach items="${members}" var="mem">, ${mem.name}
-
회원리스트에 삭제할 수 있는 기능을 넣는다. member.js에서 del() 함수로 삭제한다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="../include/header.jsp" %>
<div class="container">
<br/>
<h3>회원리스트</h3><br/><br/>
<table class="table table-hover">
<thead>
<tr>
<th>이름</th>
<th>아이디</th>
<th>전화번호</th>
<th>이메일</th>
<th>구분</th>
<th>삭제</th>
</tr>
</thead>
<tbody>
<c:forEach items="${members}" var="mem">
<c:if test="${mem.admin==0 }">
<c:set var="mode" value="일반회원"/>
</c:if>
<c:if test="${mem.admin==1 }">
<c:set var="mode" value="관리자"/>
</c:if>
<tr>
<td>${mem.name}</td>
<td>${mem.userid}</td>
<td>${mem.phone}</td>
<td>${mem.email}</td>
<c:if test="${mem.admin==0}">
<td>일반회원</td>
<td onclick="del('${mem.userid}')">삭제</td>
</c:if>
<c:if test="${mem.admin==1}">
<td>관리자</td>
<td>Admin</td>
</c:if>
</tr>
</c:forEach>
</tbody>
</table>
</div>
<script>
</script>
<%@ include file="../include/footer.jsp" %>
-
UserDelete.java: 회원 삭제 서블릿. 회원 삭제를 하면 자동적으로 회원수도 줄어들도록.
package com.member.action;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import com.member.model.MemberDTO;
import com.member.model.SMemberDAOImpl;
/**
* Servlet implementation class UserDelete
*/
@WebServlet("/member/userDelete.me")
public class UserDelete extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public UserDelete() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
String userid=request.getParameter("userid");
SMemberDAOImpl dao=SMemberDAOImpl.getInstance();
dao.memberDel(userid); //삭제
ArrayList<MemberDTO> arr=dao.memberList();
int count=dao.getCount();
//JSON 형태로 값을 가져가야함.
JSONObject mainObj=new JSONObject();
JSONArray jarr=new JSONArray();
for(MemberDTO dto:arr) {
String mode=dto.getAdmin()==1?"관리자":"일반회원";
JSONObject obj=new JSONObject();
obj.put("name", dto.getName());
obj.put("userid", dto.getUserid());
obj.put("email", dto.getEmail());
obj.put("phone", dto.getPhone());
obj.put("mode", mode);
jarr.add(obj);
}
JSONObject countObj=new JSONObject();
countObj.put("count", count);
mainObj.put("root",jarr);
mainObj.put("rootCount", countObj);
response.setContentType("text/html;charset=utf-8");
PrintWriter out=response.getWriter();
out.println(mainObj.toString());
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
-
MemberList.java: 회원리스트 서블릿
package com.member.action;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.member.model.MemberDTO;
import com.member.model.SMemberDAOImpl;
/**
* Servlet implementation class MemberList
*/
@WebServlet("/member/list.me")
public class MemberList extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public MemberList() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
SMemberDAOImpl dao=SMemberDAOImpl.getInstance();
ArrayList<MemberDTO> arr= dao.memberList();
request.setAttribute("members", arr);
RequestDispatcher rd=request.getRequestDispatcher("list.jsp");
rd.forward(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
-
view.jsp: 일반회원이 로그인했을때 상세정보를 수정할 수 있는 폼

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="../include/header.jsp" %>
<div class="container">
<form action="update.me" method="post" id="frm">
<br/>
<div class="form-group">
<label for="id">id:</label>
<input type="text" name="userid" id="userid" value="${member.userid}" readonly="readonly">
</div>
<div class="form-group">
<label for="name">Name:</label>
<input type="text" class="form-control" id="name" value="${member.name}" name="name">
</div>
<div class="form-group">
<label for="pwd">Password:</label>
<input type="password" class="form-control" id="pwd" value="${member.pwd}" name="pwd">
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="text" class="form-control" id="email" value="${member.email}" name="email">
</div>
<div class="form-group">
<label for="phone">Phone:</label>
<input type="text" class="form-control" id="phone" value="${member.phone}" name="phone">
</div>
<div class="form-check-inline">
<label class="form-check-label">
<input type="radio" class="form-check-input" name="admin" value="1">관리자
</label>
</div>
<div class="form-check-inline">
<label class="form-check-label">
<input type="radio" class="form-check-input" name="admin" value="0" checked>일반회원
</label>
</div>
<script>
if(${member.getAdmin()==0}){
$("input:radio[value='0']").prop("checked", true);
}else{
$("input:radio[value='1']").prop("checked", true);
}
</script>
<br/>
<button type="submit" class="btn btn-primary">수정</button>
</div>
</form>
<%@ include file="../include/footer.jsp" %>
-
MemberView.java: 상세보기 서블릿
package com.member.action;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.member.model.MemberDTO;
import com.member.model.SMemberDAOImpl;
/**
* Servlet implementation class MemberView
*/
@WebServlet("/member/view.me")
public class MemberView extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public MemberView() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session=request.getSession();
String userid=(String)session.getAttribute("userid");
SMemberDAOImpl dao=SMemberDAOImpl.getInstance();
MemberDTO dto=dao.memberView(userid);
request.setAttribute("member", dto);
RequestDispatcher rd=request.getRequestDispatcher("view.jsp");
rd.forward(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
-
MemberUpdate.java: 회원 상세보기-수정하기 서블릿
package com.member.action;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.member.model.MemberDTO;
import com.member.model.SMemberDAOImpl;
/**
* Servlet implementation class MemberUpdate
*/
@WebServlet("/member/update.me")
public class MemberUpdate extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public MemberUpdate() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
MemberDTO dto=new MemberDTO();
dto.setAdmin(Integer.parseInt(request.getParameter("admin")));
dto.setEmail(request.getParameter("email"));
dto.setName(request.getParameter("name"));
dto.setPhone(request.getParameter("phone"));
dto.setPwd(request.getParameter("pwd"));
dto.setUserid(request.getParameter("userid"));
SMemberDAOImpl dao=SMemberDAOImpl.getInstance();
int flag=dao.memberUpdate(dto);
HttpSession session=request.getSession();
if(flag==1) {
session.invalidate();
response.sendRedirect("login.me");
}
}
}
-
MemberLogout.java: 로그아웃 서블릿
package com.member.action;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class MemberLogout
*/
@WebServlet("/member/logout.me")
public class MemberLogout extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public MemberLogout() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session=request.getSession();
session.invalidate();
response.sendRedirect("login.me");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
-
member.js: 자바스크립트
var exp= /^[0-9]{3}-[0-9]{4}-[0-9]{4}$/;
$(document).ready(function(){
$("#send").click(function(){
//아이디가 공백일때
if($("#userid").val()==""){
alert("아이디를 입력하세요");
$("#userid").focus();
return false;
}
//암호가 공백일때
if($("#pwd").val()==""){
alert("암호를 입력하세요");
$("#pwd").focus();
return false;
}
//암호확인이 공백일때
if($("#pwd_check").val()==""){
alert("암호확인 필수");
$("#pwd_check").focus();
return false;
}
//암호 일치확인
if($("#pwd").val()!=$("#pwd_check").val()){
alert("암호 불일치");
$("#pwd_check").focus();
return false;
}
if($("#name").val()==""){
alert("이름을 입력하세요");
return false;
}
if($("#email").val()==""){
alert("이메일을 입력하세요");
return false;
}
if($("#phone").val()==""){
alert("전화번호를 입력하세요");
return false;
}
//전화번호 확인
if(!$("#phone").val().match(exp)){
alert("전화번호 입력 양식이 아닙니다.");
$("#phone").focus();
return false;
}
$("#frm").submit();
})//send
//아이디 중복체크 버튼
$("#idcheck").click(function(){
window.open("idCheck.jsp", "", "width=600 height=500")
}); //idcheck
});//document
function del(userid){
if(confirm("정말 삭제할까요?")){
$.getJSON("userDelete.me?userid="+userid, function(data){
//alert(data.root.length);
var htmlStr="";
$.each(data.root, function(key, val){
htmlStr+="<tr>";
htmlStr+="<td>"+val.name+"</td>";
htmlStr+="<td>"+val.userid+"</td>";
htmlStr+="<td>"+val.phone+"</td>";
htmlStr+="<td>"+val.email+"</td>";
htmlStr+="<td>"+val.mode+"</td>";
if(val.mode=='일반회원'){
htmlStr+="<td onclick=del('"+val.userid+"')>삭제</td>";
}else{
htmlStr+="<td>Admin</td>";
}
htmlStr+="</tr>";
})
$("table tbody").html(htmlStr);
})
}
}
-
SMemberDAOImpl.java: 추가 삭제 수정 등 각종 메소드 자바파일
package com.member.model;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class SMemberDAOImpl implements MemberDAO{
private static SMemberDAOImpl instance=new SMemberDAOImpl();
public static SMemberDAOImpl getInstance() {
return instance;
}
private Connection getConnection() throws Exception{
Context initCtx=new InitialContext();
Context envCtx=(Context) initCtx.lookup("java:comp/env");
DataSource ds=(DataSource) envCtx.lookup("jdbc/member"); //context.xml의 name을 jdbc/member로 바꾸기
return ds.getConnection();
}
//회원가입
public void memberInsert(MemberDTO vo) {
Connection con=null;
PreparedStatement ps=null;
try {
con=getConnection();
String sql="INSERT INTO jmember VALUES(?,?,?,?,?,?)";
ps=con.prepareStatement(sql);
ps.setString(1, vo.getUserid());
ps.setString(2, vo.getName());
ps.setString(3, vo.getPwd());
ps.setString(4, vo.getEmail());
ps.setString(5, vo.getPhone());
ps.setInt(6, vo.getAdmin());
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
closeConnection(con, ps);
}
}
//회원리스트 보기
public ArrayList<MemberDTO> memberList() {
Connection con=null;
Statement st=null;
ResultSet rs=null;
ArrayList<MemberDTO>arr=new ArrayList<MemberDTO>();
try {
con=getConnection();
String sql="select * from jmember";
st=con.createStatement();
rs=st.executeQuery(sql);
while(rs.next()) {
MemberDTO dto=new MemberDTO();
dto.setAdmin(rs.getInt("admin"));
dto.setEmail(rs.getString("email"));
dto.setName(rs.getString("name"));
dto.setPhone(rs.getString("phone"));
dto.setPwd(rs.getString("pwd"));
dto.setUserid(rs.getString("userid"));
arr.add(dto);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeConnection(con, st, rs);
}
return arr;
}
//회원정보 수정
public int memberUpdate(MemberDTO vo) {
Connection con=null;
PreparedStatement ps=null;
int flag=0;
try {
con=getConnection();
String sql="update jmember set name=?, pwd=?, email=?, phone=?, admin=? where userid=?";
ps=con.prepareStatement(sql);
ps.setString(1, vo.getName());
ps.setString(2, vo.getPwd());
ps.setString(3, vo.getEmail());
ps.setString(4, vo.getPhone());
ps.setInt(5, vo.getAdmin());
ps.setString(6, vo.getUserid());
flag=ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
closeConnection(con, ps);
}
return flag;
}
//회원 상세보기
public MemberDTO memberView(String userid) {
Connection con=null;
Statement st=null;
ResultSet rs=null;
MemberDTO dto=null;
try {
con=getConnection();
String sql="select * from jmember where userid='"+userid+"'";
st=con.createStatement();
rs=st.executeQuery(sql);
if(rs.next()) {
dto=new MemberDTO();
dto.setAdmin(rs.getInt("admin"));
dto.setEmail(rs.getString("email"));
dto.setName(rs.getString("name"));
dto.setPhone(rs.getString("phone"));
dto.setPwd(rs.getString("pwd"));
dto.setUserid(rs.getString("userid"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeConnection(con, st, rs);
}
return dto;
}
//삭제
public void memberDel(String userid) {
Connection con=null;
Statement st=null;
try {
con=getConnection();
String sql="delete from JMEMBER where userid='"+userid+"'";
st=con.createStatement();
st.executeUpdate(sql);
} catch (Exception e) {
e.printStackTrace();
} finally {
closeConnection(con, st, null);
}
}
//아이디 중복확인 사용하기 버튼
public String idCheck(String userid) {
Connection con=null;
Statement st=null;
ResultSet rs=null;
String flag="yes"; //사용가능
try {
con=getConnection();
String sql="select * from jmember where userid='"+userid+"'";
st=con.createStatement();
rs=st.executeQuery(sql);
if(rs.next()) {
flag="no"; //사용불가능
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeConnection(con, st, rs);
}
return flag;
}
//로그인체크 (비밀번호 오류: 2, 회원아님: -1, 관리자: 1, 일반회원: 0)
public int loginCheck(String userid, String pwd) {
Connection con=null;
Statement st=null;
ResultSet rs=null;
int flag=-1;
try {
con=getConnection();
String sql="select pwd, admin from jmember where userid='"+userid+"'";
st=con.createStatement();
rs=st.executeQuery(sql);
if(rs.next()) { //id 맞음
if(rs.getString("pwd").equals(pwd)) { //비번 일치
flag=rs.getInt("admin");
}else { //비번 오류
flag=2;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeConnection(con, st, rs);
}
return flag;
}
//회원수
public int getCount() {
Connection con=null;
Statement st=null;
ResultSet rs=null;
int count=0;
try {
con=getConnection();
String sql="select count(*) from jmember";
st=con.createStatement();
rs=st.executeQuery(sql);
if(rs.next()) {
count=rs.getInt(1);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeConnection(con, st, rs);
}
return count;
}
//닫기 closeConnection
private void closeConnection(Connection con, PreparedStatement ps) {
try {
if(ps!=null) ps.close();
if(con!=null) con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
private void closeConnection(Connection con, Statement st, ResultSet rs) {
try {
if(st!=null) st.close();
if(con!=null) con.close();
if(rs!=null) rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
'Learning > JSP' 카테고리의 다른 글
파일 전송 (0) | 2020.08.06 |
---|---|
게스트북 (평가리스트) 만들기 (0) | 2020.08.06 |
로그인, 회원가입, 게시판 만들기 1 (0) | 2020.07.29 |
서블릿: 출력경로 통일하기 (0) | 2020.07.29 |
서블릿으로 주소록 만들기 (0) | 2020.07.28 |