본 예제에는 두 가지의 댓글 작성법이 있는 데,
JS(Ajax)에 대한 보다 깊은 이해를 위해 다른 방식으로 구현했다.
즉, 기존(board6)에는 게시물에 작성하는 댓글과 댓글에 대한 댓글을 구분하여 처리하였다.
두 방식 모두 처리하는 코드는 유사해서 하나로 할 수도 있지만
이해를 위해 다르게 구현했다.
차이는 저장한 데이터를 서버에 저장한 후 사용자에게 보여주는 방식에 있다.
먼저 게시물에 대한 댓글은 작성한 댓글을 서버에 저장하고,
반환 받은 값(JSON: 댓글번호 + 서버로 전송한 값)을 적절하게 구성해서
화면 출력에 필요한 모든 구성(HTML 태그)들을 모두 JS (JQuery)로 동적으로 생성한다.
이 방법은 꼭 필요한 데이터만 주고 받지만 제법 수준 있는 JS 실력을 필요로 하고
작성된 코드도 복잡하다.
또 다른 방법은 서버에서 저장 후 반환될 때 HTML로 잘 정리된 값을 만들고
클라이언트에서는 그냥 화면에 출력만 해주면 되는 방식이다.
기존 코드
function fn_formSubmit(){
if ( $.trim($("#rewriter1").val()) == "") {
alert("작성자를 입력해주세요.");
$("#rewriter1").focus();
return;
}
if ($.trim($("#rememo1").val()) == "") {
alert("글 내용을 입력해주세요.");
$("#rememo1").focus();
return;
}
$("#form1").submit();
}
Ajax
function fn_formSubmit(){
if ( $.trim($("#rewriter1").val()) == "") {
alert("작성자를 입력해주세요.");
$("#rewriter1").focus();
return;
}
if ($.trim($("#rememo1").val()) == "") {
alert("글 내용을 입력해주세요.");
$("#rememo1").focus();
return;
}
$.ajax({
url: "board7ReplySaveAjax",
type:"post",
data: {"brdno": $("#brdno1").val(), "rewriter": $("#rewriter1").val(), "rememo": $("#rememo1").val()},
success: function(result){
if (result!=="") {
var div = $("<div>");
div.attr("id", "replyItem" + result);
div.appendTo($("#replyList"));
div.css({border: "1px solid gray", width: "600px", "padding": "5px", "margin-top": "5px", "margin-left": "0px", display:"inline-block"});
div.text($("#rewriter1").val() + " 방금" );
$("<a>",{
text: "삭제",
href: "#",
click: function (){fn_replyDelete(result)}
}).appendTo(div);
$("<a>").attr("href", "#").text("수정").click(function (){fn_replyUpdate(result)}).appendTo(div);
var href = $("<a>");
href.attr("href", "#");
href.text("댓글");
href.click(function (){fn_replyReply(result)});
href.appendTo(div);
var reply=$("<div>").appendTo(div);
reply.attr("id", "reply" + result);
reply.html($("#rememo1").val());
$("#rewriter1").val("");
$("#rememo1").val("");
alert("저장되었습니다.");
} else{
alert("서버에 오류가 있어서 저장되지 않았습니다.");
}
}
})
}
BoardReadAjax.jsp
이상의 코드에 보이는 것처럼
기존에는 폼 태그에 대하여 submit만 진행하면 됐다.
Ajax로 변환한 코드는 코드 양에서부터 부담스럽고 복잡해 보인다.
즉, submit을 할 때는 웹 브라우저가 알아서 데이터를 정리해서 보내는데
Ajax는 삭제에서 다루었지만 전송할 값들을 개발자가 모두 지정해야 하는 불편함이 있다.
(이 이유를 포함해서 이런 저런 이유로
Ajax 사용은 꼭 필요한 곳에만 적용해야 유지보수를 쉽게 할 수 있다.
어떤 웹 사이트는 Ajax로 도배가 되어 있는데 사용하기도, 개발/유지 보수하기도 힘들뿐이라고 생각한다.)
댓글 작성시 필요한 게시글 번호(brdno), 작성자(rewriter1), 댓글내용(rememo1)을 data로 구성해 준다.
댓글 번호(reno)는 서버에 저장 후 반환 되는 값이니 전달하지 않는다.
서버 주소(url)은 board7ReplySaveAjax로
삭제와 같이 기존 컨트롤 이름(board7ReplySave)과 유사하게 작성하였다
@RequestMapping(value = "/board7ReplySave")
public String board7ReplySave(HttpServletRequest request, BoardReplyVO boardReplyInfo) {
boardSvc.insertBoardReply(boardReplyInfo);
return "redirect:/board7Read?brdno=" + boardReplyInfo.getBrdno();
}
@RequestMapping(value = "/board7ReplySaveAjax")
public void board7ReplySaveAjax(HttpServletResponse response, BoardReplyVO boardReplyInfo) {
ObjectMapper mapper = new ObjectMapper();
response.setContentType("application/json;charset=UTF-8");
boardSvc.insertBoardReply(boardReplyInfo);
try {
response.getWriter().print( mapper.writeValueAsString(boardReplyInfo.getReno()));
} catch (IOException ex) {
System.out.println("오류: 댓글 저장에 문제가 발생했습니다.");
}
}
Board7Ctr.java
이상의 코드에서 확인되지만 삭제와 유사하다.
차이점은 반환 값이 저장하면서 부여된 댓글 번호(reno)라는 것이다.
클라이언트에서 전송 받은 클래스(boardReplyInfo)를 같이 넘겨도 되지만
클라이언트에서 전송한 값은 클라이언트에 있고 최소값만 네트워크로 이동하고자
클라이언트에 없는 댓글 번호만 반환했다.
success에서 반환 값을 result로 받아서
값이 없으면 오류 메시지를,
값이 있으면 사용자에게 보여줄 화면 구성을 하게 된다.
여기서는 사용자에게 보여줄 화면 구성 코드에 대한 상세한 설명은 하지 않을 것이다.
이러한 개발 방법이 있다는 것만 기억하고
가급적 다음 방법으로 개발하는 것이 좋기 때문이다.
success에 작성된 코드는
다음 코드와 같이 댓글 리스트를 생성하는 코드에서
리스트 중 하나의 댓글에 대한 코드를(forEach를 제외한 코드) 생성 하는 JS 코드이다.
<div id="replyList">
<c:forEach var="replylist" items="${replylist}" varStatus="status">
<div id="replyItem<c:out value="${replylist.reno}"/>"
style="border: 1px solid gray; width: 600px; padding: 5px; margin-top: 5px; margin-left: <c:out value="${20*replylist.redepth}"/>px; display: inline-block">
<c:out value="${replylist.rewriter}"/> <c:out value="${replylist.redate}"/>
<a href="#" onclick="fn_replyDelete('<c:out value="${replylist.reno}"/>')">삭제</a>
<a href="#" onclick="fn_replyUpdate('<c:out value="${replylist.reno}"/>')">수정</a>
<a href="#" onclick="fn_replyReply('<c:out value="${replylist.reno}"/>')">댓글</a>
<br/>
<div id="reply<c:out value="${replylist.reno}"/>"><c:out value="${replylist.rememo}"/></div>
</div><br/>
</c:forEach>
</div>
BoardReadAjax.jsp
![](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAqUAAAJZCAIAAAAf6tsHAAAgAElEQVR4nOzdd3wU16H/feX3PPfe5ya5vziO49jOzQ1pTo+xnTix5djYTrtO7NhxEsc4bnHHBRmwjW1AoojewTTRm+hVNCGtGiCQABUkENKKKoQkukQxQjDPHyNWq52ZM2dmZ4tmP+/XefFazZw5c3Z2td85Z0ZLXFnxdgqFQqFQKC4uXbp0iSsr3q4AAACXSkpKasv7iJ96UCgUCoVCCUUh7ykUCoVCcX/RyfvPf7dbkOUL3+v2he+9pZYv3v7WF29/+4u3v/3F77/9X63lnf/6wTv/Vy0/fPf//vDdL6nlR+/e8KPureXH3b/844Qv/zjhyz9J+PJPEm78ScKNP3nvxp++d+NP3/vKT9/7ys96qOWmn/W46Y4eN93R86Y7en71jp5f7dzzq5173dy51813tpav3fn+1+5qLbfc/YGv3PrzD33ltl98eNsvet/2i9633dP76/f0/vo9H339no/++5fXy68+/oav3PvJ//jKfZ98874+37yvzzfj+3wzvk+n+L6d4vt2ur9vp/v7fuv+vt/6db9v/brft9XyQOK3H0j8jloeTPzOg0nffTDpu13U0v97Xfp/7yG1DLj94dby/YcHfP+RgWr5wSMDf/CbQWr54W/VkvzD3yb/6HdqGfyj3w/+sa/8YchPrpef/u/Q1vLo0J89OvRnjw772aPDfvbHYXf8cdgdfxx+x5+G3/Gn4Z3V8tiIzo+NuFMtj4+88/GRdz0+8q4/j7zrz6PuVssTo+5+YtTPnxj98ydbyy+eHPOLv7SWe/4y5p6nxqrll38d+8u/jlPLr/6mlvH3/t1XJtz3dFuJ/8fE1vLMxPuf+bS1dP30110//XXXSb9+dtKvn530wLOTHnh28gP/nPygWp6b8uBzU7qo5fkpXZ6f+pBaXpj60AvTHn5h2sMvtpZHXkx55KWUR15K+c1LKb/513S1/PZf03/78vTfvjzjty/P+N3LM373yozfvTLzd6/M/P2rvjLrD69dL6/P/t/r5dE3Zj/6xhy1/PHNOX98c+4f35z7x25z/9Rt7p+6zftTt3l/emveY2p5e/5jb89/XC3vLHj8nQV/Vsu7C554d+ET7y58ovvCJ7ovfLJ76pPdU59MSH0yIfUvCal/eW+RWp56b9FTPRar5a89Fv+15+K/9lzy155L/tZLLUv/3mvp399vLU9/sMxX/vHhcl95pveK1vLRiq4frej60cquH6189mO1rHr2k1X/9JU+q5/zlb5rnldLvzXP91vzQr+1L/Rb+0Li2hcS176YmPZiUtqLSWkvqaX/upf6r/uXWgas/9eA9S8PWP/yQLVseGXghlcGqWXjq8m+sum1wa3l9cGbXh+SrpY3hqa/MXSzWt4cppaMN4dndGstmd1GZL7lKyM9b6tllOedUVmtZXTWu6Oz3h2d/e6Y7HfHZHcfk919TE73sTndx+YkqGVcbsK43PfG5b43Pve98Xnvjc/rMT6vx4S8HhO29JywpefE1tJr4tZen7aW9ydt85UPJm/7YHK+Wj6ckv/hlO0fTtnee6qv7Pho2vWSUvCxr0wv+GR6YWuZUdhnxs4+M3b2mbmzz8ydfWfu7DtzV99Zu/qpZfbufrN3J6plTlHinKIktcwtSppb3H9ucf95aikZMK9kwPzWMnBBqVoGLSgdtHCPWpIX7klO3ZOcWpacWjZ4kVrKBy8qH7L4elmyd6ivLN037HoZvmzf8GUVw5dVDF9eMWJ5xYjl+0cs3z9ixf6RK/aPXFE5cmXlyJWVo9SyqmrUqqrRalntHaOWNd4xa7xj11SPXVM9dm312LXV49YeGJfWWsanHRi/7qBaJqw7OGH9IbVM3KCWw59uOPzpRrUcmbSprUxOP+orUzbXtJaMmqkZx1pL5rFpmcemZdZO89SmtJbjKVnHp/tKdt0MteTUzcipn6mW3PqZufWzchtm5bWW2XknZm85MXvLiTlq2XpyztaTc7eenLvt5Nxtp+ZuOzVv26l5+Wo5PX+7r5xZsKO1LCw4G+XFZt5/8Yfv3vfIP9567beVW29ryP3CyQ3/Z/fcG26/5znynrwn78l78p68J++jsFjL+y93Gfitl2b9feycjfnPHSu/43zuDSfW/cfIXnc8//hDbzzzwI6xN5D35D15T96T9+R9zOa9pVvnunTpYrW+vb1Yy/sv/qznt95a9MeJ26ftOnLweI/mmhvqF3556eyXEsZN/vpT49Q6ZSP/P199dTchzXt1F2rea5+hvbxXt43mvNd9Oe3lvboteU/ek/fkPXnvYN5buo5utb69vVjI+y/+rOf33lvePbM2/Vhl46nfXKuOO7iwy+oSz6Dyxuczj/2s3+YbHhv9+e91m/jW9yOV9/7j+1DnvVonpHmv7kKQ946M78l78p68J+/J+yjJ+zhjYc37Tm8uejfjWEHDrsunfnotPy575P2Pj8v85cDNj08r6l107vWchvvHbLvhiXEPPfQ4eU/ek/fkPXlP3pP3Yct7/zraJdby/stdBvzvuK3pR0ubT/7wWlZc5pD77/rLwC//6O0v/LTHTY+OvLvv+u45J1/YdOxHH636r7t7B+S9j3/e+y/3z3v/5b68VxTls8tX1IVq3ge0HJD36kLb1+/98z5gR/5h3xb5933iv8SX9/7d/vav+wU05Z/3/svVvPdfYinv1VVq3quP1bwP2LtR3vvX8eW9oiiXm1ufiJr3/tV8ee9fjbwn78l78p68t5H3utVkxvf+AR8Q/9byvtNLM2YWlpw/de+1HXH5g+6647cffOkHb/nW/qDHsn8urHrZUx8/Mu/mv0/UHd+rj9W8Vx+r43v1sZr36mN1fK8+9uW9Sh3fq48F43t1oYN5r47v1cfa8b36WB3fq499ea9Sx/fqY3V8rz5W8159rI7v1ceS4/sAMnmvju/Vx9q8Vx+r43v1sS/vVer4Xn2sDu7Vx768VzG+J+/Je/KevA9z3gdMD9ifz3+g/+rDx169djCubMlz/5i96/b313TqsbJTj5XffG/lNxKW/6jvpk8Kzr+dd/J3M4pufXWu7bz3n89Xl/uP733z+eoqe3mvjcmQ5v1nl6/45vPVVQ7mvdF8vv+z883nqz/azvvLzVd88/nqKt28v9x8hfl88p68J+/J+4jkve7EvuW8X7xl+LVj/3k45c5Py2uGVDcPrm5Orm5O9jYP8jYPrLo8oPKzxD0X3sw9+fD0ktvemB9M3geEsY28V5cE8/d4agtW896fjbz3F/z1e7WC//V7dYmDee+PvCfvyXvynryPeN47ML7/7d+ePXu40+l5Xxq/tyap4tJdyVnfSFj+jYTl30hY9t/dl3393aW3vbPk1rcX3fJW6tfeXPiVv4VkPj/68157v55ifXzvyP16/kkc6vG9//165D15T96T9+R9x75+P2bsfZcK4+bM7N5nz/mEbad+9P4ayS/TtZ33vrjqcHmvPo7gfL66yvHr98znk/fkPXlP3tvIe6M77Z3Ne8fuz89P+5p3+hf+Ni7972mHehY0PjG39Jsvz/ni3b0//91u//n9d75494c3dZ36tW4Lb+mWenO3hTf8Jjn4+/MLig+qD3TzXnx/vrok1Hn/jesxb3p/vmne696fr37ZjrrEwfv1fGzcn+//93j+1Rjfk/fkPXlP3juV9/b+Hk9mFkEq72s3/PuYD3/2nbfm35mc9UpWfa9djS+lHbxzwMbb3ln8nZ7L705a/0paTfcd555aeeDrr80NGOLzfbpR8n26ajbzfbrkPXlP3pP3UTufbym5Q5L3h5f/x+e/2+0LP074ZrcFvxiW9ZfVh7vln+lZdKFX8YWeRRfeKWz8+/ojj0wp+Oa7i7/QuRd5T96T9+Q9eU/ex3jeJ0lT895SfXt7kcr7mQNv7/H8vZ//brcv/eSdn3Yb84NeS+8auPG+yQUPzi17cErh/aNzf/bJmlv+NesLP+vJ/4cbtXnP/5dD3pP35D15H5687xJi9vYilfed7npx7eCv14yNy+vzpXee+tXND/T+yl8nfO2VWbe8Nver/5x245Pj/uveT4xu2SPvyXvynrwn78n7mMr7aC4meR9MIe/Je/KevCfvyXvyPkqKYd5TKBQKhUJxWbGT98U7t2RtTluxdMGyxfOWLZ63YumCrM1pxTu3BNmVEDVLoVAoFArFQt7vKcpPW71kyqRxgwYk9uv70Scfvf/Jxx+oJanfJwMH9Bs3ZsScmVNXLU/Nzdoos+/S3duyM9YvXzJ/1vTJY0cNG9C/b2Lfj/t+0tvXbL++Hw0akDhl0ri01Uv2FOVH/GBRKBQKhdJBi2zep29YNWHcqCHJ/Qf275vYt/eHvZNe6z7gqZfH/PmV8X99ZcyLb/ZJ6Plx8sB+Q5L7DxsycMSw5DGjhk/5dNz8uTMWLZi9ZuXiNSsXb0xbsWbl4lXLU+fNTpk9Y8qnE8aMGjl0xLDkYUMGDk3unzyw34CkfkMGJ8+cOWPW7LmzZs4YOWL4sCEDE/v2Hti/75Dk/hPGjUrfsCrix4tCoVAolI5YzPN+T1H+ktS548aMGDVi8Lgxo179YHqvIRsmLSpZuHb//FX7Zi0rn79q38I1FVMWl74/fNNbvWfOSJkybfL4MSOHjBs9fMLYkRPGjZwwbtSEcaMmjh+tPhg/dsT4sSPHjRkxdvSwlKkT5s1JWbJkacmesguXrgR8H9ylz1rK9lYsXbJ40sTRo0YMHjdmxNJF8xwZ6Mv//SLgFO2vWG525oqVa+anLrdUVqxck5udGfHPDorryy9+fleHa5kiKEnivN9TlL9o4Zwpk8Z/OmF0v+SJL36ybuGGysXrq2Yu2zt54Z5xc4vHzSkeN7d40oLSmcv2Ll5XtWij95V+60dNmJuVsX7T+lVrVy1ZtXzR0sXzliyau3jhnCWL5i5bPH/NyiXr1ixL37A6K2P90iWLdhaX+QL+6lXl0mdXPrt85dJnV65cueZbvqukfPaM6Z9OGD1l0vhFC+cEH/nq0wbCRvsrlrF584b0zIMHD5w6WW+pHDx4YMPGjIzNmwPe1RcvnKdQnCoTx41UUzl0LVPCXEzyfs3KJXNmpcyfM/3ND6b0m75rhefApMV7RszcnTylsP+kgr4Td/SduKPPxO1JkwqSU3aOml00ZcmeVTmHBs0uerfPzBzPxtysTblZm3wPAn5ctCi17uQFRVE+a77WdP6zc40XT51pOnGq8cSpxvoT506eaTpz7uL5i5c/a76mKMqJs5eWLFo0f8702TOnrVm5xJGnrfuN9IAMS+833bxftHTl8ePHGhqO19fVWioNDcePHz+2aOnKgL1cvHA+4h8oFNcU/7zftG65g4W8j1QR5X1WxvrFqfMWL5zzdp+UQfNLF6ZXj5xbnDi18MPx23uM2fbO8C3dhud1G7Gl2/C8d0ds6TEmv/eE7QOm7Rw1ryQ1vXpY6p73kmZtydlsVFIXLTrZ2KwoSuP55oZT52sbzh2tPXPk2MnqIw3VR05UH2k4VHOypu5sbcO5U2cvNl28oijK2fNXU1NTFy2cszh1nmfzuuCftuDT/MLllitnd12uTbly+KcXCm88t/nfz2/5wdWLh8ISJegA1F8ZGeqbTfsrNj91+ckT9XXHa/3L+fNNLS0tLS0t5883BazyLydP1M9PXR7wribvKQ4W8t59xTDviwrz1q5evnrlkjFTUt8cnz8nvTp5VlHvSQXdx+a/MXzLvwbnvJCc89yg7JeG5D43KPvF5JyXh+Z1G7E1Ydz2TybvHDK7aG56dfeJBZ/OXJa/JUtb1qxZ7a05fU1RzjRerj3ReOjYmeojJyoO1O311hbvPbSz1FtQXFmy7/D+gw0Hjp48Unu24dTFM42XrynKgWNnV65YvnrlkrWrlxcV2v9TPd28v3L12rrS4x8sL+29Yl32rpcaKu86n3tDY8YXL+7pfqF8xsX9E0+v/r6zmYGOS/srI36zaevPT11+oqG+1k9dXV1LS0u3Tc922/Rsxck9J06crDVwoiGovN+5M39/4dxDBZ+cr7q9aceXzqb/vyczvrlvF/fDUtoKee++Ypj32Zkb0zeu3bhh/cNvr5ztOTRoTvH7k3a8NSb/X0Pz/pmc8/SA7MRZRafOfXbufHOfGbv+lpj1j4HZ/0zOeWXYlrfHbPtwcuHgOcVzsw4/8s7KvNzsgvxc/5K/NTs9p+Cqopw8d/lo/bkDNacqDtSXe2tL9x8r2nskf/e+i5cuX7nSUuE9uqO0qtxbW3XoxIGaU7Unms40XlYUJT2nIDN946YNa7Izpf7qT/C0/T++D5w4/89ZO19ftn/BvvpDdb2aa25oSP3KmgWvJS9YMCaj4srVa4qi1M24Sfu5r96H5Sxtm+qSuLg4R9r3teNUgwH871ALZon/KiU0h1qgoKBg2rRp/fv379+//7Rp0woKCvzXan9lxG82bf35qcvrG+prjh33lcbGpjX7l7y27umWlpbGxib/VQGl3nrel+zOn7w25/UZWe+lrvDsfKG+4s7zuTecS//Po56nqzZ+Up3Z6/iSb0b884gSPYW8V8ueonxHbhLfmLZi5PAhG9NWBNnOwnkzkwcmJg9MXDhvptVt9fO+ZNe2rMxNOZ70j0cvGbh479DUPb0mFb45Jv/FYXn/GJj9l8TM3tN3XW6+qn7wrc0/+qc+mX/u53kqKavroJx/Dc/rNjb/w6mFQ1PLhq6s7DMidWfBVv+ycnXayfPXzpy/WtPQ5D16au+B+tKqYzvLDxWWH8rbua9sf+uc+bVr1/ZUHtpSuK+sqnbfgXrv0VM1DY1nL147d1lZsXJ1jic9K3NTya5t9g5ZQN4fOnn+jxO2vp/bsLm2qvHUb65Vxx1c2GV1iWdQeeOLntpHxm3vvWT31avXzmQ8r00FQT4ZrTXVUfJed/OACLe9RNtmOPN+2bJliRrLli3zVShzJO/r648cPa6WuvqT5Q3FL65+YsW+hecam3zLdUt9vbW835S75S8Ts15KLZ1bVnuormdzzQ0NqTeumv9K/9mzPlngKdmdX1a8vWbqDbrbBvzX3U4VX7OC/yacEsFC3pcVb8/xrB81YvCoEYNzPOuDaad097bkgYlHDh9OHphYuttabGVlpA0bMmBg/76e9LSy4u3JAxPVS37JAxPLirdnpq8d2L/vsCEDsjLSTJvSz/uC/JxtW7ILtm994I1lY9cf+GjG7rfG7XhxxNa/D8p+Iinrw+k7fWGvKMqa7Ud/93HGH/pkPtYv86n+2c8k5/xrxNa3x2/vPX33lIzDD721bHfh9uJdO9RStHP7us1bL15Tjp28eODY2b0HGooqanbvO7q95MDW4ur0raVF5V5fy9euXSsqq8otKC/Zf6zi0InqmjPHTl5sVpR1GdsKd2zdtiW7ID/H3tH3z/srV691nVHYK7uuoGHX5VM/vZYft3XsA8/P2f7ktIK31x3pV3b+zdwTj04v/mDJ7ktHMrXBEGTeG2Wb7pJoznvdp+xI3gd58mRDQUFBYmLikCFDioqKrl69evXq1aKioiFDhiQmJvpG+WVO5H1dXf3BI8fVcvZc05Kyuc8s/UPa/hUnT531X36lpeXsuSbfkoNHjtfVWcj7zXlbHhmR0SunXns6+4Kn9oGRua9+ur60KP/A0kd1Nw913odhXxQbJZbzfnHqnBHDkhenzhk9csj+/fv2798XZORvXLdiyeKFiqIsXrTA6hfJjBg60Fu1X1GUkcMHz54xZfq0yepH0PRpk2fPmDJy+GBFUbxV+4cNGWDalH7eF+7YUrRrR9oGz4Pvru+/eG/ClF2vjt3RddiWpwbl9Jq+6+LlFt8nY+3pi38ZnPNQ7/RHPt78h76ZjydlPzUo59lhW14bu/29abuTl+9/+L0Na9dllhbvVMvWvJwtO/efaLp2pL6p6uiZUm/97n01W4q8uYX7swsqMrbvXbw2q/7EGV/7165d27Wn0rOttKy6vuroqSMN5898pmzdXbVtS07Rrh2FO2xewvfP+7TS2leXlG+u2dN88ofXsuJ2T/pdVX2Dolw9evrC1NwDLy8qe3/rmZfSa/80aWvJ0baO+QT8gXXAEt9ybTVfZW2DRkv889U3HvKvKbnQP+9ttxPwY3jy3ugYyiwM2JHg7GHSpEmJiYmlpaX+C0tLSxMTEydNmqT+WOZE3tcer68+dPzMmaYrV1quXGl5cv6DT85/cOqOMeqPZ840qauenP+g+mP1oeNqqT0um/clu/P/PC6zR9Zx3+ls3uhfPzsj708Tt7y2oqpPadMbuSd+P3Xny5M37M2aoNt/8t5NJXXezGmTxhUV5qk/FhXmTZs0LlVvZjiW837EsGRFUdSwV3/fg4z8yZ+OPXzooKIo1dXeaZPHW9p20IB+fp9Cxe0/lNp+HNi/r2lT+nlftHN7xd7S0RMX/frNjT1mlbw0Kv/xxOyH309/Y2z+hc/avhXnwmdXun1a8FRyzt+Sc54enPPMsNznhm95sOemRz5IfzIp+19jtn88v7zLWxtHT0zdW1Zcvqdob1nx6lUrCkuqj5y8VHHo5O59NRtydi9albFqY+7qjXkrN+QsX5+zbF326k15jU0XfHu5du3alh0laz07iipqKo6cqm+8WlhSvWb1yoq9pUU7257J7IXL/u2Hz2jL7IXLjJ622v77y4sXl1ecP3XvtR1x1VO6KMoFRWn70/+nU3b0yT39sqf+ydklvVeWaLNBN6gEDxRh0ojjX3dcHsxCp9rR9jngBEj7dGTqyDy2tFAm7JubmxMTEwcNGnT16lX/5VevXh00aFBiYuLly5eV9nkfpyfgzVZmkPdVB49fudLym2l3aoua+v4/nj7TVHXweNVBC3k/eW32C/OLfKezBRMeztyxpbxke8aWrQMWZT07a3vPLadfTK/97djMlRl5up8RRpPtkgvVx3F6s/faHTnyYU0RlGmTxo0aNkiNfDXs1R+1Ncn7yv0V/p8AtiN/a076lEkTfO1M/nR8fl6G/ObZGevUQbzAyOGD1dl+cdHP+z0luw9W73//44k/+vuqR7pvvOu5ld99cu6feyxvPH9ZvFdFUU6evfhkr+W3P7Xw7hdW/uG9TXf9M+39jyfs37dHLbNmTs/bUbaj2Ju7vXRdRv7cRavPnGs0bfPatWsZWduWrErPyS/dWXqgoKhi5swZB6v37ynZ7evzv/3wmbvXVWrLv/3wGaOnrTb+8tz8I7WvXzsYV7bkua5zdj80OvfXI3PuH5kTPyL73mGe331a0Lfwwtt5J59I3fvouBxt36Iz73U5lffatUYdDn58by/vdfsj+RKY5n1zc7OiGd8bhX2ZMO9rauv3Vx8/fabpypWWe8Z8x7+oYa9dePpM0/7q4zW1snn/6vTMhaXl6uns/on3Ve7bVl7SdvPR4+M9H2Qcf9lT/9j0wtdT0nU/I7ThbXWhuIJgCcXx4p/x/tmvrRmzeZ+VsW70yCG6Hw6Skb9q+cIxI4cOGtDPV3btKvQ1Uliw3X/V2NHDVi1PFTc4e8YUdSjf3Nyctnb1yOFDRg4fkrZ2tfpZVFpaPHvGFJmnpp/3+8pLjx873KP3hM99a9zX4md87b6ZX/nF0OJ9x40+IgOMn59/0z2jv3bfzFvjZ8R9e0rPjz49cuSgWmbOnLF8xer1mzzpm7MXLV27KSNPss1Ln302bfrcjZs8m9I9aevSZ82aefzY4b1lJW1HZOGyf/vhM/eO3OFfZMb3abvGXjv2n4dT7vy0vGZIdfPg6ubk6uZkb/Mgb/PAqssDKj9L3HPhzdyT/zuv/JHRJtfvg8x707l9e3nvn0NW2wl47N+I0R4dzHvBtQ+ZiQHJKQQtdT5/z549/gv37Nkjns83GrYK8v7g4eO7y47uLjta19DY3Nzy0yFfV0tzc4v/j/6lublld9nRg4ePS+b9P6dlHal9TT2dfWbO7vuHZvxycPovB6ffk5z+80Ebu4zN61N44e28k4/P3/PQUP3vtJCPdt2tjGqS95EqvsgXhH1ZrOZ91ua00SOHeKsqjT4c/CO/ZNdW3UaGDh5w+vQpwSeMvxMNDeqdd9pSunubejf+tKmtHztpa1elzp+pzs2kzp+ZtnaVunza1Ekyd+zr531lRfmJ+mOJg6Z/7n9GfvnOqTffP+Omhyf96K/jDx0/a9r7/D1Hf/XC1K8+MuPm+BlfvmPK5/57aFLy9NMn69WSunBB6qJl6zdsTtvgWZ6WPW7agsrqw6Ztfnb58vwlabMXrFq3wbNuffrceampCxecqD9WWVHu/2RaI//9zWoxCvsy/7y/urOp5jtn5n95/N6a/vs/+/3UXfcO89w7zHPvsMxfDc381ZDMXw7OuGdw+i+SN92TvKl76k5t34LMe3EIBZ/34pqW8l5cU/BMw5/39mYCfHbu3Kner1dc3Hp5rLS0VL1fz3cSUKZ3/V43sQR5f+jI8aLyGrXUNzQ2N7fcPvC25uaW+oZG9cfm5pbEdR/dPvA2dbm6qqi85tAR2bxfUzha5nT2D3P23J+sPx9oKe+1kxySeU/Yh62Q90bFk24S9irTUf6q5QuHDRm4b2+5uB1FUUpKioYNGSgY36t34/vqDx08wHeSUbJr69DBA3yrfHfsC4pB3u8vb6ivnTF//ef+e+gNv5h500Ozv/rnBTf9edpPn5+890BtY2PjuXPnzp07V1N38uFei258csKNT4y/8YnxNz4+9sbHRn/l8QlffXLmV/+88KtdZn/pzumf+/qYmfPXnz19Qi2ezMy581I3bc5evT5nybotc5Znfjpn5fDJC0dOWzRq2pJRKUvGzFg2deHao8eOq7tobGw8dfr03CVpU+atXb5+a9qm3PTNniXLVno8mQ31tZX7ywOejxr5dz89VRD2ZX55f+18v0uFcanzevbZc75PycW/Td9l+goFcCrvTcNeCfpSvVPz+eHJe/EBkYx2G+P7pqamiRMnav8YLzExcfXq1Z6NRy0AACAASURBVL5qZU7cr3f4aF3p3hpfaTjR1Nzc0nCiybekpvZ0ypap30q8bVTGCP/lh4/WyeT9gYq5jUe/dWb+Derp7CMT838+aOPPB238+aANdw/ccNeA9Xf2X9c5ae0diWs691v9/Kf6X2gR/Hy+uCndHykhKsznC8rokUMOHqw2+mTwp0a+4O/yszPWzUyZtHFDmn9a+7t8+fKaVSvmzJyS69kg6FJY8r6irL7u2M7ivf9224c3PLjkxscX3Nx12S0vr735uYU/fnVGQWnlkev2Vh54sNfim9/YdMu7ube8nfW1Nzbf8vrGW15Ou7nr8pseT73h/kX/duu7O4v3njt76tzZU+fOnq6qrBozdoInb/fitC2LN+xYnlm8Krc8LX//2vz9GwoPrs2vnLZ4/b79VWrjR48ePXjo8JxlG6cv96zwlCxLL1y+IT87r3DQ4KGVlfvr645VVpRpn5Ia+YKwL/PL+6s1v6pbdNO7i3b8Y93hD3eff3FVVcLSPbsPn75y9VrTZ1eKj5x+dc6OXyZv+vmgjfckb5q//aD2ZZMMcu30sqAdoyXi2XXxQkV6fG+1cd3nEvBMbSzRPSC6x1CwUDE4M9BtX/EL+0mTJu3cudP/+3YCbtcvcyLvj9TUle8/JignTjWN2Dziv/vclufNO3C4wbf8SI1U3jccfPVSYdzCuT367Dn/cVHjYxNzbXwI2oh2xvdRW7hfT1A86WmzZ0xRb9ZTjRiW7Cv+C+fNTjG9iq/Oxk+fNjngTiBFUVpaWiZ/On7xwtmmXVLn831/g7dm1Qr/+fw1q1aoy6dPm2x/Pn//3pKao4fPnD7V+b5Xb/rzxi8/s+KW1zfc8m7WLT223Pzm2p+8vSBj66491w2an/XVd9bf+nHxrR/tvKXX9lt6bLnlnaxbX9/wlX8sv+nR9T9/8O1zZ083NZ5pajzT1Hj23NlTvXr12rLTuyS9cEVO2dr8qvWFB9OLazLL6zPLG1ZtrViVvsXXcnFJ6ZyVGfM37FhfeDBte9XKnLJl6YX5u6s+/qhP49nTNUcP799bYnq8BE9bUZTzeV+6UPpO1+lb48dsfSWrvnfJ+Xdzjv95euGvhm5+aEz2UykFPXNPvVfQ2HXd0UfHZqnfsmePeAJZJuxjSkSeflNT04QJE9SwP3/+vLhymRN5X3Osfl/VMaNy8nRT85WWr31029D0ESdPN/mvqjkmdb/e+cqf1C64odvcvKfXHX5/Z9M/l1f8a3r20s25JbvzdxRsW5GR+/fxG+5MXHNHvzWdE9cMX+bR7b92ij5guXZhmcGZgbi1ID+sKTKFv8czLQHRLlhoWrIy1s2dPUP3A2TOrOnyt/q3v19vlcP365WXFlRVVpxvOjd20pL/+OWsr3ffcnN3z60fFd6aVHrroIqvfZT3kw9XrM3I27Zt27Zt2z6cmX7LJ7lfH3notiFVtw6quKVfya29d9zSPfu2t7L//eczx01edL7pnH9Zs2bNyrTs9N1HVm2tSC85lrnvRG5145ZDF/NrLm8oPrp0Y67a7Jat2+al5SzL25tb3Zi598Sm4pq0Hd5NBQdWr89euXLV+aZzVZUV5aUF9l5RX943Zt6oKEpD46Xfjsx8aMK2v6450i3/TM+iC72KL/QsuvBOYeM/Nhz906ziLiMz9x0/F0yWkPeWhP/pt7S0yIe94lDeH6utr6qu1S1Hak7mVubd9OFtN31425UrLdWH6vzXHpO7P/9c9heOev72xLhN947MeyWr/oOiprcza/530pa7+q+7f+jGxz7NTchqSCho/Mfaww8PSVO/ZY9CUQt5rwSd93NmTS0pLlK3am5uLizY4ZucLykumjNrqkwjIf97vLLi7ZUV5fV1tSdOnvpe539+/5PiW/sU3Tpo3/+MO/ytyce/m1L37RG7705aM37ppinL0+8dtOb2aYdvn9nwvRkNnSYf/8bYw7cOLLv1453f/6joB3c+e/LkqYsXmi5eaLr+nx83nTlz+q233tnuPZu5tyHHe277scs7Tyg7TyhFp5SdJ67MWp+7dnPW+gzPgo05a3cfKDqlFDYo+TWXMytObi6tLfCe7fZmtzOnT9fX1QbcrGep+PL+0p7nLpQNVRTlxLnGl6eu+v0Yz+8mbn1o+u6H5pU/Oqfk8Vm7Hpu05e9Ttx5oaLKSHeiQioqKJk+eLBP2ikN5f/x4/YFDx43K2TPnr1y5euXK1bNnzgesOi739/enN/1XWfH23G1bfz0o7YGxeU9pTmef3nD00Zm77ktevzbLzlQ/xcWFvFeCy/uiwi0jhiWrQ/CzZ8+mTJ20YO70ubNnNDU1KorS3Nw8YliyzP/6ljww0bfrkHzfTlnx9r2lhd6qyvNNjes253/uu33vn13/jQk135tz6q7Fp361/Mx9K8/+cn5157F5d47Ovmdu1f1rz923+twvlp25c/Hp780+8Y0JR+NnHv8/3/1kvWfHpUsXtKWgoHDM+KlVTcr22itFZ5SSc0p5k7LvolJxSdlRezpt957l23blVh/fe1Epb1JKG5Xdp5Tttc0V55SRoz/dtWv3+aZGb1Xl3tJC269o2/16l2vPZnapGRtXO+07Z/KHZJRWf7is6I/jsx8asfmFGfl9V5V69tVdvWZ/Gh8di/ZKmxH1XSTJKO8bGk7UHKu3URoaTsjkfW3OHw6kv1VWvH3Ltpxnxsx7eNiGh8dmP5iyq8u88j/MKvrjtB2/H5v56Kj1G3Pt/1eTFLcW8l4JLu/Xrlq8ft1aRVEOHzo4ZtSwFUsXlBVvX75k/rgxI44dq1EUZf26tWtXLTbvz/Xv0x0xdFBIvk9XLZUVZXXHay9fvjR01Oz/vG/EY5su3rf+/EObmn6fefHR7It/yrn4WN6lx7dceizv0mN5lx7NvvC7jAsPbWi6N+38H9Y3/ed9I0aMm3/5s0tGJXVh6vhpqTWKsu+SUnFJqb7SWg5cbSveZsXbrOz/TKn4TDnQrIyflrp0ydLLly/VHa/VvVNPviT5/f09YEMXi7S/YouXrqqtPdbQ0FBfb600NDTU1h5bvDTwW7i1eb93d9qx1XfVjI07OPHrFSu6zVyz8dWpmx4euvbeAWueHLP+zZRNs9ZllTKNT9Er5L0SXN5PGDey9tixXbsKBw9K2riu7b/FW7922eBBSUW7d9YeOzZh3EjTdsT/X44nPS3Y/y/HV7xVFfX1dc3Nl4eOmv5/fvzJE+tOdC25+o9dV57e3fLP4pbnS1peKG15vqTlueKWp3de+Xth8zNFLY+nnfh/fvLx8DGzmpsvN1++3Nx8vQQ8vnx53rx5ycMmei8qtYpSoyg1ilLbvtQoylFFqVGUqovKwGETFyxYcKX5cn19nbeqIshXNCkpKeLvKkqslYBfsYyMzekZ2XV1tWdOnzxz+oR0OVlXV7tpsycjY3NA++L/D5dCsVRiNu/V/yxHLYtT5wgWikva6qUTxo2cNztla07gN1fmZW+aNztlwriRaauXWu2e8/8frl/ZUe2trK+ra7lyZe3GnB/c9ddvv7rirZ0XP65RetUo3Q8r7x5UehxSehxVeh1Vuu28+O3XV/zo50+npedeudIsU/K2bHnhhZeWbS48oSjnFaVRUc4oyhlFOaco5xSlUVEaFGVJesHLL7+avy2/5cqV+vq6am9lWfGOIF/RcA8GAUVRNL9iGZs3L1q6cn7qcktl0dKVGZsDw76MvKc4WtRUjguZiD/BGCymeb+9vGRHVeW+mpqapqbGM2fPjR0/7e77u34hvv9P3lz2x9EFT08t+9+RO370xtLP35f0iweeHT8h5czZc1dbWq62tFy92tLcfPnixQtNTY1nzpxWS1NT48WLFy5f/uzq1Ra12rnGxlmzZr322uuDRk1bnr6j0Nuwr+5iQVX9kk3bB46Y8uqrr8+aNbupsbGpqbGmpqaqcl95SbBhT6FQKBRKrBXzvFdL5b5Sr7fy+PHapqbGlpYre8orFqYuSx4yOilpYPKQ0QtTl5Xt3X/t2tVLly6eO3f2xImGmpqj1dXeaq+3qqrSW7W/+nrxVlVWVVVWVVVWV3uPHj3S0FB/9uyZS5cuXr3aUllZuXLlqvHjJwwdOnT8+AkrV66qqqq6erWlqanx+PFar7eycl9pxI8XhUKhUCgdscjmvVqqKsqqvZVVVZWHDh2qq6s7depUQ0NDXV1dTU3NoUOH9u/f7/VWVVft91buq9xXuneP6P75vXt27t9XUlW5t9q73+utrKysPHjw4NGjR+vq6hoaGk6dOlVXV3fo0KGqqspqb2VVcHfnUSgUCoUS48Va3reWkh0V5cVVlXu9VRVVlfuqKvdW7ttTUV4cZFcqyosqK/ZUVe71Vu3zVlVUVe6tKC8uY/aeQqFQKJSgi07eR/R+JgAA4CTyHgAA9yPvAQBwP/IeAAD3I+8BAHA/8h4AAPcj7wEAcD/yHgAA9yPvAQBwP/IeiApxcXEBDyxt5ftRwGrjANyEvAfCSpvBvuUBD7QbSi4U791SfQCuQd4DkaSN+eDzXjvoF9cHEAvIeyCSyHsA4UHeA5EU/rwPuI4AIEaQ90Akaa/lM74HEArkPRBJkuN7o7vrTU8O/B8wsgdiGXkPRIz8/fmSeS/+YzyjxgHEAvIeiBjJvBdMyPP3eAAkkfdAZBglN3kPIBTIeyACBKFumuim998R6gC0yHsgfAQ3zenmvfzteLprAcCHvAeigr1b6sh7AJLIeyAqOJj3isSN+gBiDXkPAID7kfcAALgfeQ8AgPtZzvvOAADEqq5du4Yxo51kJ+/D2D0AAKJIp06dIt0Fm8h7AABkxWLeR3hKJWr45nYi3REAQKj4PupjNO/D1Mfo5nvtOSAA4Fa+j3ryPnaR9wDgeuQ9yHsAcD/yvpX4azsFX+HpyLd/R/YrQk3zXubbTMVfemrjO1P52lQAcBB5H8hqfkvWF0dalOe9PaYnTCQ6AIQNeR/IUjIZDUNDPR/gLN28F4+8ZYbg5D0ARA/yvh01gQSjc3F9mSCMwuQLxfg+jvl8AIgm5H07RhPspiEtGW8yTYWfOO9tJLHRiZHVrQAATiHv2wgyWybATKevBasiO6IV5L1gXG603PYJDXkPAKFD3rcSp5T87LRMBXvD39AJfnxv4yqGeCafKX0AcBZ5rygScWs1eKyeEERz3vuQvgDQcZH3DpAcj1q6XhBOTt2fb3uYzpgeAEKNvG9jI66MMs+ostGPUZj3zhIcE+0qUh8AHEfeS9GNH/F5gKUWojbvrZ4DWa0s6BWRDwAOIu+lBJn3poEXnXlvNY+tPgvyHgDChryXIj8dbW8uOjbzXmE+HwDChbyXYpp8plf6g2k/1MIwny9/AEl6AAgF8h78f7gA4H7kPch7AHA/8h7kPQC4H3kP8h4A3C+m875r166d0KlTp+uvPQcEAFxM/ajvFIN5DwBArCHvAQBwv1jM+87o3Llz585du3blgACAu/k+6mM078PUx+jWifv1AMDtYvr6PfGmIu8BwPXIexOC/9JG8N2xHet7YY3yXvfp2D4gNjom2FcYGPXcamdCXR8AZJD3imIQVL5VAQ98TL8T3tbTiQDdvDfqv+0MtvEV+vL7kumMpdMR/yUBax15Jwg60IHeOQA6EPK+HcFHOXkfsNzBvA9+X46cEAgqi/PY6jvBNe8cAB0Ied+O1by3NGSMWlbz3t4TJO9t1weA4JH37VjKe9NtO4owjO/tJZzkvtS1pnXkT87IewDuQ9634x8wAUlA3osPiGmgCqYEgsl7cRLLrLLabBjyXnCsAMAe8r4dwUezg/EWbZy6P9827Y6MdqrdSmahvd4avYhhyHvpPgKALPK+jS9ptAu1y93E0t/fhyjvLe3L9FxKWyGkLx95DyD6kfdtdNOFvDdiNLa2MdVhNe/tsdQ9wR4Z3wPoiMj7VroZrwgjx3a8RRvJvA/ySVlK0IDl4T+ejuS9jZMJ07UAYA9538po+td25HSgT20H8z6ax/eWWD2ZE1STzHvfJh3onQOgAyHvFUXuNr0Yz3uZKArmKeuGZUcZ39toSnAO0YHeOQA6EPLeBHmvTSPT4bhTjA6+ePCtm6CW6oufS6jfCR3onQOgAyHvTcRy3oujXXLYahSoMmwffEc4/ixCVB8AZJD34P/DBQD3I+9B3gOA+5H3IO8BwP3Ie5D3AOB+MZ33Xbt27YROnTpdf+05IADgYupHfacYzHsAAGINeQ8AgPvFYt53RufOnTt37tq1KwcEANzN91Efo3kfpj5Gt07crwcAbhfT1++JNxV5DwCuR95D6vvz5b9eXpd8fXvfoWv05b7yLehurvsFusE/d8G3FFvaRYi+bziYL0UWVLbxBcyO707cVEjrB2zlyNs7mEPnYPdMtw3byyQ+GqYdC+iezGG391wkj7Oge/ZeX/Ieorw3evfL/OYYtaPdSremYJNgFkoSPFmZTwHTYyXeqWAX8vVNOymziaCTMqtkPj3t7cuU/GEXrzU6XJY+qbVbhfrtLXPobL+jxAlk6VVz9rBr61j9TTR9x0ru17fE3tvAdO/2fjXIe4j+v5yAmpZ+peU/6yPygShg9VPA6m+m9kPW6KNTu4nVTw3/Xcgs1HbJ6DNLdyvBEmdCy5sSH5/iFWwj1xnJngj6by/Vwvb29q31psQneKS6JNM9wSoH8z7Iwx49eW9Ugby3jbwPFnlvumFI81673Nm8d6p7pkKe956EuLjW8DI9IwnFy2Q7DEKU92K+mn6HTdQlme7J9DygQasvk2kLRh3z31b7r39Tgueiu+tgnotu48EcZ6PnIoO8hzPz+Vryv1eKld8E0w+IgOWmv6UyrVl6LpZa011udHCMqlntgL3uyRAcYaMXTvY18qbEa1NL2BPTJVbrW/0V0FZ29u0tz5MQ5z8tEsw7yuq7V8zxwx4nzHtn92XamlGFYI6zvb6pyHs4c7+e+MPa9DdNu5Xgg8/3r1G0BE/Q+VAEScBy8R4lj5Xt7ikGr2aQhzrI18iToJ/2Rr2SeRNarS/fmlHjpi+Z4G0flPZnS8G8o6y+ewN2Ybo8mMNuVDOuffAHuS/552JUwfZx9m1r7y1B3sPO3+OZvtu0HyiSFUw/NWRac4Tgt9qopv8m2t9tmU10d2HvWGl3J7PQNu0zMnp2dnhT4uN0rtv7t2n1LSez1lL7Mo079fYWH229N167IxjMO8poleANH+TLJNjc0l4kD6N4X8G8JSwdZ93uye9LF3kPnby3+FGiw+pvtcxvgtVPjeCfhS7T52JprW5N8bOz+qnhv2GQz12ezFGy8BrpXYK29A7RXSKz1uhw2XhZFbOXLC6I01nTOv6HMJh3lOBAiRvXXSL5PjHdeyg42zf5t0HokPcwH98H/9FpukTmE0fwqxVtnwLya2U2cSrvZSpbyGC5vdjbKoDu8D48eR98fckPeqtvb6svkP8xDOYdZbTKaNvgXyZL771g3rSmrD4X05q235P2ng55D4fz3uizSbBQ5jchmN80Z4UiSGQ+xbQ1JT81bPQneFaPkrhO6PLelwQhynvTZNWtKZP3VrsXcAxtv6NCnffiCsG8ewVvAMnzA9ufQvJvA9MOy2xohLw3IfkL4OxZZJg5lfeCpx9k3lv9iBFvJcPBBO1weR+i4ybzGhlurvsnZU6MiQWbi5PA3stq9JLZCxJxDwMEHELb7yjdAyXe1sbLZKm+dnPJY2LajiN9k38baKtZeolNkfetTF8qo9de97W092JESvB5b/qUxR9YujUtHUPT30yrrG4r+IU0bSrg41K8C91OBn+sLFWwt21Qr5HB/XqK35G32XII6gs+kXVfMtsfPvK91T2Ctt9Ruqkj81Ep/zLZflkd/OwNsm9W3wbyHTDd0Ah538rGr5ztlyramP49nuRCAfn6HTTv7TWl/cS096xlskdMssPyXXK8fsBfkEewJ/bqB2wV7re33LcX2OteMNs6ftjD85sbZH3y3jbG98EKxd/j2a7v7KeGfMhZ2la+Y0Z9E7Qjv4tgPp1NWw7bcZPdV9DftxPZ+gFbWdo82EMnfbYUzDvK2acWTH3bb90w9C2gpu3fJksd8yHvWwl+o0wrOPViRAr/Hy46BoOr+BDjsEFF3rcKJu9Nl0Q58h4dhyfB0rR+zJP+D4bgfuR9K5nhu9Fyp6aPIoW8BwDXI+9b2R7fuwB5DwCuR963CibvO+KY3h95DwCuR9630p2uV8zyXjfgO1zqG+W94DzG6hOUrx/8yZPRK2WjKd0u2euheENxO1b3KO6nI29Opxox6qfRixj8C6FtM6T1TVtz8JWSOWim9a22jw6EvG8j/pXTvtfF7/4O9Lvh4N/jGX34yhwNow2NFlr6FAvdy+FI0oiPp8xCcZdM9yVM0pAcT8d/fUwblHxn2nt3WTp6kp0Xvytknou9nRr1P3S/RAgP8t6E7y1u9berA/1uOJX3go8G06MR5MGUyTNxC7bZbjnIPgvWit+rjkSpjUaMvr9dco+mfJto//wsmHemeHNLHbNaJ8jfMtNTEBd/pkEXeW9C8LuhuHc+38YnhaL5JDIaJRgJ5mB2uLw3+mjWVrNxTEzz3upb1Gow6Ar4vhzTp2C7k9rvlhG8PRx5d8lvLqjg/8sleD842DfyPtaQ9ybECedbZSnYoo0j43unPonsHUyZfWlPQYJ/1RwJe9N2rHbV3mth9eBYPp7t/3Le9CkL1orre1Pi/Yf3wb8z7b2T5TeJM/iQkXmfmPZN8LpoFzr7oiDakPcQ5b3Rx7fMJ0Uwn5LB1Hf2U0mcauJENGpNd7mzfRYsCUMH9HkSxDGs+B0fwVvO9IXwpiT4D++Df2cG1Lf0ipvuIk6TwYINrT6X4OsHrLX63BFVyHuI7s/Xfaz90XSJ5OeIfKaKVwn2FRGmH5TO9ll89HT3FZGDZrWTtvciWGJ0NGy/u2R+NUz3LrNWWyH430rT31PBWkQ/8h76eR/8J0WIPr5NW9PtiQwHexi8MPfZUlMd63iGOfPkG7TRlG+57hG2usTx544oR94jhHkv/+lvKTnC/KnkYKqFLR1t7MjBpynfSUur7PVQuyoujHkvf+iCP9oyB01cP8jnjihH3sOZvBdXCPKTwlJrYf5UsvSBHtKeSJLpRni6ajXvHWkt1Jln452vm8TOHgHJ+lH1mwXHkfdw5vq9jfrazSWHbkatCYZHwZ9wSPbNXiPh7LPktkFWCKaHgn7aeyHinMh7yQNo2r7k7nSbEj/94N9FRi0I2kcHQt7D5v35uk1ZrS9fwWhH2k/84D/1HNw2mHYi2GfHXy+rjYTiRZR/Z1p9dwXTSasHwWpTwf9m2W4K0Ya8h5Pfp2u7voMfJZHLe09CXOA3uwXTh7DlvW68CT73g+ybTCOOv4g2+iBZ38bR021BvMRe34wW2tOuKZM3O6IReY+oyHvF7t1Y8vsKpn0H+2apkRD1Wb7D9tqX34XVzR3ZaUCDIa1vqeUgXyCjDZ06YqF77ggP8h78f7gA4H7kPch7AHA/8h7kPQC4H3kP8h4A3C+m875r166d0KlTp+uvPQcEAFxM/ajvFIN5DwBArCHvAQBwv1jM+87o3Llz585du3blgACAu/k+6mM078PUx+jWifv1AMDtYvr6PfGmIu8BwPXI+3aMvmZS94skxd8u2YG+e5K8BwDXI++lGOW949/mHRHkPQC4HnnfShzYjO8BAB0aeR9IPtrJewBAR0HeBwoY1osn510wma+Q9wAQA8j7dtSclrxfzzXIewBwPfK+jeCCPXkPAOjQyHtFuT4tH1BNfL+e6c35HWhWn7wHANcj7x3TUdJdi7wHANcj79sEOVIn7wEAUYu8byMIbPIeANChkfdtyHvyHgDcirxvQ96T9wDgVuR9O8HcZk/eAwCiFnkP8h4A3I+8B3kPAO5H3oO8BwD3I+9B3gOA+8V03nft2rUTOnXqdP2154AAgIupH/WdYjDvAQCINeQ9AADuF0N5z6w1ACCWhTGjnWQ57wEAQIdD3gMA4H5B5X1SXJKgyHfCUuXQ1Y/Tq6a7ULy5/CamlePikrTFRt8AADHOft5bDV3F7/zAtCnx2UPw9XXJ5L0ggEOR95b6BgCAkfDlvX99G3ks2NyR+gFDZ//lRvWNllidEpCpT94DAIIRvvn86M97xSDFdU8Fgsx77cy8YKuAvunO7QMAIODY/XriTLUU/6YtOF5fcFHc2fG9OKdNzy0k+wYAQIBoyXvdKQEH6wtqisfupnkvuJDvCEHGk/cAAEk28148k6/N46gd38vEueSGoch78WV78h4AIClMf38fZN5bvd5v4/4AI4LENRp5y8zni4tpO5IVAABQBXV/vszI3ldZsCSa816XbiTbG3bLV9aeEAAAIClU43tLAR/Mtf/g6yvCYbduZfFjx/Ne2xNSHwBgSaj+Hk+3su5j7Y8B7YubCqa+DMF1+oAfQ5T34qsD8jsCAMSyaPx+PcFJgyP1LTFKd+0S8h4AELXCmvdONRXq+v4sXV+3uolkZebzAQBB4v/LMRENee+ryf16AAB7+P9wAQBwP8t5Lx7TR3/xfy7+I+ZQlEjtCwCAAIzvAQBwP/IeAAD3I+8BAHA/8h4AAPcj7wEAcD/yHgAA9yPvAQBwP/IeAAD3I+8BAHA/8h4AAPcj7wEAcD/yHgAA9yPvAQBwP/IeAAD3I+8BAHA/8h4AAPcj7wEAcD/yHgAA9yPvAQBwP/IeAAD3I+8BAHA/8h4AAPcj7wEAcD/yHgAA9yPvAQBwP/IeAAD3I+8BAHA/8h4AAPcj7wEAcD/yHgAA9yPvAQBwP/IeAAD3I+8BAHA/8h4AAPcj7wEAcD/yHgAA9yPvAQBwP/IeAAD3I+8BAHA/8h4AAPcj7wEAcD/yHgAA9yPvAQBwP/IeAAD3I+8BAHA/8h4AAPcj7wEAcD/yHgAA9yPvAQBwP/IeAAD3I+8BAHA/y3kfBwAAhMKY47Ls5H0YYKfHyQAAIABJREFUuwcAQAcTnUFJ3gMA4KToDEryHgAAJ0VnUJL3AAA4KTqDkrwHAMBJ0RmUMZT3SXCLSL+VAEAkOoMytvK+Czo+vhwCQJSLzqB0LO/Ff4AoePK6q6weLJn66pO01CyiEHkPIMq5PO/FFYLPe/F3GpD3sYO8BxDlyHv9yiE6P9Ai792BvAcQ5WIi79W1gtG5uL7MlxGS9zGOvAcQ5WIo77XVTENapr5kU0bIe3cg7wFEOffnvSCzjUb28vXFq0xnBRTy3i3IewBRzuV5Lx52Sw7fTe+/E1wv8P/RmxIfFxef4m1Xh7x3B/IeQJRzc97bu4nPRn2rJxD+yHt3IO8BRDk3532QZG7T0+5acv7fh7x3B/IeQJRzf94b/Ym86SbiJUa7Ju9jE3kPIMq5P+8FrF4FkLm/TzGe3tdF3rsDeQ8gypH3Fppy6v4+f+S9O5D3AKIcea+/XH4+X7597s93MfIeQJQj70VrZe7Xs92+irx3B/IeQJSL6byPBuS9O5D3AKJcdAYleY8OhrwHEOWiMyjJe3Qw5D2AKBedQUneo4Mh7wFEuegMytjKe/WpUTp6ifRbCQBEojMo1c/PmMh7AADCIDqD0oG8TwIAuFFo88e93Jz3XQAA7sK1M9tcnveh7SYAIDiXLSLvbYuVvA+YCNI+CKgmM30UzEST0YaSLWir2Zv7srpfAHAWeR82MZH3uulotEqXoAXJ5ZJ1BOcf8nuRXys+DvZOZQBAHnkfNuR91OW9L1wFGW96xiB5SiE4DvJPGQBsI+/DJnbzXn7YKoh2S5Pnpg0qwlCXyXvbdSTnD4h8AM4i78MmdvNeu0o3v0M0oW3Uvu281+2h0ULtY/IeQESQ92ETE3mvaAb0RjknKXRnBvJ5b3tHviPg34L4tMBoCQAEibwPm1jJeyPRnGGWxvfybcqM7/0rh2J6AwBU5H3YkPc2/x4vyJG9zObyeW/UmrbZJIPpDaPnaLRHAHCEbqiXlJSUlJSQ986Kxby3EV2Wgtxq40aby+e9fB/IewBRRTfss7KysrKydCOfvLeNvNdZKzlqD2Z8L7O543kvM9C3vMfsmUlJSUkzswX9AQAjRmFvFPnkvW2xlfe+TDXK5oiM48XVZE4FJBuXzHvdExHDcxryHkAQjEb2RqN88t62WMl73YAXLJQZuMvX1BXM5vbyXlBTfhMAcJBgGl838sl722Il7wEAUcgX5LqjeV/kk/fBI+8BABHjn/e6N+ipkU/eB4+8BwBEjH+ua8Neu4q8t428BwBEjFHGGyHvbSPvAQARQ96HDXkPAIgY8j5syHsAQMSQ92FD3gMAIoa8DxvyHgAQMeR92JD3AICIIe/DhrwHAEQMeR825D0AIGLI+7Ah7wEAEUPehw15DwCIGPI+bMh7AEDEkPdhQ94DACKGvA8b8h4AEDHhyfu4uCTtEm0R1HcB8h4AEDFO5b1ufvtiW5DfuqvI+7Ah7wEgJviC3P8/uQ/gv8p0fG81v8n7yCLvASAm+II8KytLN/JLSkqysrJClPfqcsFsv63nFKXIewBAxPjnvTby1bAPdd5rK7gs6VXkPQAgYrTR7ot87RJLeW90L562pvZH8j5syHsAiAm6o/mSkhLdsDfNe8H8vOkSxXi47w7kPQAgYnSv1vtor+jL5L1iNj9vGufkfdiQ9wAQE4xu0DO6fU8YBDbn58XT/q5B3gMAIkab6GrkG/15nrN5r814F6c+eQ8AiBjdUBcQfN+OYKEjf5Tf0ZH3AICIcSTvrf65nXgr8aqOi7wHAESMU+N7MebzFfIeABBBkc1731ru14sU8h4AYkJ48h4KeQ8AiKDg897of8ZzqkTksIQCeQ8AiBjG92FD3gMAIoa8Dxs35726CYVCoVDcVEKbP+7l2rwHAAA+0RmU5D0AAE6KzqAk7wEAcFJ0BiV5DwCAk6IzKMl7AACcFJ1BqZP3p/77uxQKhUKhUEJRyHsKhUKhUNxfyHsKhUKhUNxfyHsKhUKhUNxfyHsKhUKhUNxfojfvI9UzAABcIEpSlbwHACCEoiRVLed9EgAAEPLPzQ6c95HoJwAAHQN5DwCA+5H3AAC4H3kPAID7kfcAALgfeQ8AgPvFUN7HtSdTJ6Ca/FamO4L7xMXpvAl1F4o3l9/EtHJcXJK2yPdNd0NBP3V3p90vgIiIoby3xz+wdcObRIdKJu8FQRiKvLfUN8m19vppoz4AZ7k878Ujb5kheMjy3pNwfe8JnnYrvCnxustb18SnePWau76VZiPzdn0rhJsb9tdwhXnfpTZt657/5v6dFjShv7GmBwYH9Xr/DFb7MxrCmqamdonVKQGZ+uQ9AJfnfZDiQjWf702Jb40nNZDassqTcP2ntke+FQbZo64Spa2gXcWTIN5S2F9PQluPAhsO7GBA3z0Jcf5t6m/pTYn3b97XgDclxb9+W1syG/vWCqPcmxLfurbtkTGj6DWazQ4y77Uz84KtAvomOccuyHt7U/TkPRBZsZL30kncbhPTJTJb6fCkBI5U/ZKvXfa3jxm94PEkmGa9qF1vSoL54FXY37YOafob2IV2A3Rv++zX39K/lv+TaLe1QdwbbqwYTDe0065LAVsHElwUd3Z8Lw5a03MLyb6J14b0ugOA0ImJvBeMy42W665yLO/baxsXB2SiJt61eS+V9oJ2fTPq5mN8nf62j02/4bR5HwLXSezfk2A87W66ebuNzdNeb3bFYB/isbtMahpdyHeEIOOt5r24n+Kb9bhrD4i4mMh7RW58bzruF2wiJuya39hRO9Xe/mdNZqrT1ClmoW3WrtQVAZ3+Kv7z+4ZxbNB3vxXaWQy9aQzBswu87qG9xSDwMMYlpFy/tK/XK81shEHvbQ+CHbl+b0p82d50Rw7eVwgg4mIl731sjL9Dyz/urOa9JyEuLi4+PsU3OWCQ2aZ5b7hQ3F+/Xphuq5uYfnfdCTZvu61PL3JNRvfajdXzifgEvxkO3Y7J5L0pQeIajbxl5vNlxtAycW7pucj3E0AUcnne2xh/2x2mB24o+VTbjYoDIldzH5te3psMbaXabVtsbV68dasEj8QEgSAxze6cu75n3V3ITOa331jn6oZm53pH2lbe69KNzFBfF3d8Ul0w4c9MPhCFXJ73zjJKcd2Al0n9wOvWVq/fG43b28a06s9m7bZt3nYLv//2Rv1tf1ebOBOFI2S54bPeDITcpf92G0uN3eWv3yvCnNOtLH7seN5re2IvgIPMbCIfiKyYyHurQ3arlcW7Nlync8G73RBbm0O61+/bX0s3uM1d3K5vuTA6dfqrTUXDFsSRLjVK17khUDru/TcO6Ip+lre7P1/yWocO8d18il7MO5v34qsD8juSrM/4Hoha7s97q3ksPxVvr/1W7QOu7a/i2mJGJ2O0I2j/qXlhKAnbbW1JNMLW72/7uXDh3+OJRv8m+9btwvUNJWNYe1Nf6x5F9xEaTAhYIbg9PmBJlOe97j0HwTQIIMzI+2DzXrE+n6/9bjjN9eTAmfT2c+yaMb7eBoZ7Dby5XqdNC/31W2nYhF7fDZ+P/0lEuz3r3nGge9uhWlW4se4X7wXeAGHh+/WMWLq+bnUTycpBzucHVBZsS94D0cz9ea84N59vVF93K4tPGe4UDXnvq2l1al0c7UZ3JzClD0SnmMh7AABiHHkP2CT51/C2SyzsC0DYkPcAALgfeQ8AgPvFRN4b3UNneled7i142gdG9XU3l9+RfP2ArQQt6K4yWmjUJZkehrM+AMBUTOS9EdMMFi93JMaMTkQkG5fPb3v1JRuxcSTtna8AAOxxed7bHgcL1jqY9/Y6YFpH0HOZ+roHzX/b4J9I8E8cAGCJy/Pex8a4Vpya8kNw0z7YHt+rdYw2N0pZ/9i2/USCPHMi7wEgzGIx7yVzztnxvem+bKSvUU9MT24k6xt1ifE9AHQ4MZH3gnGw6VYBSwTT2nFyBHu0RJDBMs801PXlW9Ot7+yxAgC4P++tjmsDKmij2t743rRxS+cHussFJyLiRqIw7wVrAQA2uDnvdfNSnFsynMp722ROU4JvUHDaQd4DQIfj5rw3FfwAXbvE0kjdxsg+eKHYBXkPAFEu5vI+mCxx/PwgmPo2ThR0R+pG9cXtSFY26hJ5DwBhFlt5H2dw454kmQ2txnAoxve621rKb3HH5OsbtS9oQdxVAIA9MZT3/iliI1FkoshqsyEKNqfy3lJ9G/0xOocg7wHAcbGS95JDTKNtA9JIMFiXbNNe/SCb1fbc3nMJ9dNsX9+bEh8XF5/itdQEAKA99+e9ONJMx+tWt3VkGlxQX4bMk5Jp36leRclpEADEMvfnPQAAIO8BAHA/8h4AAPcj7wEAcD/yHgAA9yPvAQBwP/IeAAD3I+8BAHA/8h4AAPdzT94DAAAB/9zsqHkPAADkRUmqkvcAAIRQlKQqeQ8AQAhFSaqS9wAAhFCUpKp53lMoFAqFQnGqkPcUCoVCobi/WLq3n7ynUCgUCqVDFnEqk/cUCoVCobihkPcUCoVCobi/RFHeq4tCsbPQPQ0AAFyAvAcAwP3IewAA3C+G8j6uPZk6AdXktzLdEdwnLk7nTai7ULy5/CamlePikrRFvm+6Gwr6qbs77X4BREQM5b09/oGtG94kOlQyeS8IwlDkvaW+Sa61108b9QE4y+V5Lx55ywzBQ5b3noTre0/wtFvhTYnXXd66Jj7Fq9fc9a00G5m361sh3Nywv4YrpPuueBIMV/l3T79O6/4FbeutN2tVtK0eoyGsaWpql1idEpCpT94DcHneBykuVPP53pT41nBUc6ctKT0J139qe+RbYZA96ipR2graVTwJ4i2F/fUktPUosOHADgoD2ziu/ZsPqKZ2RpDG3pT41tVtj65v5/eEdFsw2NaAUfQazWYHmffamXnBVgF9k5xjF+S9vSl68h6IrFjJe+kkbreJ6RKZrXR4UvzSIzB82mW/Nt8Cg8eTYJr1ona9KQnmg1dhf9s6ZDpM11vrSUhIMcxTb0pKuzMT/3AXzhjodMjvGLQ7M2l/bEy31SO4KO7s+F4ctKbnFpJ9E68N6XUHAKETE3kvGJcbLddd5Vjet9eWPgGZqIlIbWZKpb2gXd9kvPkYX6e/7TPXmxIvNdRu31aCR2r8HNiERNrrzZC0TXH41ngSDOJef1sN8dhdJjWNLuQ7QpDxVvNe3E/xzXrctQdEXEzkvSI3vjcd9ws2ERN2zWjcqfOzJhjVEW+KWWibtSt1RUCnv4r//H7bzLvhZtq5iQSPdpVhlPsNudVJhpTrF+H9ardleeAe/X/2XRxou1Ih7K3RKYntQbAj1+9NiS/bm+7IwfsKAURcrOS9j43xd2j5j4qt5r2aWvEpvskBg8w2zXvDheL++vXCdFu9uQmzS+iaDl7fh3pKEJ/gN0mhbUCc2a037Aluf5TJe1OCxDUaecvM58uMoWXi3NJzke8ngCjk8ry3Mf62O0wP3FCy5+1GxQGR63+l3LcgMO8Db+nTi12zdtsWmwa+ZhSvDpDNJwi0Ceq7NC8Vpu0G4lIzAnpHy+/UKj7Fa3y/n3DboOlGZqivizs+qS6Y8GcmH4hCLs97ZxmluG7Ay6R+4GSy1ev3RuP2tj+RU382a7dtc7/r237bG/W3/V1t4kwM2Kn/LnT3Fdg14YEwujnA4Bq8/5mNwcmP/PV7RZhzupXFjx3Pe21P7AVwkJlN5AORFRN5b3XIbrWyeNeG63QueLcbYmtDTPf6veGoV75d33Lh8F6nv9pUNGxBMIg3G9/rdEzn7MHsHnvRbZH6f+Sot61V4rv5FL2YdzbvxVcH5HckWZ/xPRC13J/3VvNYfireXvut2kdj21/FtcWMTsZoR9D+o1NhKAnbbW1JlLn6/W0/kS78ezzB6F+Y9wH98l3092tP5jynXZ12Fz6MLmMYbGuR4Pb4gCVRnve69xwE0yCAMCPvg817xfp8vv8X2rUKvBitnd32nwDXjPHNpsMN2vXviMmf0hn212+lYROGfW9rQv9qvM6sv17vNfcwmn9PkV/L7b/sSPI7jmRZur5udRPJykHO5wdUFmxL3gPRzP15rzg3n29UX3eroJ4P3CIa8t5X0+rUujjaje5OYEofiE4xkfcAAMQ48h6wSfKv4W2XWNgXgLAh7wEAcD/yHgAA93N/3uveRqd9YFRfd3NJpvXD0DejtY4/lyDrAwBCyuV5L0hBcQUjuvXtZWoY+ua/JGCtI70VnHOQ9wAQVcj7sGZqOPtmqaumu3PqbAYAEBGxm/eOTNFbzdRo7ht5DwAuFrt5L64g2VqI8j4ifSPvAcDFYi7vA4bO2jGxDHH7grXh7Ju4M2HIe21/AACR4vK8V6zfA2+VpUwNc98U49wNQ95L9xEAEHLuz3tdkcpUydaC2dw28h4AXCxG895HMKluOltuo/Ew903QAcb3ABBTYi7vHc9gB/cVivOD4Cvbm70g7wEgqpD3+nVkxtCmo+1Q5L3V8X3w9Y36JmhB8rkAAMImtvJeJoocDCpLTYWib4L6jjQlOIcg7wEgqsRK3mvTyCiQwp/3oetbqPNeur43JT4uLj7Fa6kJAIBz3J/34vh0ZBpcsGvTCqHuW/DPQvK5BFkfABBS7s97AABA3gMA4H7kPQAA7kfeAwDgfuQ9AADuR94DAOB+5D0AAO5H3gMA4H7uyXsAACAQivxVwpz3AAAgIsh7AADcj7wHAMD9yHsAANyPvAcAwP06TN5H8l5JAAA6AkGMdqS8j3QXAACIXuQ9AADuR94DAOB+5D0AAO5H3gMA4H7kPQAA7kfeAwDgfjGU93HtydQJqCa/lemO4D5xcTpvQt2F4s3lNzGtHBeXpC3yfdPdUNBP3d1p9wsgImIo7+3xD2zd8CbRoZLJe0EQhiLvLfVNcq29ftqoD8BZLs978chbZggesrz3JFzfe4Kn3QpvSrzu8tY18Sleveaub6XZyLxd3wrh5ob9NVwh3XfFk2C4qn0Lhrs2OyxGFXQa1WnfvHOK0RDWNDW1S6xOCcjUJ+8BuDzvgxQXqvl8b0p8a8qogdQWOZ6E6z+1PfKtMMgedZUobQXtKp4E8ZbC/noS2noU2HBgB41y05MgEamBx0lRFG9Kgngjb0q8f9+0u9BptP1KdZO2R8aMotdoNjvIvNfOzAu2Cuib5By7IO/tTdGT90BkxUreSydxu01Ml8hspcOT4pce3pR4X+a0H25qhr16weNJMM16UbumoWna37YOCYfpRqHpSUhIMc1Tb0pCSorl8xSvt32vNRMp2kb9m/frk3gaQAmIXqNV4uUyeS8OWtNzC8m+ideG9LoDgNCJibwXjMuNluuucizv22sbFwdkoiYitZkplfaCdn0z4uZjfJ3+tp+l9xtOm/fB11aCx3T8rJ6TtJ8+8E3US8y1qzsKqKjXaLv6mtkVg0MkHrvLpKbRhXxHCDLeat6L+ym+WY+79oCIi4m8V+TG96bjfsEmYsKu+Y0dtVPt7X/WBKM6TZ1iFtpm7UpdEdDpr+I/Ja5JVO1m2rmJBI92VcCl/uszELqRq+7ev129MyBPgt7Y3rBRnd4anZLYHgQ7cv3elPiyvemOHLyvEEDExUre+9gYf4eW/6jYat6rV77jU3yTA3KDVf2UEwxhjfrr1wvTbfXmJnSvCgRudv16g2H/xNMDbff0aU8hgs97U4LENRp5y8zny4yhZeLc0nOR7yeAKOTyvLcx/rY7TA/cULLn7UbFAenjf6XctyAw7wNv6dNLL7N22xabBr7OvHh8gkdigkCboCkeg1X+u2u7c0BwPmJ+f3+7/kk0qnekbeW9Lt3IDPV1cccn1QUT/szkA1HI5XnvLKMU1w14mdRvu+3d97Ol6/dG43a/v1OLS/CYt9u2edst/P7bG/W3fdKKMzFgp/670N3X9W00dHYhvnOg/bGRbFT++r0izDndyuLHjue9tif2AjjIzCbygciKibzXSRbhKNxqZfGuDdfpXPBuN8TWxrLu9fv219Il/szcqJo2zU37q01FwxYEg3i5yXLh+F7qz/cN/pRR4v58yWsdOsR38yl6Me9s3ouvDsjvSLI+43sgark/763msbh+8O23ah+N7S4o+906r/P9MtozAKO7/QI3NW63tSVRaOr3t/2tdcJpdcHoP8i8F51lmFUSHLO2cyTbF+8ViT+B6yh5r3vPQTANAggz8j7YvFesz+frzCgH3p4eFxeYQ/4T4Joxvt4GhnvV+aM2vRltyf76rTRswrDvbU0Y35/v30i77/nRf9ptNzG067bxlf+ALzuS/I4jWZaur1vdRLJykPP5AZUF25L3QDRzf94rzs3nG9XX3Sqo5wO3iIa899W0OrUujnajuxOY0geiU0zkPQAAMY68B2yS/Gt42yUW9gUgbMh7AADcj7wHAMD9YiLvtXfP+ZbEab5cT7Ct/F14Ru0H1Akg7onkHsV1tDsK0b6CqQ8AcBx5bz/vtYGtbdZS1MmcW9jObPETsdSa7lrB6Qt5DwARR947ML6Xb1/MdF+WMluyh6ZrrbYmUx8AEGbkvfmQ3WjK3Ub7YuQ9ACBE3J/3atgYpWP0jO9tzLHLz5mT9wAQ42Ir77Uj9WjIe92ZA2fzXlw5DHkvmB0BAIRBbOV9wELBct0llvLe9BKA7WsElvqmu1Mb+3K2PgAgzFye90aJKBh/x7Vn1FrAQsnzCXmhyPtg9i7fE6utAQDCgLy3eT+duKng815m77bn8y21HIr6AIAwc3Pey1xWDzLvgzmfiJMguTuZJ+JI3stfEbDUNwBAqJH3FqLLtLK98wn55A4y7+VPLIzqG+1L0IJM3wAAoebmvBewl/emNUOd94rdEba4gtU8ljw/sN0+AMBx5L39vLfXvqByMB2IeN47WB8A4DjyXnYq22je20b7pnuxujvxjkz3KL8X+X0FUx8A4LgYzXsAAGIKeQ8AgPuR9wAAuB95DwCA+5H3AAC4H3kPAID7kfcAALgfeQ8AgPu5J+8BAICAIEY7TN4DAADbyHsAANyPvAcAwP3IewAA3I+8BwDA/SznfSTvOwQAoCMIY47LspP3YeweAAAdTHQGJXkPAICTojMoyXsAAJwUnUFJ3gMA4KToDEryHgAAJ0VnUJL3AAA4KTqDMiR5H9eeTJ2AavJbme4I7hMXp/Mm1F0o3lx+E9PKcXFJ2iLfN90NBf3U3Z12vwAiIoby3h7/wNYNbxIdKpm8FwRhKPLeUt8k19rrp436AJzl8rwXj7xlhuAhy3tPwvW9J3jarfCmxOsub10Tn+LVa+76VpqNzNv1rRBubthfwxXmfZfatK17/pv7d1rcRNtO/BrQb9RoU1GdVkZDWNPU1C6xOiUgU5+8B+DyvA9SXKjm870p8a3xpAZPW1Z5Eq7/1PbIt8Ige9RVorQVtKt4EsRbCvvrSWjrUWDDgR0M6LsnIc6/Tf0tvSnx/s37GvCmpPjXb2tL20CC5oAZNaqp1bqq7dH/397Z+8ZRhHH4/gCkgEB8tDQ0/AMQClcUKSORIkWkFIgGgSVSIKXABQUUkUACWzhCzgdCIcSJwYZYVriEpAgkGMeSSZQPCQUkSEISIYRTpFkKh7vdnXnffWdv7m4z9zz6FfbtzOycm2fnnbmzjKReqZrdo+/dyrzSqzQ3Y41d8X29Ej2+Bxguo+J7s4kLXSpfsfTy0N5bXqnmzFdwf1EzPvG0xytdr43r82HYfLsTcuZbnkJhgX6t6H5/z3yr/Jso9FZ0732YkQYt9SyVA5S/sbIpHnd9r4u28tnCODf9al/3HQCgf4yE75V1ufS691I03xfprotLTnT07vreZHtl3E6xu3qN75lvsUqfWzZXz6F8zXD/9rjQX9R9p2ovz0sa1FNdEaaor90t1pQ28qOgOD7U9/o89cN6nNoDGDoj4fvMtr6vXPcrXXTUqeXWjm6pvfi748yNcvTeKmlXjWvaEfDMN8vX90UdC3PPXXCrGL4yhvLuyvsexaYbc/RvhIjbAJud4wK+2ddeBEfZv69E37avvFHEc4UAMHRGxfcdaqy/+0ted6G+b4+3Wq3Nm/d2igOCsyt9L76ozzc3i8q+XmPmTt0p3bsn7nzKVZ4EtNvrg1p9X4liXGnlbannW9bQFp0HvRf7PAGggSTu+xrr77rL9HJH41strIpLynXOsfl8ry9tbeN2X640p7OK36jFVxcIFGOK6+/Snb23sOk+E84ISPP2/aVr+d6LV5n93hePXlRXCv5U8gEaSOK+j4tkca/gLdYv71uH7t9L6/bcR9Ba4+3qcbvdu0f48/2l+RYlqjtRXSHbls++CoRt6/9BS+FN+x4Y7Pv3meo5b2P95+i+d2dST8A9OhvlAwyXkfB96JI9tLF+a/GaZ8O7sMR2JegtShf30oVj7vq4nddVdXrm61pRHEFXummV7jG2XffS+QLplGGhHGDc6/Cgn+bLfJqP63t9d8B+I2N71vcAjSV934f62F6Krzf+A4qC634qrqsZj2PcFXS+NK9KSR33wUgVXz3jmW/xaJ36eTxt9V9xb+8U/u9o1LD0QKEf2fN+bCII5Xh86ZWG+9575qCXAQFgwOD7Xn2fhdfz3e+GK1fbnUp6scYuHDzT1ecZNz+Rio/SifPNXRSH8M1dfD/5h4jCnb277N5jh/q2hDxo+QBEwPfrSQTtr4d2MTbusZ5faqz0xfcATSZ932fx6vlSe28v2zuFxGmC7zstQ0vrutql0wmU9AGayUj4HgAAYMRppijxPTwEGD8NXzujcC8AGBjNFCW+BwAAiEkzRYnvAQAAYtJMUeJ7AACAmDRTlIM7n9+q+g/3+Vfcq8odLV28M1H62t+Ifjtptkb63R4AAKKTvu+DZBPke8W7Ft9Ll4zPCvYB3atBTznGGynPH/geAGDo4PuKxpXe8uq5ab4PfV+hvq/xfAAAAIME35cbh9bM++F75Xb65O2XGuD77pcIAwBAv0nf91mf9+/0+7RhAAAEMElEQVQbsr7vxdD4HgAgeUbC93aG6/vSI4j7LGLBcrugpxzjzPX2vrnhewCAwYHvC0T0faWAM0fhyoBRkKbE+h4AIHkS932NNbF+yXsL92ovzu6f72vMwXjV3j7/P+sK1Pv38gAAYCNx37v0IlHJc50ng7hrdO/tjE8tltH0G4VOLPzWrO8BAAYHvg9A8VwU3/e4oK8lXf8lqbH0bIHvAQAaDr4PaKCU9yvFH2VumbrEr93R21dpZvR9pwu+BwAYOvg+uIHb0hV/Dd+ragyeW1Df0GGNzwdV4+N7AIDBge+DGwTdxb5kl36NNbd++z5iewAAiA6+97epVzN371K5XlfUbi+zG6fX45vKj9PX9gAAEJ2R8z0AAMAI0kxR4nsAAICYNFOU+B4AACAmzRQlvgcAAIhJM0WJ7wEAAGLSTFHiewAAgJg0U5T4HgAAICbNFCW+BwAAiEkzRVnH9wAAAKAwQI9bCfY9AAAAPHTgewAAgPTB9wAAAOmD7wEAANIH3wMAAKQPvgcAAEgffA8AAJA++B4AACB98D0AAED64HsAAID0EX1PCCGEkMSC7wkhhJD0g+8JIYQklaH8m5zGQj2fEEJImpmYmBj6HJoTfE8IISTNSL5fXlmdnVuYnJ6ZnJ6ZnVtYXlkd+lQHEHxPCCEkzXh9v7h8fc/Ugf3HTiwuXz9z6cbCqfPTB48sLl9Xxmm1WqVfN6h8Zeh/gXzwPSGEkDTj+n55ZfX9j/f//vf9a3ezTVtnN22dvXonu3zr/r5DX0mrfFfkpZ+VV6SOQwm+J4QQkmZc38/OLXxwqL16I1v9M9u0dfax7d9cvJVdup3Nn7k4O7cgjdO775sge3xPCCEkzbi+n5yemV68sGH6x187/eSulaffufLMu7+eOHdlcnpGGifU92vFqkATZJ//U+B7QgghScXr+31LK3nTPzVx9YldKyfPXY7re+WVAWdD9vieEEJIsvHW8w/On/rjn+zmv9mG6W+tZ3+tZydO//Ll0a+lcWr7vhfZt4rUG8SV/Rq+J4QQkli85/U+mp65dnP99nr26KvfP7Jt/u697Lc79w58dvT40nfSOPV8763tByWi7PNmx/eEEEKSivR5vE8+3X/y7LkzPy7/cP7nsz9dOPj5kd07t7SXvpXGqbd/L/0QlFiyp55PCCEk2Vi+b+fIsfl9770xueP53Tu3tJeOe9vXPp+/1rPv68WVPb4nhBCSbOzfp3t4/IUPtz/39g6/8mt8347bfmDvWpf9Gr4nhBCSWOy+n5qaOjz+0p5tz76185WhT7uXSLJn/54QQkiyCfp/OVNTU1+8+eLr214e+rRrR5E99XxCCCHJZqT+P54ue3xPCCEk2YyO7+2yX8P3hBBCEks2Stj/LPieEEIIST/4nhBCCEk/Xd9PAAAAQLqMjY21xgAAACB1/gOXNl6lzNENLwAAAABJRU5ErkJggg==)
즉 HTML을 JS를 이용하여 동적으로 생성하는 것이라 이상과 같이 복잡한 것이다.
개인적이 발전을 위해서는 이상의 두 코드(JS/HTML)을 비교해서 익혀두면 좋을 것이다.
이러한 복잡한 코드를 서버에서 HTML로 처리해서 반환 받으면 쉽게 처리 할 수 있다.
먼저, 다음과 같이 board7ReplySaveAjax4Reply 컨트롤을 만든다.
@RequestMapping(value = "/board7ReplySaveAjax4Reply")
public String board7ReplySaveAjax4Reply(BoardReplyVO boardReplyInfo, ModelMap modelMap) {
boardSvc.insertBoardReply(boardReplyInfo);
modelMap.addAttribute("replyInfo", boardReplyInfo);
return "board7/BoardReadAjax4Reply";
}
기존 코드와 다른 점은 modelMap으로 반환 값을 주고 JSP 파일을 지정한다는 것이다.
기존에는 저장 후
return "redirect:/board7Read?brdno=" + boardReplyInfo.getBrdno();
- Ajax로 키 값만 전송해서 클라이언트에서 해당 글만 생성
response.getWriter().print( mapper.writeValueAsString(boardReplyInfo.getReno()));
했는데,
이번 예제는 Ajax를 기존 MVC 예제처럼 댓글에 대한 정보를
JSP(BoardReadAjax4Reply.jsp)로 넘겨서 처리한다.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<div id="replyItem<c:out value="${replyInfo.reno}"/>"
style="border: 1px solid gray; width: 600px; padding: 5px; margin-top: 5px; margin-left: <c:out value="${20*replyInfo.redepth}"/>px; display: inline-block">
<c:out value="${replyInfo.rewriter}"/> <c:out value="${replyInfo.redate}"/>
<a href="#" onclick="fn_replyDelete('<c:out value="${replyInfo.reno}"/>')">삭제</a>
<a href="#" onclick="fn_replyUpdate('<c:out value="${replyInfo.reno}"/>')">수정</a>
<a href="#" onclick="fn_replyReply('<c:out value="${replyInfo.reno}"/>')">댓글</a>
<br/>
<div id="reply<c:out value="${replyInfo.reno}"/>"><c:out value="${replyInfo.rememo}"/></div>
</div><br/>
BoardReadAjax4Reply.jsp
BoardReadAjax4Reply.jsp 파일의 내용은 앞서 댓글 리스트에서 사용된 HTML 코드를 그대로 사용한 것이다.
댓글 리스트에서는 forEach문을 사용하여 List를 처리했고
여기서는 하나의 댓글이므로 replyInfo(BoardReplyVO)로 하나의 클래스가 사용되었다.
function fn_replyReplySave(){
if ( $.trim($("#rewriter3").val()) == "") {
alert("작성자를 입력해주세요.");
$("#rewriter3").focus();
return;
}
if ($.trim($("#rememo3").val()) == "") {
alert("글 내용을 입력해주세요.");
$("#rememo3").focus();
return;
}
var formData = $("#form3").serialize();
$.ajax({
url: "board7ReplySaveAjax4Reply",
type:"post",
data : formData,
success: function(result){
if (result!=="") {
var parent = $("#reparent3").val();
$("#replyItem"+parent).after(result);
$("#replyDialog").hide();
alert("저장되었습니다.");
} else{
alert("서버에 오류가 있어서 저장되지 않았습니다.");
}
}
})
}
서버에서 작성된 HTML이 result 변수에 담겨서 success의 콜백 함수를 호출한다.
클라이언트에서는 부모 댓글을 찾아서($("#replyItem"+parent)) 부모댓글 다음(after)에
result 값을 넣어주면 자동으로(? – JS/JQuery의 장점) 신규 댓글이 생성되어 보여지게 된다.
부모 댓글을 찾기 위해 댓글 항목을 출력할 때,
하나의 댓글을 나타내는 DIV 에 "replyitem"와 댓글 번호를 이용한 고유 이름(ID)을 부여 했다.
서버로 데이터를 전송하기 위해 JSON 데이터를 생성할 때도 하나씩 키와 값을 지정하지 않고
JQuery에서 제공하는 serialize를 이용했다.
serialize는 Form ID만 지정해주면 자동으로 JSON data가 생성된다.
정리하면
JQuery Ajax를 사용할 때
댓글 삭제나 수정처럼 JSON으로 데이터를 전송하고 받아서 처리하기도 하고
댓글 저장(들)처럼 HTML로 받아서 처리할 때가 있다.
잘 선택해서 사용하면 빠르고 안정적인 사이트를 구축할 수 있을 것이다.