2013. 12. 2. 22:15

집에서 턱걸이하는 기구인 반석스포츠의 치닝디핑 !

기본적으로 턱걸이 + 평행봉을 할 수 있기 때문에 홈트레이닝을 하기에 적합한거 같기에 주문을 하게 되었습니다.



저는 기본 모델인 비스펙 치닝디핑 선택 1번을 구매하였습니다. 배송비 포함해서 64,000원에 구매 




우선 크기가 크기 때문에 집이 아닌 다른 곳에서 받아서 가신다면 절대 반대입니다. 무게가 18kg 나 됩니다.

헬스 하시는분들 18kg 를 드는건 쉬울지 몰라도 이동하려고 하면 허리 다 나갑니다. 그러니 집에서 받으시거나 

회사에서 받으시면 차를 이용하세요.


집에와서 설치를 했습니다. 친구의 도움으로 빠르게 설치 할 수 있었습니다.  

혼자했다면 30분 걸렸을꺼에요...(설치는 쉬운데 볼트를 쪼이고 하는 작업이 생각보다 힘이 들어가네요)


설치 완료 



집에 작아서 걱정했는데 이렇게 그냥 빈공간에 두시면 된답니다.



턱걸이 시작 한지 2주 됐을 때 찍은 사진입니다. 창피해서 안올리려고 했는데 ... 자세한 후기를 위해 이렇게 올렸어요.

현재는 턱걸이 5개 할 수 있고, 근력밴드 쓰면 15개 까지 할 수 있습니다.


처음에는 턱걸이를 최대 2개 밖에 못해서, 근력밴드가 좋다고해서  구매 하였습니다.

근력밴드 후기 보기 클릭클릭


아까운 헬스장 다니시는 것 보다 집에서 틈틈히 턱걸이 하시는게 훨씬 좋은거 같네요.

반응이 좋으면 후기 계속 올리겠습니다 ㅎㅎㅎ





'2019년 이전 정리 > 홈트레이닝' 카테고리의 다른 글

턱걸이 근력 밴드 (풀업밴드) 후기  (16) 2013.12.02
Posted by hoonihoon
2013. 12. 2. 15:10
로그인 성공시 메인페이지로 이동 하는 방법

로그인 성공시 원하는 URL 로 이동 할 수 있습니다. 


   $.ajax({

url:"xxxxxxxxxxxxxxxxxxx"

type:'POST',

dataType:'json',

data:JSON.stringify(sendObject),

contentType: 'text/html;charset=UTF-8',

mimeType: 'application/json',

success:function(data) {

if(data.MESSAGE) {

alert("로그인성공");

window.location.href = "main.html";

} else {

alert("로그인실패");

}

},

error:function(data,status,er) {

alert("error: "+data+" status: "+status+" er:"+er);

}

});  

Posted by hoonihoon
2013. 12. 2. 13:54

세션의 유효시간은 디폴트로 30분으로 설정 되어있다.

C:\Tomcat\conf\web.xm   파일을 열어서 수정이 가능 하다

<session-config>

     <session-timeout>30</session-timeout>

 </session-config>


코드에서 설정 하는 법 

session.setMaxInactiveInterval(30) : 30초후 세션 삭제.(30초 후, refresh하면 ID 변경)

session.invalidate() : 세션 바로 삭제.

Posted by hoonihoon
2013. 12. 2. 13:41

HTTP 개념

1. HTTP 는 비연결 구조로 사용자의 연결을 계속 유지 하지 않는 방식

2. 사용자의 요청에 대한 응답을 한 후 연결을 해제


아래글은 쿠키와 세션을 이해하기 쉽게 그림으로 설명 해 놓은 글입니다. 


로그인 정보나 장바구니 정보 같은 클라이언트 기반 정보들은 어떻게 저장할까?

다음 그림을 보자.

HTTP는 연결 보장을 하지 않으므로 또 다시 요청이 들어 온다면 서버는 해당 브라우저의 세션정보를 찾아줘야 할 것이다.

그런데 서버입장에서 생각해보면 서버에 요청해놓은 브라우저들이 엄청 많기에 세션정보를 어떻게 줄까?


그래서 자신의 세션 정보를 찾기 위해 자신의 세션을 증명하는 ID 가 필요하다.

보통의 사이트에서는 ID를 쿠키로 가지고 있게 된다. 

쿠키란 브라우저 상에서 저장되는 객체이다.

더쉽게 말하면 쿠키는 사용자 컴퓨터의 하드디스크에 저장되는 작은 텍스트 파일이며 세션은 서버의 메모리상에 존재하는 객체이다.

사용자 컴퓨터에서 세션정보처럼 많은 정보를 저장하기 힘든 관계로 많은 정보는 세션에 저장하고 그 세션 아이디만 web browser(사용자pc) 에 쿠키 형태로 저장을 해두는 것이다.


이런식으로 하면 세션아이디로 로그인 정보를 꺼내 줄 수 있다.

그럼 한번 이 세션아이디로 정말 로그인이 가능한지 테스트 해볼까?



일단 쿠키를 수정하기 위해 크롬 ad-on "Edit This Cookie" 를 설치한다.



원하는 사이트에 로그인 한 후 Edit This Cookie 를 실행해 보면



앵간하면 SESSION ID 라고 써있는 쿠키를 발견할 수 있을 것이다.


SESSION ID 라고 써있는 쿠키를 발견했다면 그 값을 잠시 메모장에 저장해 둔다.


그러고선 SESSION ID 를 지워보자



브라우저를 리플래쉬하면??




당연히 세션ID를 잃어버렸으니까 서버에서 자기 세션을 찾지 못하므로 서버는 이놈이 로그인 안된줄 알고 로그인 하라는 메시지를 보낼 것이다.


그렇다면 다시 아까 메모장에 저장해둔 세션 아이디를 입력하고 리프래쉬 해보자!


어떻게 되는가?




멀쩡하게 로그인 한것과 같은 화면이 되버린다.


아직 서버 안에 세션객체가 죽지 않았기 때문에


알맞는 세션 아이디만 있으면 다시 그 세션(로그인 정보와 장바구니 정보)를 물려줄 것 이다.



이쯤되면 아~ 로그아웃을 꼭 누르고 나와야 겠구나 할것이다.


왠만한 사이트의 로그아웃 기능은 쿠키의 세션아이디를 지워버리는 역할을 한다.


만약 피씨방 같은곳에서 로그아웃을 하지 않고 브라우저 창만 닫고 나온다면?


 


피씨에 저장된 쿠키의 세션 아이디값을 읽어다가 


브라우저에 쿠키를 설정하고 해당 사이트에 들어가면 그대로 로그인이 되버리므로 조심 조심


공공장소에서는 항상 로그아웃버튼을 누르고 나오시길!



[추가정리]
1. 쿠키
- 서버에 접속시 접속한 클라이언트 정보를 클라이언트에 저장한다.
-이후에 서버로 전송되는 요청에는 쿠키가 가지고 있는 정보가 같이 포함되어서 전송
-크기는 4096 Byte 이하
-클라이언트에 총 300개 까지 쿠키를 저장할 수 있다.
-하나의 도메인 당 20개의 값만 가질수 있다.
-쿠키는 이름,값,유효기간,도메인,경로 등으로 구성

사용예)
방문했던 사이트에 다시 방문 하였을 때 아이디와 비밀번호 자동 입력
팝업에서 오늘 이창을 다시 보지 않음체크

2. 세션
-웹서버 쪽 웹 컨테이너에 상태를 유지하기 위한 정보를 저장
-저장 데이터에 제한이 없음
-웹서버는 각각의 웹브라우저로부터 발생한 요청에 대하여 특정한 식별자를 우여하여 같은 브라우저인지 구별
-세션쿠키라고도 한다.
-브라우저를 닫거나, 서버에서 이 이쿠키를 삭제 했을때만 삭제가 되므로 비교적 지속성이 쿠키보다 안전하다
- 각각의 클라이언트마다 고유의 ID를 부여
-세션 객체마다 저장해 둔 데이터를 이용하여 서로 다른 클라이언트의 요구에 맞게 서비스제공

차이점은 : 
저장되는 곳이 다르다는 것.
= (쿠키는 클라이언트, 세션은 서버)
저장형태 
=(쿠키 텍스트형식, 세션은 Object형으로 메모리에 저장)
만료기간도 다르다는 것
= (쿠키는 저장시 설정하는데 설정하지 않으면 브라우저 종료시 소멸, 세션은 정확한 시점을 알 수 없음)
자원
=(쿠키는 클라이언트자원사용, 세션은 서버의 자원 사용)
용량
=(쿠키는 한 도메인에 20개, 쿠키당 4KB, 총 300개, 세션은 서버가 허용하는 한 용량에 제한 없음)

출저: 

 http://jhoonslife.tistory.com/354

http://marcof.tistory.com/16

http://bllizz.tistory.com/15

Posted by hoonihoon
2013. 12. 2. 12:51

어디서?

미래창조과학부에서 2013년말까지 010번호로 변경 해야 한다고 발표.

왜?

미래창조과학부에서는 010통합정책 목표를 다음과 같이 설정했다.


기대효과?


010 가입자끼리는 010을 누르지 않아도 전화가 걸린다는 사실을 알고 계신가요?

010 가입자끼리 전화를 걸때 아직도 010 식별번호를 누르는 사람이 많아요. 

010 번호를 사용하는 사람끼리는 통신사에 관계없이 전화번호만 누르면 전화가 되요^^













Posted by hoonihoon
2013. 11. 29. 16:29

[a.html] => 이동 전 페이지

<HTML>
<HEAD>
<TITLE>Get 방식의 주소 파라미터를 받아서 처리</TITLE>
<script type="text/javascript">
var move = function(number) {
location.href = "b.html?tab=" + number;
};

</script>
</HEAD>

<BODY>
<input type="button" value="1번 탭으로 이동" onClick="move(1)" />
<br />
<input type="button" value="2번 탭으로 이동" onClick="move(2)" />
</BODY>
</HTML>



[b.html] => a.html에서 이동할 페이지

<HTML>
<HEAD>
<TITLE>Get 방식의 주소 파라미터를 받아서 처리</TITLE>

<script type="text/javascript" src="jquery-1.6.4.js"></script>

<script type="text/javascript">
var displayTab = function(number) {
$('div > div').css('display', 'none');
$('#tab_' + number).css('display', 'block');
};

$(document).ready(function() {
var address = unescape(location.href);
var param = "";
if(address.indexOf("tab", 0) != -1) {
param = address.substring(address.indexOf("tab", 0) + 4);
} else {
param = "1";
}
displayTab(param);
});

</script>

<style type="text/css">
div#tab_1 {display:none; position:absolute; top:50px; left:50px; width:100px; height:100px; background:red;}
div#tab_2 {display:none; position:absolute; top:150px; left:50px; width:200px; height:200px; background:blue;}
</style>

</HEAD>

<BODY>
<div id="tab_menu">
<input type="button" value="1번 탭 보이기" onClick="displayTab(1)" />
<input type="button" value="2번 탭 보이기" onClick="displayTab(2)" />
</div>
<div id="tab">
<div id="tab_1">
</div>

<div id="tab_2">
</div>
</div>
</BODY>
</HTML>


[실행화면]

a.html


1번 버튼으로 이동


2번 버튼으로 이동



잡다한 내용은 다 빼고.. 여기서 중요한 것은 unescape(location.href) 이 부분이다
저 구문을 출력해 보면 아래와 같이 나온다


현재 주소창에 띄워져 있는 문자들을 그대로 가져온다

그런데 여기서 필요한것은 tab = 2 라는 부분이므로 

var address = unescape(location.href);
var param = "";
if(address.indexOf("tab", 0) != -1) {
        param = address.substring(address.indexOf("tab", 0) + 4);
} else {
        param = "1";
}


이런식으로 "2" 를 가져올수 있다

그냥 써줘도 되는데 굳이 조건식을 사용한 것은.. 
a.html을 거쳐서 b.html로 갈수도 있지만 바로 b.html을 실행했을때는 1번 페이지를 보여주려고 했기 때문이다


출저 : http://ggoreb.tistory.com/162

Posted by hoonihoon
2013. 11. 22. 11:00

결론:

SELECT * FROM tb_b1 WHERE b_index > 10 ORDER BY b_index ASC LIMIT 1;  [이전글]

SELECT * FROM tb_b1 WHERE b_index < 23 ORDER BY b_index DESC LIMIT 1; [다음글]

참조:

http://www.phpschool.com/gnuboard4/bbs/board.php?bo_table=tipntech&wr_id=19972&sca=&sfl=wr_subject%7C%7Cwr_content&stx=%C0%C0%B4%E4%C7%FC+%B0%D4%BD%C3%C6%C7&sop=and

시판에서 글보기를 했을시 하단에 전체 글목록을 보여주는 방법도 있지만

현재 보는글과 관련된글(답글)을 보여주면서 동시에 이전글, 다음글로 바로 이동하게 하는 방법도 있습니다.

이전글, 다음글로 바로 이동할때는 글을 보는 페이지(view.php)에서 이전글, 다음글에 해당하는 데이터를 알아야 합니다.

우선 묻지마보드의 경우에는 글보기를 할때 키값이 글번호입니다.

그럼 현재 보는글에서 다음글, 이전글에 대한 글번호를 구할수가 있어야 합니다.


예전에 초기버전의 묻지마보드의 경우에는 디비에 저장되는 글번호의 형식이 auto_increment 형식이 아닌

일반 int 형식으로 글을 작성할때마다 직접적인 번호조작에 의해서 1부터 차례대로 디비에 저장이 되게 됩니다.

그래서 이전글, 다음글을 불러올때는 아주 간편하게 해결이 됩니다.


예전 게시판처럼 글번호가 1,2,3,4 이렇게 무조건 순차적으로 저장이 될경우에는

이전글은 현재보는 글번호 + 1

다음글은 현재보는 글번호 - 1

이런식으로 되게됩니다. 그렇다면 이렇게 간편한데.. 왜 그런 방식을 채택하지 않냐는 의문이 생깁니다.

바로 효율성때문입니다. 현재는 글번호 필드가 auto_increment로 저장이 되며 글삭제시 그 삭제된부분의 

번호는 뻥뚤리게 됩니다. 그러면 글목록을 불러올때 글번호가 차례대로 출력되는건 가상번호때문입니다.

이 가상번호란 디비에 저장되어있는것이 아니라 리스팅할때 list.php 파일속에서 자체적으로 번호를 순차적으로 만들어 줍니다.


현재 묻지마보드의 경우 이러한 가상번호로 리스팅할때 순차적으로 번호가 주어지게 되며, 실제로 디비에 저장되는

글번호(no)는 아래 그림처럼 글이 삭제된경우에는 순차적인게 아니라 삭제된 부분의 번호는 비어있게 됩니다.


<그림 1>



답글이 달려도 그러하고 글이 삭제된 경우에도 그부분에 해당하는 글번호는 비게됩니다.

이러한 경우에는 이전글, 다음글을 가져올때 위의 방법처럼 1을 더하고 1을 뺀다고해서 해결될 문제가 아닙니다.

운이 좋다면 1을 더했을때 이전글을 추출할수 있을것이고 운이 나쁘다면 못할것입니다. 근데 우리는 운을 믿어서는 안되죠..^^


이제 본격적으로 이전글, 다음글을 구하는 Logic에 대해서 알아보도록 하겠습니다.

기본 원리는 시간을 이용한것입니다.


<그림 2>




이전글은 현재 보고있는 글보다 분명 먼저 작성된 글이다. (즉, date 값이 작음)

다음글은 현재 보고있는 글보다 분명 이후에 작성된 글이다. (즉, date 값이 큼)


여기서 말하는 date값이란 디비에 저장되는 글쓴시간의 타임스탬프 값입니다.


<그림 2>에서 현재 보고있는글은 503번 글이라고 한다면 우리에게 필요한것은 504번글과 502번글의 글 고유번호입니다.

이것을 구하기 위해서 503번글이 작성된 시간을 바탕으로 쿼리를 날리게 됩니다.


<그림 3>



이 쿼리에서 que1은 다음글을 구해오는 쿼리이며 que2는 이전글을 구하는 쿼리입니다.

que1을 보면 디비에서 date가 현재 우리가 보는 글이 쓰여진 날짜($row[date])보다 작은걸 가져옵니다.

즉, <그림2>에서 503번글 밑으로의 글들을 말하는거죠.

근데 이때 문제는 502번, 501번, 500번 즉, 503번 밑으로 모든 글들은 날짜가 $row[date]보다 작습니다.

그래서 뒤에 따라오는게 바로 "order by no desc limit 1" 입니다.

즉, 날짜가 작은것 중에서 역순으로 딱 한개만 쿼리하는거죠. 결과적으로 말하면 이 쿼리가 바로 <그림2>에서 502번을 가져오는거죠.


이전글을 구하는 쿼리 역시 같습니다. 위에서 설명한대로 하지만 단 한가지 다른점은 이번에는 역순(desc)으로 가져오는게 

아니라 정순(asc)로 가져와야합니다. 잘 생각해보시면 이해가 될겁니다. <그림2>에서 503번 위쪽에서 딱 하나를 가져올때는

가장 밑에 글을 가져와야만 그게 504번글이 되기때문이죠.


이해가 되셨나요??

이부분이 이전글, 다음글을 구하는 알고리즘의 가장 핵심부분입니다.

이것만 view.php 파일속에 제대로 삽입했다면 그다음에는 여러분이 원하시는데로 만들수 있습니다.

저같은 경우에는 다음 그림처럼 보이게 만들었습니다.


<그림 4>

위 그림에서 아래쪽 화살표를 클릭하면 다음글을.. 위쪽 화살표를 클릭하면 이전글을 보게 됩니다.

근데 저는 여기에 약간의 기능을 더 추가했습니다.


이전글이나 다음글이 없다면, 즉, 현재 보는글이 가장 첨의 글이거나 가장 나중의 글이라면

이전글, 다음글 버튼을 회색으로 처리했습니다. 그리고 그 버튼을 눌르면 "존재하지 않는 글을 선택하셨습니다." 라는

경고창을 띄우고 되돌려 보내게 했습니다.


이부분의 구현방법은 <그림 3>과 아래 그림을 잘 비교해보시면 이해가 갈겁니다.

<그림 3>은 게시판 자체 view.php 파일이며, 아래 그림은 스킨폴더속의 view_foot.php파일의 한 부분입니다.


<그림 5>



이제 구현하시겠습니까??

사실 간단해 보이지만 이 부분을 구현해내기위해서 혼자서 데이터베이스의 필드를 조작해보기도 하고

새로운 필드(prev_no, next_no)를 추가해보기도 했습니다. 근데 너무 일이 복잡해질듯해서 생각해본 결과

이렇게 간단하게 해결이 되더군요. 한번 해보시기 바랍니다.

Posted by hoonihoon
2013. 11. 22. 10:42

출저: http://theeye.pe.kr/entry/%EA%B2%8C%EC%8B%9C%ED%8C%90%EC%9A%A9-%ED%8E%98%EC%9D%B4%EC%A7%95-%ED%81%B4%EB%9E%98%EC%8A%A4[아이군블로그]


게시판에서 쓸만한 페이징 클래스를 제작해 보았다. 문제 발견시 피드백 부탁드립니다^^


---------------------------------------------------------------------------------------
페이징 클래스 소스코드 :
---------------------------------------------------------------------------------------

public class PageNavigation {
   
   
private        boolean        isPrevPage;
   
private        boolean        isNextPage;
   
protected    int            nowPage;
   
protected    int            rowTotal;
   
protected    int            blockList;
   
protected    int            blockPage;
   
private        int            totalPage;
   
private        int            startPage;
   
private        int            endPage;
   
private        int            startRow;
   
private        int            endRow;
   
   
// 페이지를 계산하는 생성자
   
public PageNavigation(int nowPage, int rowTotal, int blockList, int blockPage) {
       
super();
       
       
// 각종 플래그를 초기화
        isPrevPage
= false;
        isNextPage
= false;
       
       
// 입력된 전체 열의 수를 통해 전체 페이지 수를 계산한다
       
this.totalPage    = (int) Math.ceil((double)rowTotal / (double)blockList);
       
       
// 현재 페이지가 전체 페이지수보다 클경우 전체 페이지수로 강제로 조정한다
       
if(nowPage > this.totalPage)
       
{
            nowPage
= this.totalPage;
       
}
       
       
// DB입력을 위한 시작과 종료값을 구한다
       
this.startRow    = (int) (nowPage - 1) * blockList;
       
this.endRow        = (int) this.startRow + blockList - 1;
       
       
// 시작페이지와 종료페이지의 값을 구한다
       
this.startPage    = (int) ((nowPage - 1) / blockPage) * blockPage + 1;
       
this.endPage    = (int) this.startPage + blockPage - 1;
       
       
// 마지막 페이지값이 전체 페이지값보다 클 경우 강제 조정
       
if(this.endPage > this.totalPage)
       
{
           
this.endPage = totalPage;
       
}
       
       
// 시작 페이지가 1보다 클 경우 이전 페이징이 가능한것으로 간주한다
       
if(this.startPage > 1)
       
{
           
this.isPrevPage = true;
       
}
       
       
// 종료페이지가 전체페이지보다 작을경우 다음 페이징이 가능한것으로 간주한다
       
if(this.endPage < this.totalPage)
       
{
           
this.isNextPage = true;
       
}
       
       
// 기타 값을 저장한다
       
this.nowPage = nowPage;
       
this.rowTotal = rowTotal;
       
this.blockList = blockList;
       
this.blockPage = blockPage;
   
}
   
   
public void Debug()
   
{
       
System.out.println("Total Page : " + this.totalPage + " / Start Page : " + this.startPage + " / End Page : " + this.endPage);
       
System.out.println("Total Row : " + this.rowTotal + " / Start Row : " + this.startRow + " / End Row : " + this.endRow);
   
}
   
   
// 전체 페이지 수를 알아온다
   
public int getTotalPage()
   
{
       
return totalPage;
   
}
   
   
// 시작 Row값을 가져온다
   
public int getStartRow()
   
{
       
return startRow;
   
}
   
   
// 마지막 Row값을 가져온다
   
public int getEndRow()
   
{
       
return endRow;
   
}
   
   
// Block Row 크기를 가져온다
   
public int getBlockSize()
   
{
       
return blockSize;
   
}
   
   
// 시작페이지값을 가져온다
   
public int getStartPage()
   
{
       
return startPage;
   
}

   
// 마지막 페이지값을 가져온다
   
public int getEndPage()
   
{
       
return endPage;
   
}
   
   
// 이전페이지의 존재유무를 가져온다
   
public boolean isPrevPage()
   
{
       
return isPrevPage;
   
}
   
   
// 다음페이지의 존재유무를 가져온다
   
public boolean isNextPage()
   
{
       
return isNextPage;
   
}
}

---------------------------------------------------------------------------------------
서블릿(Controller) 소스코드 :
---------------------------------------------------------------------------------------

// 리스트를 가져온다
if(request.getParameter("page") == null)
{
    nowPage
= 1;
}
else
{
    nowPage
= Integer.parseInt(request.getParameter("page"));
   
   
if(nowPage < 1)
   
{
        nowPage
= 1;
   
}
}

// 객체를 생성한다 (현재페이지, 전체글수, 페이지당표시할 글의수, 한번에 표시할 페이징블록수)    
PageNavigation pageNav = new PageNavigation(nowPage, rowTotal, 10, 5);

// 디버깅이 필요할시 사용한다. 안써도 됨
pageNav
.Debug();

// 시작Row값과 종료Row값을 넣어 쿼리문을 작성한다
sql
= "SELECT * FROM TableName ORDER BY no DESC LIMIT " + pageNav.getStartRow() + ", " + pageNav.getBlockSize();

// 뷰에게 넘길 값을 지정한다
request
.setAttribute("pageIsPrev",    pageNav.isPrevPage());    // 이전페이지 블록의 존재유무
request
.setAttribute("pageIsNext",    pageNav.isNextPage());    // 다음페이지 블록의 존재유무
request
.setAttribute("pageStart",    pageNav.getStartPage());// 시작페이지 번호
request
.setAttribute("pageEnd",        pageNav.getEndPage());    // 종료페이지 번호

---------------------------------------------------------------------------------------
jsp(View) 소스코드(EL표기법, JSTL사용) :
---------------------------------------------------------------------------------------

<div>
   
<center>
       
<c:if test="${pageIsPrev}">
           
<a href="index.do?page=${pageStart - 1}">prev</a>
       
</c:if>
       
<c:forEach var="page" begin="${pageStart}" end="${pageEnd}">
           
<a href="index.do?page=${page}">[${page}] </a>
       
</c:forEach>
       
<c:if test="${pageIsNext}">
           
<a href="index.do?page=${pageEnd + 1}">next</a>
       
</c:if>
   
</center>
</div>



---------------------------------------------------------------------------------------
결과 :
---------------------------------------------------------------------------------------
prev [11] [12] [13] [14] [15] next

Posted by hoonihoon