워커 [영문] 스크립트 명령어 리스트입니다.

영문] 스크립트 명령어 리스트입니다.

--------------------------------------------------------------------------------

원래는 천천히 하나하나씩 이해하기 쉽게 설명하면서 진행하려고 했는데, 아무래도 영어하시는 분들도 계시고, 후딱 먼저 보여드리고 예습하시라는게 나을 것 같아서 일단 적어놓습니다.

스크립트 명령어 리스트입니다. 슈퍼맨 명령어이지만, 스크립트는 워커에서도 돌아갑니다.

UseSkill: UseSkill(PlayerName, SkillName[Id=XXX]),
for example: UseSkill(jack,Attack Aura[Id=77]),
if the player name is "self", then means use to the player himself.

CharSel: CharSel(player name), select a player, for exmaple: CharSel(jack)

MonSel: MonSel(Monster Name[Id=XXX]), select the nearest monster of the specified kind,
for example: MonSel(Rabbit[Id=20002])

UseSkill2: UseSkill2(Skill Name[Id=XXX), use specified skill to selected obj

UseItem: UseItem(Item Name[Id=XXX]), for example UseItem(Scroll of Escape[Id=736]).

BuyItem: BuyItem(Item1 Name[Id=XXX],Count), BuyItem(Item1 Name[Id=XXX],Count; Item2 Name[Id=XXX],Count);
for example: BuyItem(Scroll of Escape[Id=736],1)

SellItem: SellItem(Item1 Name[Id=XXX],Count), SellItem(Item1 Name[Id=XXX],Count; Item2 Name[Id=XXX],Count);
for example: SellItem(Scroll of Escape[Id=736],1);
SellItem(*) is sell all items which setting as "Sell" in current config

SaveItem: SaveItem(Item1 Name[Id=XXX],Count), SaveItem(Item1 Name[Id=XXX],Count; Item2 Name[Id=XXX]),Count);
Deposit Items in the warehouse;
for example SaveItem(Scroll of Escape[Id=736],1),
SaveItem(*) is deposit all items which setting as "Warehouse" in current config

LoadItem: LoadItem(Item1 Name[Id=XXX],Count), LoadItem(Item1 Name[Id=XXX],Count; Item2 Name[Id=XXX], Count)
Withdraw items from warehouse;
for example LoadItem(dagger[Id=1],1)

Msg: Msg(info),
for example Msg(return town after dead!),
the info does not send to game server.

Set(FightStart): active L2Superman

Set(FightStop): inactive L2Superman

Set(BeatBackOpen): auto fight back monsters' attack when L2Superman is inactive(default)

Set(BeatBackClose): do not auto fight back monsters' attack when L2Superman is inactive

Delay: Delay(N), the script execution pause for N ms, for example: Delay(1000)

Label: Label(XXX),
XXX is label name,
for example: LABEL(detect range), there are match case some commands after label.

Jmp: Jmp(XXX),
jump to the command with the certain label,
for example Jmp(detect range), use it to control the scripts execute flow

Call: Call(XXX), XXX is the label name,
for example: Call(begin attack),
the difference between "Jmp" and "Call" is that:
"Call" will return to execute the next command after execute the block of commands with the certain label.

MoveTo(X,Y,Z): MoveTo(X,Y,Z), make the character MoveTo the location(X,Y,Z)

NpcSel: NpcSel(NPC Name[Id=XXX]),
Select the NPC, for example NpcSel(Jackson[Id=7002])

NpcDlg: NpcDlg(NPC Name[Id=XXX]),
chat with this NPC, for example: NpcDlg(Jackson[Id=7002])

DlgSel: DlgSel(str)
select "str" in the dialog, for example: DlgSel(Sell Item)

CharStatus: CharStatus(Item,Cond,Value)
Condition command, detect the status of character,
Item: CHP(current hp value), CMP(current mp value), CCP(current cp value),
HP(hp percent), MP(mp percent), CP(cp percent), WEIGHT(load percent),
LV, SP, RACE(Human:0, Elf:1, Dark Elf:2, Orc:3, Dwarf:4), STAND
Cond: >=, >, ==, !=, <, <=
for example: CharStatus(Weight,>=,45), detect whether weight is over 45% or not

PosOutRange: PosOutRange(X, Y, Z, Radius)
Condition command,detect whether char is out of rangeor not,
for example: PosOutRange(-96716,255766,-3443,3000) dectect wether char is out of the circle which center is (-96716,255766,-3443) and the radius is 3000.

PosInRange: PosInRange(X, Y, Z, Radius)
Condition command, detect whether char is in the range or not,
for example: PosInRange(-96716,255766,-3443,3000)

PosOutRange2: PosOutRange2(X,Y,Z,Step)
Condition command, detect wether char is out of range or not,
for example: PosOutRange(-96716,255766,-3443,50) dectect wether char is out of the circle which center is (-96716,255766,-3443) and the radius is 50 step. Note: 1 step=36

PosInRange2: PosInRange2(X,Y,Z,Step)
Condition command, detect wether char is in the range or not,
for example: PosInRange2(-96716,255766,-3443,50)

GoHome: GoHome() return town after dead

Say: Say(XXX), say XXX in normal channel

Shout: Shout(XXX), shout XXX

PartySay: PartySay(XXX), say XXX in party channel

PrivateSay: PrivateSay(Player Name, XXX), say XXX in private channel

Exit: Exit(), exit the execution of the scrpt

Pause: Pause(), pause the execution of the script

StrInDlg: StrInDlg(XXX)
Condition command, detect whether XXX is in the NPC dialog or not
for example: StrInDlg(fungus)

StrOutDlg: StrOutDlg(XXX)
Condition command, detect whether XXX is not in the NPC dialog
for example: StrOutDlg(fungus)

ChangeWaitType: ChangeWaitType(X)
X=0:sit down, X=1 stand up

ForceAttack: ForceAttack(NPC Name[Id=XXX]), Attack NPC

Set(FishStart): begin to fish

Set(FishStop): stop fishing

Set(RangeType,Rand): Set combat range to random(no limit range)

Set(RangeType,StartPos,radii): make the current pos as center of combat range and radius is radii

Set(RangeType,DefPos,x,y,z,radii): make the (x,y,z) as center of combat range and radius is radii

Set(RangeType,DefRange): set combat range to custom polygon range

Set(RangeType,DefPath): set combat range to certain path.

Set(DefRange,Clear): clear the pos of the polygon.

Set(DefRange,Add,x,y,z): add the pos (x,y,z) to polygon

Set(DefPath,Clear): clear the pos of default path,Set(DefPath,Clear)

Set(DefPath,Add,x,y,z,radii): add the pos(x,y,z) to default path

Set(Item,Ops,Item1[Id=XXX];Item2[Id=XXX]): Setting for certain items, ops: Pick|NoPick|Save|NoSave|Sell|NoSell|Delete|NoDelet e
Set(Item,Ops,*): setting for all items

Set(Mon,Ops,Mon1[Id=XXX];Mon2[Id=XXX]): Setting for certain monsters, ops:Attack|NoAttack|AttackOne|Dodge
Set(Mon,Ops,*): setting for all mons

SellSeed(Fruit Name[Id=XXX],Count,CityId): Sell fruits,
City Id: Gludio Castle(1), Dion Castle(2), Giran Castle(3), Oren Castle(4), Aden Castle(5), Innadril Castle(6), Goddard(7)

BuySeed: Buy seeds, BuySeed(Seed Name[Id=XXX],Count)

LoadConfig: LoadConfig(Config file), for example LoadConfig(defaults), load "defaults.ini"

IsMember: IsMember(Player Name)
Condition command, detect whether XXX is party member

!IsMember: !IsMember(Player Name)
Condition command, detect whether XXX is not party member

RequestJoinParty: RequestJoinParty(object,type)
Request object to join party,
Type: Item-Distribution-Method, 0 certain, 1 random, 2 rand include swap, 3 as party member sequence, 4: sequence include swap
for example: RequestJoinParty(jack,0)

RequestOutParty: RequestOutParty(object)
drive object out of party,
for example: RequestOutParty(jack)

QuitParty: QuitParty()
quit party

QueryPlayerStatus: QueryPlayerStatus(object name,item,cond,value)
condition command,
item:HP,CHP,MP,CMP,CP,CCP
cond:>=, >, ==, !=, <, <=

MemberStatus: MemberStatus(object name,status name[Id=XXX])
condition command, detect whether object has certain status,
for example: MemberStatus(jack,Attack Aura[Id=77])

!MemberStatus: !MemberStatus(object name,status name[Id=XXX])
condition command, detect whether object doesn't have certain status
for example: !MemberStatus(jack,Attack Aura[Id=77])

ReLogin: ReLogin(interval)
interval: logout and will login afer "interval" seconds,
if the interval is 0, that means logout and will not login any more.

DisFromNpc: DisFromNpc(NPC Name[Id=XXX], Cond, Steps)
Condition command,
cond: >=, >, ==, !=, <, <=
detect whether the distance from npc meet the requirement

DisFromPlayer: DisFromPlayer(Player Name, Cond, Steps)
Condition command,
cond: >=, >, ==, !=, <, <=
detect whether the distance from player meet the requirement

MonInRange: MonInRange(Mon Name[Id=XXX],x,y,z,r,cond,Count)
Condition command,
cond: >=, >, ==, !=, <, <=
detect the Count of certain mon in the center of (x,y,z) and radius is r.
MonInRange(*,x,y,z,r,cond,Count) detect the total mon Count in the center of (x,y,z) and radius is r.

MoveToPlayer: MoveToPlayer(player name)

MoveToNPC: MoveToNPC(NPC name[Id=XXX])

ItemCount: ItemCount(ItemName[Id=XXX],cond, Count)
Condition command,
cond: >=, >, ==, !=, <, <=

by 딸기아부지 | 2007/07/04 11:19 | 기타잡기 | 트랙백
프린터포트를 이용한 외부제어

COFFEE-HOWTO

Fotis Georgatos, < gef@hellug.gr>
Annie Pinder, < ajp@leguin.org.uk>

v0.8, 30 November 2000


One of the most memorable comments about software I have ever heard, is whether this or that can make coffee. Coffee is a world commodity that is second only to oil. Linux DOES make coffee. And it tastes good, as well!

For a long time, humanity was wondering how could a computer make coffee... People need coffee wake up and stay awake in front of the computer for a long time. Everyone knows that coding is better at night...

The main problem is how to manage the coffee machine with the computer, so that it will be controlled by software. This generally means an ON/OFF switch implemented as a circuit which controls the coffee-machine's power supply.

This HOWTO has turned out in a public project, look at http://coffee.sourceforge.net/,

1. Menu

2. Electronic circuit

3. Software

4. Overdose symptoms

5. Expansions

6. References

7. etc


1. Menu

1.1 French

Popular coffee among programmers because doesn't need a lot of care; like commercial software. Its exciting taste has inspired thousands of programmers in writing incredible software, written in the very first ours of a day. Windows for example was written at 5:00 o'clock in the morning, Due to coffee! A result is guaranteed.

1.2 Nescafe

Nescafe is a rather strong coffee, made by pouring hot water in a mixture of coffee, sugar and some water. You usually take 1 spoon of coffee and 1 spoon of sugar with just a bit of water, to mix it. In the meantime you should have the water boiling. As soon as the water is hot enough, you mix them all together and preferably add milk. Although you can use something simpler than a coffee-machine to boil the water, I have seen this done many times...

1.3 Frappe

A popular variation of the above mentioned coffee. Actually, it doesn't need a coffee-machine, rather a refrigerator for cold water and ice-cubes.

1.4 Freddo

This is a difficult one, read coffee-faq (see references)

1.5 Espresso

Espresso is a very strong, italian sort of coffee. You serve it in small cups (You ask why? See chapter: Overdose Symptomes) with on or to pieces of lump sugar. To produce a good espresso you need fresh grinded coffee beans, water, lump sugar and a special machine. These machines boil the water and press the very hot steam through the grinded coffee beans. You can buy a super-duper-automatic machine for a lot of money. But a low cost machine is useable, too.

OK., lets start. Fill water in your machine. Let it become hot. In the meantime fill about 1 teespoon of coffeepowder in the filterhandle of your machine. Press the coffeepowder down. Not too much. Now the water is at the right temperature. Attach the filterhandle to the machine and let the machine work. After about 30 seconds you can serve a delicate, hot espresso. It is fine after a good meal. You feel good and can code for a few more hours.

1.6 Cappuccino

(See also chapter: Espresso) If you have a more profi-like machine, you can use it, to froth milk with it. You need this feature to make a creamy sort of coffee. It is easy to prepare. Put some frothed milk in a coffee pot and fill it up with espresso. Then decorade with some chokolade flakes. That큦 it.


2. Electronic circuit

A general diagram is like this:

--------- 0-5V  --------- ~220V  ----------------|  PC   |===>===|Circuit|========|Coffee-Machine|---------       ---------        ----------------

The concept is that we take a controling voltage from the computer, which drives an electrically isolated circuit with a Relay or Triac.

You must choose a Relay circuit, if you have a coffee-machine greater than 200W. You can use a triac-based one if your coffee machine isn't high power.

All circuits presented are tested, but the results are YOUR RESPONSIBILITY. If you have no experience with electronics you should NOT try these, otherwise you may get a bad one...

You should be very careful while experimenting with 220V, and using an appropriate fuse is advisable.

2.1 Driving voltage 0-5V from the computer

Here is a simple example to get a voltage 0-5V from the parallel port of the computer.

      Back View          -----    Pin 10 - ACK      Male DB-25         |   |    Pin  9 - D7      Connector          |   |                           Pin 2 - D0                         v   v                           v   Pin 1 -~Strobe       ____________________________________________________________      /                                                            \      \     13  12  11  10   9   8   7   6   5   4   3   2   1     /       \                                                          /        \     25  24  23  22  21  20  19  18  17  16  15  14     /         \______________________________________________________/

Pin 1 is Strobe (inverse logic)

Pins 2-9 is DATA BUS's signals, exactly what was written to the parallel port's latches with an OUTB command.

Pin 10 is the acknowledge signal (ACK), controlled by you, so that you can produce an interrupt to the CPU.

Pins 18-25 are short-circuited and this is the ground (GND).

In detail:

<= in   DB25    Cent    Name of         Reg=> out  pin     pin     Signal          Bit     Function Notes------  ----    ----    --------        ---     -----------------------------=>       1       1      -Strobe         C0-     Set Low pulse >0.5 us to send=>       2       2      Data 0          D0      Set to least significant data=>       3       3      Data 1          D1      ...=>       4       4      Data 2          D2      ...=>       5       5      Data 3          D3      ...=>       6       6      Data 4          D4      ...=>       7       7      Data 5          D5      ...=>       8       8      Data 6          D6      ...=>       9       9      Data 7          D7      Set to most significant data<=      10      10      -Ack            S6+ IRQ Low Pulse ~ 5 uS, after accept<=      11      11      +Busy           S7-     High for Busy/Offline/Error<=      12      12      +PaperEnd       S5+     High for out of paper<=      13      13      +SelectIn       S4+     High for printer selected=>      14      14      -AutoFd         C1-     Set Low to autofeed one line<=      15      32      -Error          S3+     Low for Error/Offline/PaperEnd=>      16      31      -Init           C2+     Set Low pulse > 50uS to init=>      17      36      -Select         C3-     Set Low to select printer==      18-25   19-30,  Ground

2.2 Controlling with a Relay

The simplest circuit that one can build is:

                             Vcc                              |                              +------+                              |    __|__                            Relay   /^\  Diode 1N4002                             Coil  /---\                              |      |                              +------+                              |                           | /                  4.7K    B |/  Cparallel port >-\/\/\/\/---|        NPN Transistor: BC547A or 2N2222Adata pi                    |\  E                           | V                             |parallel port >--------------+ground pin                   |                          Ground
Connect Vcc with the same voltage as the relay type (usually 5 or 12V). Obviously, the relay's specifications should be scaled for your coffee-machine.

Barmen, tend to put the relay AFTER the transistor, at the emitter (E) pin instead of the collector (C) pin. This is bad practice because it biases the transistor badly, and may result in bad coffee :-). Diode 1N4002 is useful to protect the transistor from the relay's currents. If you don't use it the transistor will become dark and smelly...

2.3 Controlling with TRIAC #1

If you only want a simple circuit, you can use Motorola's triac driver MOC301[012], together with a general purpose TRIAC like SC141D. This method has the advantage that you don't need an extra power supply.

For non-inductive loads, this is the circuitry:

        270     1 +-------+ 6    180  +5v -VAVAVA-----+       +----VAVAVA-----+-------------- Line Hot                2 |  MOC  |               |  TTL in ---------+ 3012  +nc            VA  SC141D                  |       | 4           / |                nc+       +------------/  |                  +-------+               +----\/\/\/---- Line Neutral                                                LOAD

If you are going to work with 220V, try to obtain a 3021. Inductive loads should be used in conjuction with bypass capacitors, see Motorola Application Note AN-780. Coffee-machines are mainly resistive loads and not inductive (like a motor), but who knows what yours is!

2.4 Controlling with TRIAC #2

+5VDC|    180                      180            2.2k+---/\/\/\----+-----+   +----/\/\/-+--/\/\/\---+-------> 120V              |    1|   |6         |           |         Hot              |    +=====+         |           | MT1              |    | MC  | TRIAC   |          +-+              |    | 3032| Driver  |        G | | TRIAC              |    +=====+         |         /| |              \    2|   |4         |        / +-+       2N3904  |----+   |          |        |  | MT2              /     |   +--------- | -------+  |             V      \              |        |  |             |      /              |        \  |             |      \ 43    .01u  ---   10k /  |             |      /       500V  ---       \  |             |      |              |        /  |             +------+              |        |  |            Neutral             |                     +--------+--+---o    o--> 120V             /                                      load >-/\/\--|  2N3904             \              V              |             ---            ///You should change resistors accordingly for 220V.

Circuit description:

The MC3032 is an optoisolator TRIAC driver. The 180-ohm resistor sets the current for the LED emitter in the optoisolator. Change the value of this resistor - if necessary - to get a reasonable current (e.g., 15 mA).

Note that you cannot test this circuit without a load. The TRIAC will not switch unless connected to an AC voltage source, so you can't test it for simple switching without applying AC and a load. Note the 500V rating on the .01 cap.


3. Software

3.1 Software

You will have to build an executable that will work like this:

  • Get permission to use I/O address space, by calling kernel, with the command ioperm: eg ioperm( BASE, range ,1);
  • Perform an out request instruction, to set the 0-5V voltage to the parallel port, eg outb( 1, BASE );
  • Wait enough time so the coffee is made. It would be nice if that time is read by looking at the command line.
  • Then it will turn off the coffee-machine: outb( 0 , BASE );
  • Before ending it should give back the parallel port with a ioperm( BASE, range, 0);
Change BASE = 0x3bc for /dev/lp0, 0x378 for /dev/lp1, and 0x278 for /dev/lp2, range=8.

It would be useful if you had that program setuid, so that everybody can drink coffee!

3.2 Device driver

Just read kernel hacker's guide, implement a device driver (it could even be user space I think). Please compile it as a module, so that we won't need a kernel compile in every update. Then write:

echo cappuccino >/dev/coffee

And you will have a hot cup of coffee in minutes! Remember to give the right permission to /dev/coffee, depending on whether you want only root making coffee or not.

The advantage of this method is that it supports feedback from the coffee-machine by using the ACK of parallel port, so that smart coffee-machines could produce an interrupt.

Do it as homework.

3.3 Connecting with the Internet

If you have implemented the C program (see above), you just have to write a simple CGI script to turn ON and OFF the coffee-machine. You should write some nice webpages, explaining how to make coffee, and put them on an apache web server...


4. Overdose symptoms

  • excitement
  • nervousness
  • insomnia
  • tachycardia or cardiac arhythmia
  • restlessness
  • Hypersensibility to light
  • Annoyance in respect with various audio stimuli
  • gastrointestinal disturbance


5. Expansions

These are our ideas:

  • All hardware and software described here, can be expanded so that it will support toast, beaf, applepies, etc.
  • Cluster with 8 coffee-machines. This will let you have coffee even when the first one gets off. Of course there will be a perfomance hit.
  • Parallel vector coffee-machine will be a future release.
  • If you want the maximum automation you'll need more circuits and sensors, so that you can control water flow, temperature, coffee quantity etc.
  • In the near future we will implement SNMP features.
  • Serial coffee-machine at 115Kbps.


6. References


7. etc

7.1 preface

This document was initially written as part of a small debate in the linux-greek-users list , whether linux can make coffee or not. It has been an article in our beautiful online magazine about Linux called magaz. Remember, that magaz is greek it will look like that to you.

7.2 Authorship and maintenance

My name is Fotis Georgatos and I have also been in the past busy with the greek documentation and wwwpages maintainance. I welcome submissions to this HOWTO, as long as you're not anxious about the changes.

I'm Annie Pinder and a coffee fan. I live in England. I made the language changes on this document. I'm currently in the English equivalent of High School, in my final compulsory year.

7.3 Copyrights

The casual copyright with everything you get with linux... To find it, you'll have to read all of HOWTOs and average out the most common. Otherwise, no, you cannot copy it.

7.4 Credits

  • Ethiopia: Identified as the originating country of coffee. As many people corrected, coffee did not originally come from America nor was brought by Christofer Colombus. It was popular in the Middle East long before America was discovered. Still, we can remember Cristobal Colon, as the person who brought tobacco and chocolate in Europe.
  • Kostas Lialiambis is the one who dared saying that he can't make coffee with his Linux box.
  • Panagiotis Vrionis, Yannakopoulos Haralambos, for giving me interesting and humorous notes.
  • NUMEROUS people on the internet with additions and remarks.

by 딸기아부지 | 2007/05/17 15:00 | 기타잡기 | 트랙백
텍스트 파일에서 ^M 지우기

텍스트 파일에서 ^M 지우기

원도우에서 UNIX 계열의 서버에 자료를 upload할 경우에 파일 뒤에 ^M가 붙어 있는것을 볼수 있습니다.
이유는 원도우는 \n\r 이구 유닉스는 \n 이기에 \r 이 남는것이 문제입니다.
자료를 ftp 로 전송할때 ASCII로 전송하면 아무 문제가 없지만
제거 방법은
1. vi 에서
:%s/^M//g
^M 은 crl > v > enter 입니다.
2. perl -pi -e 's/\r//' filename

by 딸기아부지 | 2007/05/15 10:27 | 리눅스관련 | 트랙백
shell 문법
shell 문법 조회(152)
솔라리스 | 2007/02/16 (금) 11:55 공감하기(0) | 스크랩하기(0)
자료 출처 http://myhome.naver.com/yskim511/index00.html
1. 매개변수(파라메타)
쉘 변수에는 세가지 유형이 있으며 이는 매개 변수로 알려져 있다. 그종류는 키워드 매개 변수, 위치 매개변수, 특수 쉘 매개변수 등이다.
1) 키워드 매개 변수
키워드 매개변수명은 알파벳 문자나 _ (밑줄) 문자로 시작 되어야 한다. 그리고 그 다음에는 알파벳이나 밑줄문자의 임의의 숫자가 올 수 있다. 그 값들은 다음과 같이 기록함으로써 키워드 매개변수에 배정된다.
변수=값 변수=값 ...
2) 위치 매개 변수
쉘 프로그램이 실행될 때마다 프로그램명은 변수 $0에 배정되고, 명령 라인에 타이프된 인수들은 변수 $1, $2, $3 ...에 배정된다. 위치 매개변수들 set 명령으로 값을 배정 받을 수 있다. $9 이상의 매개변수는 ${nn}으로 표현할 수 있다.
Examples:
$ cat hi
print hello $1
$ hi there world
hello there
3) 특수 매개 변수
$# 프로그램에 전달된 인수들의 수 또는 set문 실행에 의해 세트된 매개 변수들의 수
$* $1, $2, $3 ...과 같은 모든 위치 매개변수들을 집단적으로 참조
$@ $* 과 같이 위치 매개변수들을 집단적으로 참조
$0 실행중인 프로그램 이름
$$ 실행중인 프로그램의 프로세스 번호
$! 실행을 위해 백그라운드로 보내진 마지막 프로그램의 프로세스 번호
$? 백그라운드로 실행되지 않은 마지막 명령의 종료 값
$- 현재 설정된 옵션값
2. 매개변수 치환
가장 간단한 경우로서, 매개변수의 값은 달러표시($)를 가진 매개 변수를 선행함으로써 접근될 수 있다. 매개 변수의 치환은 파일명 치환전에, 그리고 명령 라인이 인수로 분리되기 전에 쉘에 의해 수행된다.
$parameter 또는 ${parameter}
매개변수의 값을 치환한다.
$ print $PWD ${11} $$
/usr/dgk arg11 1234
$ file=test_f
$ cp $file ${file}x
$
$ ls -x
$ test_f test_fx
${parameter:-value}
parameter의 값이 null이 아닌 경우 그값을 치환하고, null인 경우에는 value값만을 치환.
$ EDITOR=/bin/ed
$ echo ${EDITOR:-/bin/vi}
/bin/ed
$ EDITOR=
$ echo ${EDITOR:-/bin/vi}
/bin/vi
$ echo $EDITOR
$
${parameter:=value}
parameter값이 null이 아닌경우 그값을 치환하고, null인 경우 value값을 치환하고 그것을 parameter에 대입.
$ unset x
$ typeset -u x
$ print ${x=abc}
ABC
$
$ BOOKS=
$ : ${BOOKS:=$HOME/books}
$ echo $BOOKS
/usr/kys/books
$ : ${BOOKS:=tester}
$ echo $BOOKS
/usr/kys/books
$
${parameter:?value}
parameter 값이 null이 아닐경우 그값을 치환. 그렇지 않으면 value을 표준 에러에 기록하고 빠져나옴.
만약 value가 생략되어 있으면 parameter와 메서지를 출력프로그램에서 요구되는 변수들이 모두 설정되었는지 또는 무효가 아닌지의 여부를 알아보기위해 쉽게 사용하여 체크할수 있다.
$ print ${foo?}
ksh: foo: parameter null or not set
$ BOOKS=
$ : ${BOOKS:?"No BOOKS file"}
No BOOKS file
${parameter:+value}
parameter가 null이 아닐 경우 value를 치환.  null인 경우 아무것도 치환하지 않음.
$ set a b c
$ print ${3+foobar}
foobar
$
$ toption=
$ echo options: ${toption:+ "T mode"}
options:
$
${#parameter}
매개변수의 길이를 치환
$ HOME=/home/klog
$ print ${#HOME}
10
$
${#array[*]} , ${#array[@]}
배열의 요소들의 수를 치환
$ unset x
$ x[1]=5 x[3]=8 x[6]=abc x[12]=
$ print ${#x[*]}
4
${parameter#pattern}
매개변수의 값을 치환하며 이때 pattern과 부합되는 왼쪽 부분은 제거된다. 쉘 화일명 치환문자들(*,?,[..],@,!)을 사용할 수 있다.
$ cd $HOME/src/cmd
$ print ${PWD#$HOME/}
src/cmd
$
${parameter##pattern}
가장 큰 pattern과 부합되는 왼쪽 부분은 제거된다.
$ x=/one/two/three
$ print ${x##*/}
three
$
${parameter%pattern}
pattern과 부합되는 오른쪽 작은 부분이 제거된다.
$ x=file.c
$ print ${x%.c}.o
file.o
$
${parameter%%pattern}
pattern과 부합되는 오른쪽 큰 부분이 제거된다.
$ x=foo/fun/bar
$ print ${x%%/*}
foo
$
3. 파일 입출력
1) 파일 열고 닫기
exec 명령을 아무런 아규먼터 없이 사용하여 현재 환경에서 파일을 열고 닫을 수 있으며, I/O 방향재설정 방법을 사용하며 이때 파일디스크립터 값은 0-9까지 사용할 수 있다.
Examples:
exec 3< foo  <- foo을 파일디스크립터3 으로 지정하여 읽기위해
open
$ exec 3<&- <- 파일디스크립터3 을 close
4. 다큐먼트, 반환값
1) 다큐먼트
문자 #로 단어가 시작된다면 셀은 라인의 나머지를 주석으로 취급하고 ksh이 실행하지 않는다
Examples:
$ cat samp_1
# This is comment line
# pwd
ls -x # display listing of the directory
$ samp_1
samp_1 samp_2 samp_3 samp_4 samp_5
$
2) 반환값
각각의 명령어는 반환값을 가진다. 명령어의 반환값은 조건 명령이나 순환명령에서 많이 사용된다. 반환값은 0에서부터 255의 값을 가진다.
반환값 0 은 정상적인 종료인 경우의 값이며 조건이나 순환명령어에서 TRUE로 사용되는 값이다. 그 이외의 모든 다른 값은 FALSE로 취급된다.
반환값 1은 명령의 실행이 실패한 경우 129-160은 명령어가 신호를 수신하고 종료한 경우에 발생되는 값이다.
ksh에서는 $? 변수에 가장 최근에 종료된 명령어의 반환값이 저장된다.
5. 병렬 프로세스 기능
병렬프로세스 기능은 동시에 실행되면서 상호간에 통신하고 동기화를 하는 프로세스간의 상호 작용 기능을 제공한다. 병렬프로세스의 시작은 명령어 라인의 끝에 "|&" 을 추가하므로서 구현할 수 있다.
기본적으로 병렬 프로세스의 표준입력은 그 프로세스의 부모 프로세스의 표준 출력과 연결되며, 병렬 프로세스의 표준 출력은 그 프로세스의 부모 프로세스의 표준 입력과 연결된다.
cat /etc/passwd |&
while true
do
if [ -z "$FLINE" ]
then
exit 0
else
read -p FLINE
fi
echo $FLINE
done
6. 쉘 스크립트 실행 방법
1) . Script ( Dot Command )
도트 명령은 지시된 파일이 마치 그 파일로 부터의 라인들이 그지점에서 타이프 된 것처럼 쉘에 의해 판독되고 실행되도록 한다. file은 실행하도록 하는 것이 아니라 다만 읽기 쉽게 한다.
Examples:
$ cat > .profile
export PS1='$PWD> '
export PATH=$PATH:$HOME
^d
$ . .profile
/home/edu01> _
-> 변경된 .profile의 내용을 로그아웃, 로그인 순서를 그치지 않고 현재 쉘에서 실행하여 사용자 환경을 지정할 수 있다.
2) ksh script_filename
서브쉘을 생성하여 그 쉘이 스크립트를 읽어서 실행하도록 한다. 이 경우 script_filename 파일이 실행 퍼미션이 지정되어 있지 않아도 된다.
Examples:
$ cat > test_sub_shell
echo "test execution of shell script file "
echo $PWD
^d
$
$ ls -l test_sub_shell
-rw-r--r-- 1 edu01 other 54 Jan 29 10:00 test_sub_shell
$ ksh test_sub_shell
test execution of shell script file
/home/edu01
$
3) chmod +x script_filename
script 파일에 실행 퍼미션을 설정하여 실행한다.
Examples:
$ chmod +x test_sub_shell
$ ls -l test_sub_shell
-rwxr-xr-x 1 edu01 other 54 Jan 29 10:00 test_sub_shell
$ test_sub_shell
ksh: No such file or directory
-> 현재 디렉토리 경로가 PATH에 설정되어 있지 않다.
$ export PATH=$PATH:.
-> 현재 디렉토리를 PATH 환경변수에 설정한다
$ test_sub_shell
test execution of shell script file
/home/edu01
$
7. 파일과 문자 테스트 연산자
test 명령이나 [ ... ] 연산 결과 TRUE로 반환 받는 조건이다.
1) 파일연산자
-r file 프로세스에 의해 판독가능한 파일
-w file 프로세스에 의해 기록 가능한 파일
-x file 프로세스에 의해 실행 가능한 파일
-f file 보통 파일
-d file 디렉토리
-c file 문자 특수 파일
-b 2file 블록 특수 파일
-p file 파이프 파일
-u file 파일이 SUID(집합사용자 확인) 비트세트를 가진 경우
-g file 파일이 SGID(집합그룹확인) 비트 세트를 가진 경우
-k file sticky bit이 설정된 파일
-s file 비제로 길이를 가진 파일
-L file 심볼릭 링크 파일
-O file 파일의 주인이 effective user id인 경우
-G file 파일의 그룹이 effective user id인 경우
-S file socket 형태의 특수 파일인 경우
-t file file descriptor가 어떤 단말기와 연관된 개방된 파일 디스크립터인 경우
2) 스트링 연산자
string 스트링이 널이 아닌 경우
-n string 스트링이 널이 아닌경우
-z string 스트링이 널인 경우
string1 = string2 string1 과 string2 가 같은 경우
string1 != string2 string1 과 string2 가 같지 않은 경우
3) 정수 비교 연산자
int1 -eq int2 int1 이 int2 와 같은 경우
int1 -ge int2 int1 이 int2 와 같거나 그보다 큰경우
int1 -gt int2 int1 이 int2 보다 큰경우
int1 -le int2 int1 이 int2 와 같거나 작은 경우
int1 -lt int2 int1 이 int2 보다 작은 경우
int1 -ne int2 int1 이 int2 와 같지 않은 경우
4) 부울 연산자
!expr expr이 FALSE
expr1 -a expr2 expr1이 TRUE, 그리고 expr2가 TRUE
expr1 -o expr2 expr1이 TRUE 혹은 expr2가 TRUE
Examples:
$ test -x file -a ! -d file
-> file이 실행 가능하고 디렉토리가 아닌 경우
$ test "x$1" = xabc
-> $1이 abc인 경우
$ [ "x$1" = xabc ]
-> $1이 abc인 경우
$ test ! ( -w file -o -x file )
-> file 이 쓸 수 있거나 실행 가능한 파일이 아닌경우
$ [ ! ( -w file || -x file ) ]
-> file 이 쓸 수 있거나 실행가능한 파일이 아닌경우
8. 내장된 정수 연산
1) 정수 연산
일반적인 대부분의 수식 연산을 ksh 에서는 지원하고 있다. 다음은 ksh에서 지원 되는 연산자들이다.
- 단항 -
~ NOT
! 논리부정
* , / , % 곱하기, 나누기, 나머지
+ , - 더하기, 빼기
<< , >> 왼쪽 시프트, 오른쪽 시프트
< , > , <= , >= 비교
== , != 동등, 비동등
& 그리고
^ 배타적 또는
| 또는
&& 논리적 and
|| 논리적 or
= 배정
2) let 명령
Korn쉘은 expr 명령없이 정수 연산을 수행하기 위한 메커니즘을 제공하고 있는데 그것이 let 명령이다. let은 쉘에 내장되어 있기 때문에 계산을 위한 새로운 과정을 만들거나 찾거나 프로그램을 로딩할 필요도 없다. let의 형식은
$ i=100
$ let i = i + 1
$ echo $i
101
$
$ let ' i = i + 1 ' 'j = j + 10'
개별적인 식들이 중간에 공백으로 가지고 있다면 인용부호로 묶어서 사용해야하며 이것은 수식 쉘로부터의 *, &, <, > 와 같은 문자들이 가지는 특별한 의미를 제거하는 부가적 효과를 가진다.
$ let 'i = ( i + 10 ) * j '
둥근 괄호를 이용하여 수식을 그룹화할 수도 있다.
3) (( expression ))
(( expression )) 은 let "expression" 과 같은 의미이다. 쌍으로된 둥근 괄호를 이용하여 let에 대한 대안적 형식을 취할수 있다.
$ (( i = i * 5 ))
$ (( i >= 0 && i <= 100 ))
4) expr
expr 명령을 사용하여 수식 계산을 실행한 후에 변수에 그 값을 지정한다.
Examples:
$ aa=10
$ aa=`expr $aa + 10`
$ echo $aa
20
$
5) integer variable
수식계산에 사용되는 변수를 정수로 선언하여 일반적인 형태의 수식계산 방식을 ksh에서 사용하도록 지정한다. 하지만 이렇데 지정된 변수는 반드시 정수 값만 가질수 있다.
Examples:
$ integer aa
$ aa=100
$ aa=aa+1
$ echo $aa
101
$ aa="test a integer variable"
ksh: aa: bad number
$
9. 배열
Korn쉘은 제한된 배열 능력을 제공한다. 배열은 1차원으로 512요소를 가지며, 배열의 인덱싱은 0에서 시작하고 511까지 지정할수 있다.
배열의 요소는 한쌍의 각괄호( [ ] ) 안에 넣어진 정수값으로 된 색인첨자와 함께 호출되는 것으로 자신이 요구하는 만큼 요소에 값을 할당하여 사용한다.
$ arr[0]=hello
$ arr[1]="some text"
$ arr[2]=/home/dgk/memos
배열로부터 값을 불러오는 방법은 배열의 이름과 각 괄호안에 원하는 요소의 번호를 넣고 그것을 ${ }에 넣어 사용한다.
$ echo ${arr[0]}
hello
$ echo ${arr[2]}
/home/dgk/memos
$ echo $arr
hello
-> 첨자가 없는 경우 요소 0이 이용된다.
$ echo $arr[1]
hello[1]
-> { }을 사용하지 않고 출력한 경우 예상치 않은 결과 값을 출력한다.
$
$ echo ${arr[*]}
hello some text /home/dgk/memos
-> 배열에 들어있는 모든 내용을 불러 온다
$
$ echo ${#arr[*]}
3
-> 배열 arr에 있는 요소들의 갯수. 이때 수는 실제 요소의 갯수가 아니고 가장 큰 첨자 + 1 한 값이 출력된다. 이 값은 배열안에 다음 요소를 저장하기 위한 첨자로 사용된다.
$
$ arr[10]=foo
$ echo ${arr[*]}
hello some text /home/dgk/memos foo
$ echo ${#arr[*]}
11
-> 사용자가 정수 명령을 배열명에 선언해 줌으로써 Korn쉘에게 정수 배열을 선언하게 한다.
$ integer arr
$ arr[0]=100
$ arr[1]=50
$ (( arr[2] = arr[0] + arr[1] ))
$ echo ${arr[2]}
150
$
배열구성요약
${array[i]} 요소 i 값을 치환
$array 첫번째 요소 array[0]값을 치환
${array[*]} 모든 요소값을 치환
${#array[*]} 요소들의 수를 치환
array[i]=value value을 array[i]로 치환
10. 함수 정의
ksh에서의 function명령은 name ( ) { ....; } 형식으로 선언된다. 기능을 분류하거나 순환적으로 일어나는 일들을 하나의 변수 형식으로 지정하여 불러 사용할 수 있도록 한다.
function identifier
{
compound-list
}
identifier( )
{
compound-list
}
Examples: 등록된 사용자수를 세는 nu 라는 함수를 정의한다.
$ function nu
> {
> who | wc -l
> }
$ nu
13
$
$ cat funt1
function check_yesno
{
typeset -l reply
while true
do
read -r "reply?$1? " || return 1
case $reply in
y|yes} return 0;;
n|no) return 1;;
*) print 'please answer y or n';;
esac
done
}
while check_yesno 'Do you want to continue? '
do
foobar
done
$
일반적으로 정의된 함수는 서브쉘에 보내지지 않는다. 하지만 typeset이라는 명령을 사용하여 함수정의를 export 시킬 수 있다.
$ typeset -fx funtion-name
-> function-name을 주지 않으면 엑스포트된 함수들의 명단을 출력한다.
$ typeset -f -> 정의된 함수의 리스트를 출력한다.
funcrion nu
{
who | wc -l
}
$
함수정의 삭제
함수정의를 삭제하기 위해 -f 옵션을 가진 unset명령을 사용한다.
$ type nu
nu is a function
$ unset -f nu
$ type nu
ksh: nu: not found
$
11. 변수의 속성 정의
매개변수의 종류는 앞에서 키워드 매개변수, 위치매개변수, 특수매개변수로 나누어 설명하였다. 이런 각각의 변수는 하나 또는 그 이상의 특성을 정의할 수 있으며 typeset 이라는 명령어를 사용하여 변수의 특성을 on/off 하거나 설정되어 있는 내용을 리스트할 수 있다.
Command: typeset [-options] vasriable
Options:
-u Uppercase 소문자를 대문자로 변환한다. -l 옵션은 자동적으로 off된다
$ typeset -u x=abc
$ print $x
ABC
-l Lowercase 대문자를 소문자로 변환한다. -u 옵션은 자동적으로 off 된다.
$ typeset -l x=ABC
$ print $x
abc
-i or -ibase Integer 정수 변수로 정의된다. base는 수의 진법 정의
$ integer x=6
$ typeset -i8 y=x+x
$ print $y
8#14
-L or -Lwidth Left-justified 앞에오는 공란들을 왼편 자리 맞춤시키고 스트립 시킴. width가 비제로로 정의 되어 있으면 자리수를 width로 설정한다. -R옵션은 자동적으로 off된다.
$ typeset -L3 x=abcd y
$ y=3
print "$y-$x"
3 -abc
-LZ or -LZwidth Strip Leading Zero 앞에오는 제로들은 스트립되고 왼편으로 자리 맞춤한다.
$ typeset -LZ3 x=abcd y
$ y=03
print "$y-$x"
3 -abc
-R or -Rwidth Right-justified 오른편 자리 맞춤시키고 스트립시킴. width가 비제로인 경우 자리수를 width 로 설정.
$ typeset -R3 x=abcd y
$ y=3
$ print "$y-$x"
3-bcd
-Z or -Zwidth Zero-filled
-RZ or -RZwidth Zero-filled
-Z만 설정된 경우 -L 옵션이 굛 되어있지 않다면 오른편로 자리 맞춤 시키고 스트립시킨다. width가 비제로 값이면 자리수를 width로 설정한다. 만약 처음의 비공란 문자가 숫자이면 0으로 채워진다.
$ typeset -Z3 x=abcd y
$ y=3
$ print "$y-$x"
003-bcd
-r Read-only 변수가 읽기전용으로 설정되어 있다면 그 변수값을 변경하려 하면 에러 메세지를 출력하고 변경이 불가능하다.
$ typeset -r foo=bar
$ foo=nobar
ksh: foo: is read only
$ unset foo
ksh: foo: is read only
-x Exported 모든 변수에 값이 설정되면 자동적으로 현재 환경에 값을 배당한다.
$ typeset -x foo=bar
$ export foo=bar
12. 패턴
[ . . . ] 부호 문자들을 정의하여 그중 어느 하나의 문자와 일치하는 패턴 정의할수 있다. ' - ' 부호를 사용하여 범위를지정 할수 있다. ' ! ' 부호를 사용하여 역으로 매치 시킬수도 있다.
$ ls
chap1 chap10 chap11 chap2 chap3 chapa chapb chapc
$ ls chap[123]
chap1 chap2 chap3
$ ls chap[12][01]
chap10 chap11
$ ls chap[!2-4]
chap1
$ ls chap[1-3]
chap1 chap2 chap3
? 문자 어떤 문자이든 상관없이 한 문자와 매치 된다
$ ls chap?
chap1 chap2 chap3
chapa chapb chapc
* 문자 어떤 문자든 0번 또는 그 이상과 매치
$ ls chap*
-> chap 으로 시작되는 모든 스트링
$ ls x*y
-> x로 시작하고 y로 끝나는 모든 스트링
?(pattern[|pattern]...) 패턴 0번 또는 한번 발생되는 pattern과 매치
$ ls para?([345]|99)1
-> para1, para31, para41, para51, para991 과 매치
*(pattern[|pattern]...) 패턴 0번 이상 발생되는 pattern과 매치
$ ls para*([0-9])
-> para, para뒤에 어떤 숫자라도 붙어 있는 스트링과 매치
+(pattern[|pattern]...) 패턴 1번 이상 발생되는 pattern과 매치
$ ls para+([0-9])
-> para뒤에 숫자가 붙어 있는 모든 스트링과 매치
@(pattern[|pattern]...) 패턴 정확히 한번 발생되는 pattern과 매치
$ ls para@(chute|graph)
-> parachute, paragraph 과 매치
!(pattern[|pattern]...) 패턴 pattern에 정의된것을 제외한 모든것과 매치
$ ls para!(*.[0-9])
-> para로 시작하고 .숫자로 끝나지 않는 모든 스트링과 매치
13. 조건문
[ [ test-expression ] ] 또는 [ test-expression ] 기호
test 명령을 대신하여 테스트하는데 사용할 수 있다.
$ [ [ foo > bar && $PWD -ef . ] ] && print foobar
foobar
1) if . . . then . . . else . . . fi
if 는 일반적으로 3가지 패턴으로 사용할수있다.
형식1:
if test -f $1
then
echo $1 exist
fi
형식2:
if test -f $1
then
echo $1 exist
else
echo $1 does not exist
fi
형식3:
if (( score < 65 )
then grade=F
elif (( score < 80 )
then grade=C
elif (( score < 90 )
then grade=B
else grade=A
fi
Examples:
if print 'Please enter your name: c' ; read -r name
then if mail "$name" < mailfile
then :
else print "Cannot mail to $name"
fi
else print 'end-of file'
exit 1
fi
2) case
case word in
[ ( ) pattern [ | pattern.... ] ... ] compound-list ;; ]
. . . .
esac
word와 매치되는 pattern을 찾아서 해당되는 compound-list를 실행한다.
Examples:
$ cat case1
case $x in
-d*) dflag=1;;
-e*) eflag=1;;
"") print -r -u2 - "x must have a value";;
*) if test ! -r "$x"
then print -r - "$x: no read permission"
fi ;;
esac
$ cat case2
read -r line
case $line in
[$1]*) : ;; # ok
*) print 'Line must begin with one of: $1"
exit 1;;
esac
14. 반복
1) for 문
for identifier [ in word .... ]
do compound-list
done
word의 개수만큼 do와 done사이의 명령어들을 반복적으로 실행한다
Examples:
$ cat for1
for i in apple banana mango
do
echo "$it"
done
$
$ for1
apple banana mango
$
$ cat for2
for i in * ## 현재 디렉토리의 모든 파일
do
if test -d "$i"
then print -r - "$i"
fi
done
다음 예제는 트럼프 놀이를 쉘 스크립트로 작성한 것이다. 한번 <Enter> 키를 칠 때 마다 카드 번호를 한 장씩 출력해준다. 총 7장의 카드를 출력해준다.
$ cat for3
integer i=0 ; typeset -u card
echo "Gamer I : 이름을 입력하시오: c"
read gamer01
echo "Gamer II : 이름을 입력하시오: c"
read gamer02
echo "카드를 섞고 있습니다"
for suit in clubs diamonds hearts spades
do
for n in ace 2 3 4 5 6 7 8 9 10 jack queen king
do
card[i]="$n of $suit"
i=i+1
done
done
echo "게임을 시작하겠습니다"
for gamer in $gamer01 $gamer02
do
echo "$gamer: c"
i=0
while [ $i -le 7 ]
do
read
echo " ${card[RANDOM%52]} t"
i=i+1
done
echo
done
2) select문
select identifier [ in word .... ]
do compound-list
done
나열하는 word를 화면에 메뉴 형태로 표준 출력 화면으로 출력해 주고, 표준 입력으로부터 무한 반복으로 값을 입력 받는다. 값을 입력 받기위해 프롬프트를 출력해 주는데 디폴트 프롬프트는 '?' 이다. 프롬프트는 환경변수 PS3에서 지정할 수 있다.
Examples:
$ cat select1
PS3='Please enter a number: '
select i in add delete modify list exit
do
case $i in
add|modify)
print Select editing file
break;;
delete)
print Select removing job;;
list)
print Select display job;;
exit)
print Select exit job
print Good-bye
exit ;;
*) print 'Invalid number';;
esac
done
$ select1
1) add
2) delete
3) modify
4) list
5) exit
Please enter a number:_
3) while문
while test문 또는 명령어 실행
do compound-list
done
while 반복문은 test문 또는 명령의 실행결과가 참(true)인 동안 루틴을 반복적으로 수행한다.
Examples:
$ cat while1
while read -r line
do
print -r - "$line"
done
$ cat while2
while [ $line -le $maxline ]
do
echo >> $BUFFER
lines=`expr $lines + 1`
done
$ cat while3
while true
do
read name
if [ ${name}x = x ]
then
break
fi
done
4) until 문
until test문 또는 명령어 실행
do compound-list
done
test문 또는 명령 실행결과가 거짓(false)인 경우 루틴을 반복 수행한다.
Examples:
$ cat until1
until cc -c foo.c
do vi foo.c
done
$ cat until2
until who | grep klog >/dev/null
do
echo waiting 5 seconds
sleep 5
done
echo klog has logged on
$ cat until3
until false
do
read name
if [ ${name}x = x ]
then
break
fi
done
15. 흐름 제어
1) break [ n ]
이 명령의 실행은 가장 안쪽 n개의 for, while, until 루프의 실행이 즉시 종료시키고 빠져 나오며 루프다음의 명령을 계속 실행한다.
Examples:
$ cat break1
for i in *
do
for j in foo bar bam
do
if test "$j" = "$i"
then
break 2
fi
done
done
2) continue [ n ]
for, while, until 루프안에서의 이명령의 실행은 continue 다음에 오는 임의의 명령들이 skip 되도록 한다.
Examples:
$ cat continue1
for i in *
do
if test -d "$i"
then continue
fi
print -r - "$i is not a directory"
done
$
16. 쉘 프로그래밍 응용
1) vi with backup the file
vi 편집기를 호출하여 파일을 편집하여 저장하기전 이전의 파일을 filename.bak 파일에 저장하도록 하는 쉘 스크립트를 작성한다.
$ cat vvi
#!/usr/bin/ksh
#
if [ $# -le 0 ]
then
vi
exit
fi
cp $1 ${1}.tmp
vi $1
if cmp -s $1 ${1}.tmp
then
rm ${1}.tmp
else
cp ${1}.tmp ${1}.bak
rm ${1}.tmp
fi
2) newcat
출력용 필터인 newcat 을 생성한다. 내용의 각 라인에 라인번호를 붙여서 23개 라인씩 출력한다.
$ cat newcat
#!/usr/bin/ksh
if [ $# -lt 1 ]
then
echo "Usage Error: newcat filenames... " ; exit
fi
for filename in $*
do
integer count=1
integer page=1
exec < $filename
echo "Filename : $filenamettPage: $page "
while read line
do
if [ $count -eq 22 ]
then
echo "--More-- <Press Return> "
read
echo "f"
page=page+1
echo "Filename : $filenamettPage: $page "
fi
echo "$countt$line"
count=count+1
done
done
3) exec_check 실행 점검 스크립트
program_01 이라는 프로그램을 실행하는 스크립트를 작성한다. 이미 이 프로그램이 실행중이라면 30초간 대기하면서 이미 실행중인 프로그램의 실행종료를 대기한다. 대기중 실행종료가 확인되면 프로그램을 실행시킨다. 30초가 초과되면 타임아웃으로 인식하고 메시지를 출력하고 스크립트를 종료한다.
$ cat exec_check
#!/usr/bin/ksh
#
trap "echo off > ex_check_file; echo "인터럽트 수신/종료"; exit 200" 2
if [ $# -ne 1 ]
then
echo "실행할 프로그램명이 입력되지 않았습니다"
echo "USAGE: exec_check program-name"
exit
fi
if [ ! -f ex_check_file ]
then
echo off > ex_check_file
fi
integer count=0
while read e_flag < ex_check_file; [ e_flag = 'on' ]
do
echo "$1 프로그램이 실행중입니다. 프로그램 종료 대기중..."
sleep 5
count=count+1
if [ $count -eq 6 ]
then
echo "TIME OUT...."
echo "$1 프로그램이 아직 실행중입니다"
echo "잠시후 다시 실행하여 주십시오"
echo "스크립트를 종료합니다"
exit
fi
done
echo on > ex_check_file
$1
echo off > ex_check_file
echo "$1 프로그램 실행을 정상 종료합니다"
4) 웹으로 finger을 실행하게 하는 CGI 프로그램
#!/bin/sh !/usr/bin/ksh
FINGER=/usr/bin/finger
echo Content-type: text/html
echo
if [ -x $FINGER ]
then
if [ $# -eq 0 ]
then
cat << EOM
<HTML>
<HEAD><TITLE>Finger Gateway</TITLE></HEAD>
<BODY>
<H1>Finger Gateway</H1>
<ISINDEX>
This is a gateway to "finger". Type a user@host combination in your browser's search dialog.<P>
EOM
else
echo <PRE>
$FINGER "$*"
echo </PRE>
fi
else
echo Cannot find finger on this system.
fi
cat << EOM
</BODY></HTML>
EOM
by 딸기아부지 | 2007/04/04 09:33 | 리눅스관련 | 트랙백
순환고리 검색 (start with .... )
SELECT LPAD(' ', LEVEL*4) || ORG_NM
FROM ICD_INTG_ORG
START WITH INTG_ORG_ID = '0000019499' --여기서부터 시작하라는 순환고리의 시작을 선언
CONNECT BY PRIOR INTG_ORG_ID = HIGH_INTG_ORG_ID -- 검색의 대상을 prior로 해서 그 부분을 tree형태로 검색
ORDER SIBLINGS BY INTG_ORG_ID --검색한 순서대로 보고 싶을때 사용 oracle 9i 이상에서만 가능


* PRIOR 의 위치
1. CONNECT BY PRIOR 자식컬럼 = 부모컬럼 ==> 부모에서 자식으로 트리 구성
2. CONNECT BY 자식컬럼 = PRIOR 부모컬럼 ==> 자식에서 부모으로 트리 구성

* WHERE 절의 조건과 CONNECT BY에서 의 조건 비교

1. 조직 명이 '본부' 명을 가지면 출력 안함
SELECT LPAD(' ', LEVEL*4) || ORG_NM
FROM ICD_INTG_ORG
WHERE ORG_NM NOT LIKE '%본부%'
START WITH INTG_ORG_ID = '0000019499'
CONNECT BY PRIOR INTG_ORG_ID = HIGH_INTG_ORG_ID

2. 조직 명이 '본부' 명 이면 그 이하 조직 모두 출력 안함
SELECT LPAD(' ', LEVEL*4) || ORG_NM
FROM ICD_INTG_ORG
START WITH INTG_ORG_ID = '0000019499'
CONNECT BY PRIOR INTG_ORG_ID = HIGH_INTG_ORG_ID
AND ORG_NM NOT LIKE '%본부%'
by 딸기아부지 | 2007/03/23 21:38 | DB관련 주워온 글 | 트랙백 | 핑백(1)
오라클 백업 및 복구 설명
네이버 블로그 :: 포스트 내용보기








document.domain = 'naver.com';
var url_admin = 'http://admin.blog.naver.com';
var url_blog = 'http://blog.naver.com';
var url_prologue = 'http://prologue.blog.naver.com';
var url_lifelog = 'http://lifelog.blog.naver.com';
var url_memolog = 'http://memolog.blog.naver.com';
var url_photolog = 'http://photolog.blog.naver.com';
var url_section = 'http://section.blog.naver.com';
var url_profile = 'http://profile.blog.naver.com';
var url_guestbook = 'http://guestbook.blog.naver.com';
var url_event = 'http://event.blog.naver.com';
var url_blogrss = 'http://blog.rss.naver.com';
var url_caferss = 'http://cafe.rss.naver.com';
var url_boomrss = 'http://boom.rss.naver.com';
var url_photorss = 'http://photo.rss.naver.com';
var url_bridge = 'http://blogbridge.naver.com';
var url_bloglab = 'http://bloglab.naver.com';
var url_upblog = 'http://up.blog.naver.com';
var url_upprofile = 'http://upprofile.blog.naver.com';
var url_upmemolog = 'http://upmemolog.blog.naver.com';
var url_upphotolog = 'http://upphotolog.blog.naver.com';
var url_upguestbook = 'http://upguestbook.blog.naver.com';
var url_images = 'http://blogimgs.naver.com';
var url_attach = 'http://blogfiles.naver.net';
var url_attachmpeg = 'mms://stream.media.naver.com';
var url_mpegthumbnail = 'http://thumb.media.naver.com';
var url_iaattach = 'http://iafiles.naver.net';
var url_upia = 'http://upia.blog.naver.com';
var url_upia1 = 'http://upia1.blog.naver.com';
var url_upia2 = 'http://upia2.blog.naver.com';
var url_thumbnail2 = 'http://blogthumb2.naver.net';
var url_skin = 'http://blogimgs.naver.com/skin';
var url_skin_layout_img = 'http://blogimgs.naver.com/skin';
var url_skin_item_img = 'http://itemimgs.naver.com';
var url_personacon = 'http://itemimgs.naver.com/personacon';
var url_item = 'http://item.naver.com';
var url_item2 = 'http://item2.naver.com';
var url_itemfactory = 'http://factory.blog.naver.com';
var url_factory_bridge = 'http://bridge.factory.blog.naver.com';
var url_itemsimgs = 'http://itemsimgs.naver.com';
var url_itemimgs = 'http://itemimgs.naver.com';
var url_cafe = 'http://cafe.naver.com';
var url_mail = 'http://mail.naver.com';
var url_cafeattach = 'http://cafefiles.naver.net';
var url_photo = 'http://new.photo.naver.com';
var url_boom = 'http://boom.naver.com';
var url_play = 'http://play.naver.com';
var url_blink = 'http://blink.naver.com';
var url_blink_bridge = 'bridge.blink.naver.com';
var url_blink_prore = 'prore.blink.naver.com:10006';
var url_prore = 'http://prore.naver.com:14080';
var url_cacheserver = '218.145.30.39';
var url_toon = 'http://toon.naver.com';
var url_kitchen = 'http://kitchen.naver.com';
var url_kitchen_rpc = 'http://kitchen.naver.com/outer_interface/getBlogRecipe.nhn';
var url_lcs = 'http://lcs.naver.com';
var url_id = 'http://nid.naver.com';
var url_kin = 'http://kin.naver.com';
var url_help = 'http://help.naver.com';
var url_messenger = 'http://messenger.naver.com';
var url_krdic = 'http://krdic.naver.com';
var url_endic = 'http://endic.naver.com';
var url_jpdic = 'http://jpdic.naver.com';
var url_book = 'http://book.naver.com';
var url_bookinfo = 'http://book.naver.com';
var url_booksearch = 'http://xmlbook.search.naver.com';
var url_musicsearch = 'http://xmlmusic.search.naver.com';
var url_musicinfo = 'http://music.naver.com';
var url_moviesearch = 'http://xmlmovie.search.naver.com';
var url_movieinfo = 'http://movie.naver.com';
var url_shoppingsearch_main = 'http://a51552.nhncorp.com';
var url_shoppingsearch_sub = 'http://a50894.nhncorp.com';
var url_shoppinginfo = 'http://shopping.naver.com';
var url_static = 'http://static.naver.com';
var url_happybean = 'http://happybean.naver.com';
var url_happylog = 'http://happylog.naver.com';
var url_note = 'http://note.naver.com';
var url_mailsocket = 'han255.naver.com';
var url_besetosocket = 'beseto.blog.naver.com';
var url_besetoupdateurl = '/updatehub/UpdateHUB.nhn';
var url_tag = 'tagreal';
var url_publictag = 'http://tag.blog.naver.com';
var url_spamfilter = '222.122.84.164';
var url_factory = 'http://factory.blog.naver.com';



/***************************************************************
본 스크립트 파일에서 선언하는 함수는 반드시 'cm_'를 함수명 앞에 붙인다.
****************************************************************/

//addec by mj.chong 2006.12.06
//tag 금칙 문자 (%, &, +, <, >, ?, /, \, ', ", =, \n)
//comma는 별로도 제외하는 로직이 있음
var restrictedTagChars = /[\x25\x26\x2b\x3c\x3e\x3f\x2f\x5c\x27\x22\x3d]|(\x5c\x6e)/g;

var IE = false ;
if (window.navigator.appName.indexOf("Explorer") !=-1)
{
IE = true;
}

// Iframe 내에서 호출하여 페이지 높이를 맞춘다.
function cm_paperInit(minHeight)
{
try
{
var timeArray = new Array(200, 500, 1500, 3500, 7000, 12000, 20000);
//alert("1_cm_paperInit, timeArray.length="+timeArray.length);
for(var i=0; i < timeArray.length; i++)
setTimeout('_cm_paperInit(\''+minHeight+'\')', timeArray[i]);

if(self.name!=null && self.name=="papermain")
{
top.window.scrollTo(0,0);
}
}catch (e) {}
}

// Iframe 내에서 호출하여 페이지 높이를 맞춘다.
// 최대 하위 3단까지만 리사이징을 하도록 한다.
function _cm_paperInit(minHeight)
{
try
{
// alert("2_cm_paperInit");
if(minHeight==null) minHeight = 0;
if (self.name!=null && self.name!="" && parent!=null
&& parent._cm_resizeIframe!=null)
{
parent._cm_resizeIframe(self.name, minHeight);
}

if (parent.name!=null && parent.name!=""
&& (parent.name=="papermain" || parent.name=="mainFrame")
&& parent.parent!=null && parent.parent._cm_resizeIframe!=null && parent.parent._cm_paperInit!=null)
{
parent.parent._cm_resizeIframe(parent.name, minHeight);
}

if (parent.parent.name!=null && parent.parent.name!=""
&& (parent.parent.name=="papermain" || parent.parent.name=="mainFrame")
&& parent.parent.parent!=null && parent.parent.parent._cm_resizeIframe!=null && parent.parent.parent._cm_paperInit!=null)
{
parent.parent.parent._cm_resizeIframe(parent.parent.name, minHeight);
}
}catch (e) {}
}

// 직접사용은 금함. cm_paperInit()를 사용할것.
function _cm_resizeIframe(name, minHeight)
{
//alert("cm_resizeIframe, name="+name);
if(minHeight==null) minHeight = 0;
if(name==null || name=="") return;

try
{
if (IE)
var oBody = document.frames(name).document.body;
else
var oBody = document.getElementById(name).contentDocument.body;

var oIFrame = document.getElementById(name);

var frmWidth = oBody.scrollWidth;// + (oBody.offsetWidth - oBody.clientWidth);
var frmHeight = oBody.scrollHeight;// + (oBody.offsetHeight - oBody.clientHeight);

if(name=="papermain" || name=="mainFrame")
{
if(frmHeight >= 500)
oIFrame.style.height = frmHeight;
else
oIFrame.style.height = 500;

var oOpacityDiv = document.getElementById("opacityDiv");
if(oOpacityDiv!=null)
{
oOpacityDiv.style.height = parseInt(oIFrame.style.height) + 200;
}
}
else
{
oIFrame.style.height = frmHeight;
}

// 무료스킨 좌측2단의 경우. 포스트폭 사이지를 조절한다.
if(applyResizeContentWidth)
{
if(frmWidth > 590) oIFrame.style.width = frmWidth;
//else oIFrame.style.width = 590;
}

}catch (e) {}
}

// 외부 페이지를 Iframe으로 호출할 경우에 외부페이지에서 호출하기 위한 함수.
function cm_paperInitExternal(name, minHeight)
{
try
{
//alert("cm_paperInitExternal, name="+name);
var timeArray = new Array(200, 500, 1500, 3500, 7000, 12000, 20000);
for(var i=0; i < timeArray.length; i++)
{
setTimeout('_cm_paperInitExternal(\''+name+'\',\''+minHeight+'\')', timeArray[i]);
}
}catch (e) {}
}

// Iframe 내에서 호출하여 페이지 높이를 맞춘다.
// 최대 하위 3단까지만 리사이징을 하도록 한다.
function _cm_paperInitExternal(name, minHeight)
{
try
{
if(minHeight==null) minHeight = 0;

if (name!=null && name!='')
{
_cm_resizeIframe(name, minHeight);
}
if (self.name!=null && self.name!=''
&& (self.name=="papermain" || self.name=="mainFrame")
&& parent!=null && parent._cm_resizeIframe!=null)
{
parent._cm_resizeIframe(self.name, minHeight);
}
if (parent.name!=null && parent.name!=''
&& (parent.name=="papermain" || parent.name=="mainFrame")
&& parent.parent!=null && parent.parent._cm_resizeIframe!=null)
{
parent.parent._cm_resizeIframe(parent.name, minHeight);
}
}catch (e) {}
}

/* onLoad Handler */
LOAD_LIST = new Array();
function LH_create()
{
this.LIST = LOAD_LIST;
this.add = LH_add;
this.exec = LH_exec;
}

function LH_add(strExec)
{
LOAD_LIST[LOAD_LIST.length] = strExec;
}

function LH_exec()
{
var list_len = LOAD_LIST.length;
for (var i = 0; i < list_len; i++)
{
try {eval(LOAD_LIST[i]); }catch(e){}
}
}





function cm_imageZoom(url)
{
window.open("/common/util/imageZoom.jsp?url="+url,"imageZoom","scrollbars=no,width=100,height=100");
}

//============================================================================
// 아래의 함수를 사용할 경우 연락바람. by jhhany.
//============================================================================




function reSize()
{
var ParentFrame = papermain.document.body;
var ContentFrame = document.all["papermain"];
ContentFrame.style.height = ParentFrame.scrollHeight + (ParentFrame.offsetHeight - ParentFrame.clientHeight) + 100;
//ContentFrame.style.width = ParentFrame.scrollWidth + (ParentFrame.offsetWidth - ParentFrame.clientWidth);
}

function paperInit()
{
parent.reSize();
//parent.document.location.href = '#';
}

function settop()
{
/* var topurl = document.location.href;
if (topurl.indexOf('#') > 0)
document.location.href = document.location.href;
else
document.location.href = document.location.href + '#';*/
window.scrollTo(0,0);
}


// 팝업 관련 함수 최용철 20050531 추가
function open_window(url, name, width, height, feature)
{
var oWnd;

if (IE && width < window.screen.width && height < window.screen.height)
{
var windowX = Math.ceil( (window.screen.width - width) / 2 );
var windowY = Math.ceil( (window.screen.height - height) / 2 );

oWnd = window.open(url, name, feature+",width=" + width +",height=" + height+",left="+windowX+",top="+windowY + ",resizable=yes");
}
else
{
oWnd = window.open(url, name, feature+",width=" + width +",height=" + height + ",resizable=yes");
}

return oWnd;
}
//Object Tag for ActiveX
function diplayDynamicObjectforSkin(_objPath_)
{
var _object_ = "";

_object_= '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';

document.write(_object_);
}
function displayStaticFlashMovie()
{
var _object_ = "";
_object_= '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';

document.write(_object_);
}
function displayMultiMediaPlayer()
{
var _object_ = "";

_object_= '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';

document.write(_object_);
}
function loadingUCCModule(programLink, userId)
{
var _object_ = "";

_object_= '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';
_object_ += '';
document.write(_object_);
}

function appendActiveX(_str)
{
var _object_ = _str;
document.write(_object_);
}

//============================================================================
// 포토로그에서 사용
// 기존의 musiciframe을 대체하기 위한 객체
// 포스트 삽입된 BGM에서의 명령을 hFrame에 전달해 주기 위한 다리 역할을 함
//============================================================================
function MusicIFrame(){
// 포스트 BGM 재생
this.PlayPost = function(idx, bgmlist, obj)
{
top.hiddenFrame.PlayPost(idx, bgmlist, obj);
}
// 포스트 BGM 재생 (첫번째곡)
this.PlayPost1 = function(idx, bgmlist, obj)
{
top.hiddenFrame.PlayPost1(idx, bgmlist, obj);
}
// 포스트 BGM 중지
this.StopPost = function()
{
top.hiddenFrame.StopPost();
}
// 이전곡
this.PrevPost = function()
{
top.hiddenFrame.PrevPost();
}
// 다음곡
this.NextPost = function()
{
top.hiddenFrame.NextPost();
}
}
var musiciframe = new MusicIFrame();

String.prototype.trim = function()
{
return this.replace(/(^\s*)|(\s*$)/g, "");
}
function validTag(tagObj, e)
{
var tagVal = tagObj.value;
var commacnt = 0;
var key = window.event ? e.keyCode : e.which;

if(tagVal.charAt(tagVal.length-1) == ',' && (key == 44 || key == 32))
return false;
for(var i=0; i < tagVal.length; i++) {
if(tagVal.charAt(i) == ',') {
commacnt++;
}
if(commacnt >= 9) {
alert("태그는 최대 10개까지 입력할 수 있습니다.");
return false;
}
}

if (key != 0x2C && (key > 32 && key < 48) || (key > 57 && key < 65) || (key > 90 && key < 97))
return false;
}

function check_tagvalidate(aEvent, input)
{

var keynum;
if(typeof aEvent=="undefined") aEvent=window.event;
if(IE)
{
keynum = aEvent.keyCode;
}
else
{
keynum = aEvent.which;
}
//edited by mj.chong 20061206
//if(keynum == 188 ) {
// input.value = BlogTag.validateTagString(input.value);
//}
// %, &, +, -, ., /, <, >, ?, \n, \ |
var ret = input.value;
if(ret.match(restrictedTagChars) != null ) {
ret = ret.replace(restrictedTagChars, "");
input.value=ret;
}
//콤마가 연속으로 있으면 하나로 만든다.
re = /[\x2c][\x2c]+/g;
if(ret.match(re) != null ){
ret = ret.replace(re, ",");
input.value=ret;
}
highlightMyTag();

}

function check_tagsvalidate(input)
{
input.value = BlogTag.validateTagString(input.value);

//중복되는 태그 제거
input.value = BlogTag.eliminateDuplicate(input.value);

var tagcount = BlogTag.length(input.value);
highlightMyTag();
//태그 수 제한
if(tagcount > 10)
{
alert("태그는 최대 10개 까지 입력이 가능합니다.");
input.value = BlogTag.absoluteTagString(input.value, 10);
input.focus();

return;
}


//태그의 길이 제한
var bvalidate;
var tagmaxlength = 100;
bvalidate = BlogTag.isValidateTagLength(input.value, tagmaxlength);

if(!bvalidate)
{
alert("태그는 100자 이상 입력할 수 없습니다.");
input.focus();
return;
}
}

var BlogTag =
{
//유효한 태그명인지 확인.
isTagname : function(tagname)
{
return tagname.match(restrictedTagChars)==null;
}
,

//태그 문자열을 유효하게 만든다.( 금지문자 제거, 연속되는 컴마 제거 )
validateTagString : function(tagstring)
{
var ret = tagstring.replace(restrictedTagChars, "");

//콤마가 연속으로 있으면 하나로 만든다.
re = /[\x2c]+/g;
return ret.replace(re, ",");
}
,

absoluteTagString : function(tagstring, maxcnt)
{
var valitags = BlogTag.validateTagString(tagstring);

var arraytag = valitags.split(",");

var tagnames = "";

var absolutecnt = arraytag.length;
if(absolutecnt > maxcnt)
absolutecnt = maxcnt;

for(var i=0; i< absolutecnt; i++)
{
tagnames = tagnames + arraytag[i] + ",";
}
tagnames = BlogTag.validateTagString(tagnames);

tagnames = tagnames.substring(0, tagnames.length-1);

return tagnames;
}
,

//중복되는 태그를 없앤다.
eliminateDuplicate : function(tagstring)
{
var valitags = BlogTag.validateTagString(tagstring);

var arraytag = valitags.split(",");

var tagnames = "";

for(var i=0; i {
for(var j=0; j {
//이미 존재 하는 태그라면 없앰.
if(arraytag[j]==arraytag[i])
{
arraytag[i]="";
}
}

tagnames = tagnames + arraytag[i] + ",";

}
tagnames = BlogTag.validateTagString(tagnames);

tagnames = tagnames.substring(0, tagnames.length-1);

return tagnames;

}
,

//태그수 를 계산 한다.
length : function(tagstring)
{
var arraytag = tagstring.split(",");

return arraytag.length;
}
,

//각 태그의 길이를 특정 크기 이하로 제한한다.
validateTagLength : function(tagstring, maxlen)
{
var arraytag = tagstring.split(",");
var tagnames = '';

for(var i=0; i {
if(arraytag[i].length > maxlen)
{
arraytag[i] = arraytag[i].substring(0, maxlen);
}
tagnames = tagnames + arraytag[i] + ",";
}

tagnames = tagnames.substring(0, tagnames.length-1);

tagnames = BlogTag.eliminateDuplicate(tagnames);

return tagnames;
}
,

//각 태그의 길이가 유효한지 확인한다.
isValidateTagLength : function(tagstring, maxlen)
{
var arraytag = tagstring.split(",");

for(var i=0; i {
if(arraytag[i].length > maxlen)
{
return false;
}
}

return true;
}
}

/* Function Equivalent to java.net.URLEncoder.encode(String, "UTF-8")
Copyright (C) 2002, Cresc Corp.
Version: 1.0
*/
function encodeURL(str){
var s0, i, s, u;
s0 = ""; // encoded str
for (i = 0; i < str.length; i++){ // scan the source
s = str.charAt(i);
u = str.charCodeAt(i); // get unicode of the char
if (s == " "){s0 += "+";} // SP should be converted to "+"
else {
if ( u == 0x2a || u == 0x2d || u == 0x2e || u == 0x5f || ((u >= 0x30) && (u <= 0x39)) || ((u >= 0x41) && (u <= 0x5a)) || ((u >= 0x61) && (u <= 0x7a))){ // check for escape
s0 = s0 + s; // don't escape
}
else { // escape
if ((u >= 0x0) && (u <= 0x7f)){ // single byte format
s = "0"+u.toString(16);
s0 += "%"+ s.substr(s.length-2);
}
else if (u > 0x1fffff){ // quaternary byte format (extended)
s0 += "%" + (oxf0 + ((u & 0x1c0000) >> 18)).toString(16);
s0 += "%" + (0x80 + ((u & 0x3f000) >> 12)).toString(16);
s0 += "%" + (0x80 + ((u & 0xfc0) >> 6)).toString(16);
s0 += "%" + (0x80 + (u & 0x3f)).toString(16);
}
else if (u > 0x7ff){ // triple byte format
s0 += "%" + (0xe0 + ((u & 0xf000) >> 12)).toString(16);
s0 += "%" + (0x80 + ((u & 0xfc0) >> 6)).toString(16);
s0 += "%" + (0x80 + (u & 0x3f)).toString(16);
}
else { // double byte format
s0 += "%" + (0xc0 + ((u & 0x7c0) >> 6)).toString(16);
s0 += "%" + (0x80 + (u & 0x3f)).toString(16);
}
}
}
}
return s0;
}

/* Function Equivalent to java.net.URLDecoder.decode(String, "UTF-8")
Copyright (C) 2002, Cresc Corp.
Version: 1.0
*/
function decodeURL(str){
var s0, i, j, s, ss, u, n, f;
s0 = ""; // decoded str
for (i = 0; i < str.length; i++){ // scan the source str
s = str.charAt(i);
if (s == "+"){s0 += " ";} // "+" should be changed to SP
else {
if (s != "%"){s0 += s;} // add an unescaped char
else{ // escape sequence decoding
u = 0; // unicode of the character
f = 1; // escape flag, zero means end of this sequence
while (true) {
ss = ""; // local str to parse as int
for (j = 0; j < 2; j++ ) { // get two maximum hex characters for parse
sss = str.charAt(++i);
if (((sss >= "0") && (sss <= "9")) || ((sss >= "a") && (sss <= "f")) || ((sss >= "A") && (sss <= "F"))) {
ss += sss; // if hex, add the hex character
} else {--i; break;} // not a hex char., exit the loop
}
n = parseInt(ss, 16); // parse the hex str as byte
if (n <= 0x7f){u = n; f = 1;} // single byte format
if ((n >= 0xc0) && (n <= 0xdf)){u = n & 0x1f; f = 2;} // double byte format
if ((n >= 0xe0) && (n <= 0xef)){u = n & 0x0f; f = 3;} // triple byte format
if ((n >= 0xf0) && (n <= 0xf7)){u = n & 0x07; f = 4;} // quaternary byte format (extended)
if ((n >= 0x80) && (n <= 0xbf)){u = (u << 6) + (n & 0x3f); --f;} // not a first, shift and add 6 lower bits
if (f <= 1){break;} // end of the utf byte sequence
if (str.charAt(i + 1) == "%"){ i++ ;} // test for the next shift byte
else {break;} // abnormal, format error
}
s0 += String.fromCharCode(u); // add the escaped character
}
}
}
return s0;
}

function setSlidePhoto2Preview(method, sec, width, height, files) {
document.getElementById("previewArea").innerHTML =
''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ' + 'width="' + width + '" height="'+ height +'" name="motionPhoto" align="middle" allowScriptAccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" autostart="true"/>
';
}

function setSlidePhoto2View(method, sec, width, height, files) {
var sTag = ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ' + 'width="' + width + '" height="'+ height +'" name="motionPhoto" align="middle" allowScriptAccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" autostart="true"/>';
document.write (sTag);
}



//--------- added by mj.chong 2006. 8. 18 -----------------
if(!window.ajax) window.ajax = {};

window.ajax.getXmlHttpRequest = function() {
var xmlhttp = false
//Mozila
if(window.XMLHttpRequest){
xmlhttp = new XMLHttpRequest()
} else {
//IE
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP")
}
return xmlhttp;
}

window.ajax.loadData = function(successFunc, path) {
var xmlhttp = ajax.getXmlHttpRequest();
if(xmlhttp!=null) {
xmlhttp.open("GET",path,true);
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4) {
if (xmlhttp.status == 200) {
var data = xmlhttp.responseText;
successFunc(data);
}
}
}
xmlhttp.send(null);
}
return false;
}

// 팝업 모양 레이어
// blogId : blogId
// afterFunc : 로그인 체크 후 실행할 function
// vars : afterFunc 에 전달할 매개 변수들
// params : loginCheck 에서 사용하는 변수들의 기본 값과 다른 값을 사용해야할 경우 전달
window.ajax.loginCheck = function(afterFunc, blogId, vars, params) {
if(blogId == null) {
alert("Blog id is needed.");
return;
}

var xmlhttp = ajax.getXmlHttpRequest();
if(xmlhttp!=null) {
url = "/BlogLoginCheck.nhn?blogId="+blogId;
callback = "http://nid.naver.com/nidlogin.login?mode=form&template=auto&id="+blogId
+"&url=http://blog.naver.com/common/util/loginFrameClose.jsp";
msg = "";
if(params!=null) {
if(params['callback']!=null) url = params['callback'];
if(params['msg']!=null) url = params['msg'];
} else {
//checkFrame 등도 위와 같이 변수로 받으려 했으나...변수로 받으면 제대로 받아지지 않아 이 방법을 씀 ㅡㅡ
params = { checkFrame:parent.document.getElementById("checkFrame")
, loginLayer:parent.document.getElementById("login_layer")
, bgLayer:parent.document.getElementById("login_layer_bg")};
}

if(params['checkFrame']==null) params['checkFrame'] = parent.document.getElementById("checkFrame");
if(params['loginLayer']==null) params['loginLayer'] = parent.document.getElementById("login_layer");
if(params['bgLayer']==null) params['bgLayer'] = parent.document.getElementById("login_layer_bg");

xmlhttp.open("GET", url, true);
xmlhttp.onreadystatechange = function() {
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
if(xmlhttp.responseText == "LOGOUT") {
params['bgLayer'].style.display="";
params['checkFrame'].src = callback + "&pmsg=" + msg ;
params['loginLayer'].style.display = "";
params['loginLayer'].focus();
}
else {
params['bgLayer'].style.display="none";
params['loginLayer'].style.display = "none";
afterFunc(vars);
}
}
}
xmlhttp.send(null);
}
}

// 팝업 윈도우
// blogId : blogId
// afterFunc : 로그인 체크 후 실행할 function
// vars : afterFunc 에 전달할 매개 변수들
// params : loginCheck 에서 사용하는 변수들의 기본 값과 다른 값을 사용해야할 경우 전달
window.ajax.loginPop = function(afterFunc, blogId, vars, params) {
if(blogId == null) {
alert("Blog id is needed.");
return;
}

var xmlhttp = ajax.getXmlHttpRequest();
if(xmlhttp!=null) {
url = "/BlogLoginCheck.nhn?blogId="+blogId;
callback = "/common/util/loginFramePop.jsp?blogId="+blogId;

xmlhttp.open("GET", url, true);
xmlhttp.onreadystatechange = function() {
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
if(xmlhttp.responseText == "LOGOUT") {
//login check pop up
window.open(callback, "", "top=100, left=100, width=465 height=355, toolbar=no,location=no,directories=no, mebar=no");
} else {
afterFunc(vars);
}
}
}
xmlhttp.send(null);
}
}
//--end of logout data lost protection --------------------



/**
* ui javascript framework
*/
var IE = false ;
if (window.navigator.appName.indexOf("Explorer") !=-1){
IE = true;
}

// create class
var Class = function(/* definition */){
var obj = function() {
if (this.__const) this.__const.apply(this,arguments);
}
if (arguments[0]) Class.extend(obj.prototype, arguments[0]);

return obj;
}

// class inheritance - multiple inheritance supportable
Class.extend = function(superClass/*, subCls1, subCls2, ... */) {
var obj = superClass;
for(var i=1; i < arguments.length; i++) {
if (arguments[i]) {
for(var x in arguments[i]) {
obj[x] = arguments[i][x];
}
}
}

return obj;
}

// global event object
var Event = {
register : function(oEl, sEvent, pFunc) {
oEl = $(oEl);
if (oEl.addEventListener) {
oEl.addEventListener(sEvent, pFunc, false);
} else if(oEl.attachEvent) {
oEl.attachEvent('on'+sEvent, pFunc);
}
},
unregister : function(oEl, sEvent, pFunc) {
oEl = $(oEl);
if (oEl.removeEventListener) {
oEl.removeEventListener(sEvent, pFunc, false);
} else if(oEl.detachEvent) {
oEl.detachEvent('on'+sEvent, pFunc);
}
},
ready : function(evt) {
var e = evt || window.event;
var b = document.body;

Class.extend(e, {
element : e.target || e.srcElement,
page_x : e.pageX || e.clientX+b.scrollLeft-b.clientLeft,
page_y : e.pageY || e.clientY+b.scrollTop-b.clientTop,
key : {
alt : e.altKey,
ctrl : e.ctrlKey,
shift : e.shiftKey,
up : [38,104].has(e.keyCode),
down : [40,98].has(e.keyCode),
left : [37,100].has(e.keyCode),
right : [39,102].has(e.keyCode),
enter : (e.keyCode==13)
},
mouse : {
left : (e.which&&e.button==0)||!!(e.button&1),
middle : (e.which&&e.button==1)||!!(e.button&4),
right : (e.which&&e.button==2)||!!(e.button&2)
},
stop : function() {
if (this.preventDefault) {
this.preventDefault();
this.stopPropagation();
} else {
this.returnValue = false;
this.cancelBubble = true;
}
}
});

return e;
}
}

// global element object
var Element = {
show : function() {
[].load(arguments).each(function(v){ $(v).style.display=''; });
},
hide : function() {
[].load(arguments).each(function(v){ $(v).style.display='none'; });
},
toggle : function() {
[].load(arguments).each(function(v){ Element[Element.visible(v)?'hide':'show'](v) });
},
visible : function(oEl) {
return ($(oEl).style.display!='none');
},
realPos : function(oEl) {
if (oEl.offsetParent) {
var p = this.realPos(oEl.offsetParent);
return { top: oEl.offsetTop+p.top, left: oEl.offsetLeft+p.left };
} else {
return { top: oEl.offsetTop, left:oEl.offsetLeft };
}
},
getCSS : function(oEl, name) {
return oEl.style[name];
},
setCSS : function(oEl, css) {
Class.extend(oEl.style, css);
},
hasClass : function(oEl, className) {
return $(oEl).className.split(/\s+/).has(className);
},
addClass : function(oEl, className) {
if (!this.hasClass(oEl, className)) ($(oEl).className+=' '+className).replace(/^\s+/,'');
},
removeClass : function(oEl, className) {
$(oEl).className = $(oEl).className.replace(new RegExp('(^|\s+)'+className+'($|\s+)','g'),'');
}
}

// array extend
Class.extend(Array.prototype, {
has : function(value) {
for(var i=0; i if (this[i] == value) return true;
}
return false;
},
load : function(obj) {
try {
for(var i=0; i this.push(obj[i]);
}
} catch(e){}
return this;
},
each : function(iter) {
for(var i=0; i iter(this[i],i);
}
},
filter : function(iter) {
var ret = [];
for(var i=0; i if (iter(this[i],i)) ret.push(this[i]);
}
return ret;
},
map : function(iter) {
for(var i=0; i this[i] = iter(this[i],i);
}
return this;
},
refuse : function(value) {
return this.filter(function(v){ return v!=value });
}
});
if (Array.prototype.forEach) {
Array.prototype.each = Array.prototype.forEach;
}

// function extend
Class.extend(Function.prototype, {
bind : function(obj) {
var f=this, a=[].load(arguments);a.shift();
return function() {
return f.apply(obj, a);
}
},
bindForEvent : function(obj) {
var f=this;
return function(e) {
return f.call(obj, Event.ready(e));
}
}
});

// get object by id
function $() {
var ret = [];
for(var i=0; i < arguments.length; i++) {
if (typeof arguments[i] == 'string') {
ret.push(document.getElementById(arguments[i]));
} else {
ret.push(arguments[i]);
}
}
return ret[1]?ret:ret[0];
}

// create element
function $c(tag) {
return document.createElement(tag);
}

// get element by selector
function $s(sel, limitNode) {
var ret = [], all = null, last=[], loopTmp, tmps;
var i, j, k;
var sels = sel.split(','), sems, em;
var id, cls, tag, re_cls3, b;

limitNode = $(limitNode)||document.body;
var getAll = function() { if(!all) all = [].load(limitNode.getElementsByTagName('*')); return all; }

for(i=0; i < sels.length; i++) {
sems = sels[i].replace(/^\s+|\s+$/g).split(/\s+/g);

for(j=0; j em = sems[j];
if (!j && em.substr(0,1) != '#') {
if (/^[a-zA-Z0-9:]+$/.test(em)) {
loopTmp = document.getElementsByTagName(em);
} else {
loopTmp = getAll();
}
} else if (em.substr(0,1) == '#' || em.substr(0,1) == '.') {
loopTmp = [];
for(k=0; k < last.length; k++) {
tmps = last[k].getElementsByTagName('*');
for(var l=0; l < tmps.length; l++) loopTmp.push( tmps[l] );
}
last = [];
}

switch (em.substr(0,1)) {
case '#': // for id
id = new RegExp('^#([\\w0-9\\-]+)').exec(em)[1];

if (!last.length) {
last = [ document.getElementById(id) ];
} else {
last = loopTmp.filter( function(v){ return (v.id==id) } );
}
em = em.replace(/^#[\w0-9\-]+/, '');
if (em.length) {
sems[j--] = em;
continue;
}
break;
case '.': // for class
cls = new RegExp('^\\.([\\w0-9\\-]+)').exec(em)[1];
last = loopTmp.filter( function(v){ return new RegExp('(^|\\s)'+cls+'(\\s|$)').test(v.className) } );


em = em.replace(/^\.[\w0-9\-]+/, '');
if (em.length) {
sems[j--] = em;
continue;
}
break;
default:
tag = new RegExp('^[a-zA-Z0-9\\:]+').exec(em);

if (!j && (tag+"").toLowerCase() == 'body') {
last = [ document.body ];
} else if (!last.length) {
last = [].load( document.body.getElementsByTagName(tag) );
} else {
loopTmp = last; last = [];
for(var k=0; k < loopTmp.length; k++) {
tmps = loopTmp[k].getElementsByTagName(tag);
for(var l=0; l < tmps.length; l++) {
last.push( tmps[l] );
}
}
}

em = em.replace(/^[a-zA-Z0-9\:]+/, '');
if (em.length) {
sems[j--] = em;
continue;
}
}

if (!last.length) break;
}

ret = ret.concat(last);
}

return ret;
}

// get elements by class name
document.getElementsByClassName = function(className, oParent) {
var a = [].load(($(oParent) || document.body).getElementsByTagName('*'));
var r = new RegExp('(^|\\s)'+className+'($|\\s)','gi');
return a.filter(function(v){ return r.test(v.className); });
}



// 이 파일은 postList, postView에서 공통으로 사용하는 것으로.
// common.js, skin.js, scrap5.js 등의 파일을 하나로 통합한 것임.
// 2005.07.07 by jhhany
// 2006.10.28 by amysoul Edit

// Browse Type
// IE Script
var IE = false ;
if (window.navigator.appName.indexOf("Explorer") !=-1){
IE = true;
}
function resizeIfr(obj, minHeight) {
minHeight = minHeight || 10;

try {
var getHeightByElement = function(body) {
var last = body.lastChild;
try {
while (last && last.nodeType != 1 || !last.offsetTop) last = last.previousSibling;
return last.offsetTop+last.offsetHeight;
} catch(e) {
return 0;
}

}

var doc = obj.contentDocument || obj.contentWindow.document;
if (doc.location.href == 'about:blank') {
obj.style.height = minHeight+'px';
return;
}

//var h = Math.max(doc.body.scrollHeight,getHeightByElement(doc.body));
//var h = doc.body.scrollHeight;
if (/MSIE/.test(navigator.userAgent)) {
var h = doc.body.scrollHeight;
} else {
var s = doc.body.appendChild(document.createElement('DIV'))
s.style.clear = 'both';

var h = s.offsetTop;
s.parentNode.removeChild(s);
}

//if (/MSIE/.test(navigator.userAgent)) h += doc.body.offsetHeight - doc.body.clientHeight;
if (h < minHeight) h = minHeight;

obj.style.height = h + 'px';
if (typeof resizeIfr.check == 'undefined') resizeIfr.check = 0;
if (typeof obj._check == 'undefined') obj._check = 0;

// if (obj._check < 5) {
// obj._check++;
setTimeout(function(){ resizeIfr(obj,minHeight) }, 200); // check 5 times for IE bug
// } else {
//obj._check = 0;
// }
} catch (e) {
//alert(e);
}

}
//===============================================================
// skin.jsp 시작
//===============================================================
function setSkinCss(){
//var parentFrame = parent;
document.body.style.background = 'none';
var ssh = parent.document.styleSheets.length;


if(IE){
for(var i=0;i var styleRules = parent.document.styleSheets(1).rules;
for(var j=0;j var selector = styleRules.item(j).selectorText;
if(selector != null && selector.substring(0,10) == "#post-area") {
var declaration = styleRules.item(j).style.cssText;
document.styleSheets[0].addRule(selector, declaration);
}
}
}
}else{
for(var i=0;i var styleRules = parent.document.styleSheets[1].cssRules;
for(var j=0;j var selector = styleRules.item(j).selectorText;
if(selector != null && selector.substring(0,10) == '#post-area'){
var declaration = styleRules.item(j).style.cssText;
var styleSheetElement = $('poststylesheet').sheet;
var styleSheetLength = styleSheetElement.cssRules.length;
styleSheetElement.insertRule (selector + " { " + declaration + " } ", styleSheetLength);
}
}
}
}

}
//===============================================================
// skin.jsp 끝
//===============================================================
//===============================================================
// scrap5.jsp 시작
//===============================================================
var jsv_logNo = "";
var jsv_openYn = "";
var jsv_valid = "";
var jsv_num = "";
var jsv_blogid = "";
function ui_scrap(blogid,num,no) {
jsv_blogid = blogid;
jsv_num = num;
jsv_logNo = no;
}

function ui_scrap2(blogid,num,no) {
ui_scrap(blogid,num,no);
}
function ui_scrap3(blogid,num,no) {
ui_scrap(blogid,num,no);
}
function ui_scrap4(blogid,num,no) {
ui_scrap(blogid,num,no);
}
function ui_scrap5(blogid,num,no) {
ui_scrap(blogid,num,no);
}
function ui_scrap6(blogid,num,no) {
ui_scrap(blogid,num,no);
}
function ui_scrap7(blogid,num,no) {
ui_scrap(blogid,num,no);
}
function ui_scrap8(blogid,num,no) {
ui_scrap(blogid,num,no);
}
function ui_scrap9(blogid,num,no) {
ui_scrap(blogid,num,no);
}

function setOnEventHandler() {
if (IE) {
document.onclick = MouseDown;
}else {
document.captureEvents(Event.CLICK)
document.onclick = MouseDown;
}
}

function exec_menuitem(key) {
switch(key) {
case "EVENT1" :
//scrap(jsv_logNo,jsv_openYn,jsv_valid);
scrap(jsv_num);
break;
case "EVENT2" :
scrap_cafe(jsv_num);
break;
case "EVENT3" :
printPost(jsv_blogid, jsv_num, jsv_logNo);
break;
case "EVENT4" :
openbook(jsv_num); // 임시 동영상 by jhhany
//openbook();
break;
case "EVENT5" :
add_prologue();
break;
// 이하 포토로그 이벤트
case "EVENT6" :
scrap_photo(jsv_num);
break;
}
}

// IE Script
var mouse_top;
var mouse_left;
var scroll_top;
var scroll_left;
var event_id = "none";
var status_over = false;
var parent_menu_name = "menu_parent";
var child_menu_array = ["menu_child1"];
//var child_menu_array = ["menu_child1", "menu_child2", "menu_child3"];
var submenu_left_indent = 70;
var column_height = 18;
var submenu_top_indent = 0;
var mainmenu_top_indent = 0;
var menuover_bgcolor = "#e4ff75";
var menuover_fgcolor = "#ffffff";
var default_menuover_bgcolor = "#ffffff";
var default_menuover_fgcolor = "#000000";

//NS4 = (document.layers);
//IE4 = (document.all);
isWin = (navigator.appVersion.indexOf("Win") != -1)

document.onclick = MouseDown;

function startIt() {
}

function menuOver(e, ar_obj, ar_id) {
var event = e || window.event;
status_over = true;
changeColor(ar_obj);
hideChild(event_id);
viewSubMenu(event, ar_obj, ar_id);
}

function menuOut(ar_obj) {
status_over = false;
changeColor(ar_obj);
}

/*function SubmenuOver(ar_obj) {
status_over = true;
changeColor(ar_obj);
}*/
/* modified by gony 2006.10.30 */
function changeColor(ar_obj) {
if (typeof ar_obj._gony_painted == 'undefined') ar_obj._gony_painted = false;

ar_obj.style.backgroundColor = ar_obj._gony_painted?default_menuover_bgcolor:menuover_bgcolor;
ar_obj._gony_painted = !ar_obj._gony_painted;
}

function MouseDown(e) {
var event = e || window.event;
var event_target = event.target || event.srcElement;
event_target = event_target.toString();
event_check = event_target.indexOf("javascript:ui_scrap(");
event_check2 = event_target.indexOf("javascript:ui_scrap2(");
event_check3 = event_target.indexOf("javascript:ui_scrap3(");
event_check4 = event_target.indexOf("javascript:ui_scrap4(");
event_check5 = event_target.indexOf("javascript:ui_scrap5(");
event_check6 = event_target.indexOf("javascript:ui_scrap6(");
event_check7 = event_target.indexOf("javascript:ui_scrap7(");
event_check8 = event_target.indexOf("javascript:ui_scrap8(");
event_check9 = event_target.indexOf("javascript:ui_scrap9(");

if (!status_over) hideAll();
if (!event_check) {
parent_menu_name = "menu_parent";
viewMenu(event, parent_menu_name);
}else if(!event_check2){
parent_menu_name = "menu_parent2";
$('menu_parent2_scrap_type').innerHTML = "스크랩 : 허가됨";
$('regToPrologue').innerHTML = "";
$('regToPrologue').height = '1px';
viewMenu(event, parent_menu_name);
}else if(!event_check3){
parent_menu_name = "menu_parent3";
$('menu_parent3_scrap_type').innerHTML = "스크랩 : 허가됨";
viewMenu(event, parent_menu_name);
}else if(!event_check4){
parent_menu_name = "menu_parent2";
$('menu_parent2_scrap_type').innerHTML = "스크랩 : 금지됨";
$('regToPrologue').innerHTML = "";
$('regToPrologue').height = '1px';
viewMenu(event, parent_menu_name);
}else if(!event_check5){
parent_menu_name = "menu_parent3";
$('menu_parent3_scrap_type').innerHTML = "스크랩 : 금지됨";
viewMenu(event, parent_menu_name);
}else if(!event_check6){
parent_menu_name = "menu_parent2";
$('menu_parent2_scrap_type').innerHTML = "스크랩 : 허가됨";
$('regToPrologue').innerHTML = "프롤로그에 등록";
$('regToPrologue').height = '22px';
viewMenu(event, parent_menu_name);
}else if(!event_check7){
parent_menu_name = "menu_parent4";
viewMenu(event, parent_menu_name);
}else if(!event_check8){
parent_menu_name = "menu_parent5";
$('menu_parent5_scrap_type').innerHTML = "스크랩 : 금지됨";
viewMenu(event, parent_menu_name);
}else if(!event_check9){
parent_menu_name = "menu_parent5";
$('menu_parent5_scrap_type').innerHTML = "스크랩 : 허가됨";
viewMenu(event, parent_menu_name);
}else {
if (!status_over) hideAll();
return;
}
}

/* modified by gony 2006.10.30 */
function hideChild(ar_id) {
if (event_id == "none") return;
for(var i=0; i < child_menu_array.length; i++) {
try {
document.getElementById(child_menu_array[i]).style.display = 'none';
} catch(e) { continue; }
}
}
/* modified by gony 2006.10.30 */
function hideAll() {
document.getElementById(parent_menu_name).style.display = 'none';
if (event_id == "none") return;

for(var i=0; i < child_menu_array.length; i++) {
try {
document.getElementById(child_menu_array[i]).style.display = 'none';
} catch(e) { continue; }
}
}
/* modified by gony 2006.10.30 */
function viewMenu(e, ar_id) {
if (ar_id == "none") return;
var menuLocBod = window.document.body;
var xPos = e.pageX || e.clientX+menuLocBod.scrollLeft;
var yPos = e.pageY || e.clientY+menuLocBod.scrollTop;

with(document.getElementById(ar_id).style)
{
top = (yPos-70)+'px';
left = (xPos-120)+'px';
display = '';
}
}

function viewSubMenu(e, ar_obj, ar_id) {
if (ar_id == "none") return;
event_id = ar_id;
parent_top = menu_parent.style.pixelTop;
parent_left = menu_parent.style.pixelLeft;
child_top = ar_obj.style.pixelTop;
child_left = ar_obj.style.pixelLeft;
screen_height = window.document.body.offsetHeight;
screen_width = window.document.body.offsetWidth;
mouse_top = e.y;
mouse_left = e.x;
menuLocBod = window.document.body;
xPos = menuLocBod.scrollLeft + parent_left + submenu_left_indent;
eval("submenu_top_indent = " + ar_id + ".children[0].children[0].children.length");
submenu_top_indent = submenu_top_indent * column_height;
if (screen_height > mouse_top + submenu_top_indent)
yPos = event.clientY + menuLocBod.scrollTop;
else
yPos = (event.clientY + menuLocBod.scrollTop) - submenu_top_indent;

if (mouse_top - submenu_top_indent < 0)
yPos = event.clientY + menuLocBod.scrollTop;

eval(ar_id + ".style.pixelTop =" + yPos);
eval(ar_id + ".style.pixelLeft =" + xPos);
eval(ar_id + ".style.display = \"\"");
}

function changeOnColor(obj){
obj.style.backgroundColor = menuover_bgcolor;
}
function changeOutColor(obj){
obj.style.backgroundColor = default_menuover_bgcolor;
}

var menu_p = '';
menu_p += '';
document.write(menu_p);

var menu_p2 = '';
menu_p2 += '';
document.write(menu_p2);

var menu_p3 = '';
menu_p3 += '';
document.write(menu_p3);

var menu_p4 = '';
menu_p4 += '';
document.write(menu_p4);

var menu_p5 = '';
menu_p5 += '';
document.write(menu_p5);

String.prototype.row0replace = function(){
return this.replace(/(href)|(src)|(alt)/g, "").replace(/(width=21 height=9)/g,"width=0 height=0");
}
String.prototype.row2replace = function(){
return this.replace(/(href)|(src)|(alt)/g, "");
}
String.prototype.row3replace = function(){
return this.replace(/(target=_top)|(target=_parent)/g, "target='_blank'");
}

String.prototype.row4replace = function(){
return this.replace(/(onclick)|(CURSOR: hand)|(alt)/g, "").replace(/(target=_top)|(target=_parent)/g, "target='_blank'").replace(/(setTimeout)/g, "opener.setTimeout");
}

function printPost(blogId, num, logNo){
var printWin = open("/PostPrint.nhn?blogId=" + blogId + "&logNo=" + logNo, "printWin", "width=610, height=600, resizable=no, scrollbars=yes");
}

function viewPrintPost(printWin){
var printObj = $('printPost' + jsv_num);
var printHTML = "";

if(typeof(printObj) != "undefined" && typeof(printWin.document.getElementById("printArea")) != "undefined") {
printHTML = "";
for(var i=0; i < printObj.rows.length-2; i++){ // -2를 하는것은 마지막의 두줄은 프린트하지 않기 위함.
printHTML += ""+printObj.rows.item(i).innerHTML+"";
}
printHTML += "
";
printWin.document.getElementById("printArea").innerHTML = printHTML;
}
}

function viewPrintPost_old(printWin){
var printObj = document.all["printPost" + jsv_num];
var printHTML = "";

if(typeof(printObj) == "object" && typeof(printWin.document.all.printArea) == "object"){
printHTML = ""
+ printObj.rows[0].outerHTML.row0replace()
+ printObj.rows[1].outerHTML
+ printObj.rows[2].outerHTML.row2replace()
+ printObj.rows[3].outerHTML.row3replace()
+ printObj.rows[4].outerHTML.row3replace()
+ printObj.rows[5].outerHTML.row4replace()
+ "
";

//alert(printHTML);
printWin.document.all.printArea.innerHTML = printHTML;
//alert(printWin.html.outerHTML);
}
}
function openbook_old(){ // 임시
window.open("/export/opendic/sendData.jsp?blogId=" + jsv_blogid + "&logNo=" + jsv_logNo,"openbook","width=100,height=100");
}
function add_prologue(){
window.open(url_prologue + "/PrologueFrontSetting.nhn?blogId="+ jsv_blogid + "&logno=" + jsv_logNo, "prologue", "width=440,height=160");
/*
var layout = document.getElementById("isLayout") != null ? document.getElementById("isLayout").value : "0";
var slide = document.getElementById("isSlide") != null ? document.getElementById("isSlide").value : "0";

if(slide == "1") {
alert("슬라이드 포토 업로드된 포스트의 카페에 담기, 오픈사전 등록, 프롤로그 등록은 추후 서비스될 예정 입니다."); return;
}else if(layout == "1") {
alert("레이아웃 포토가 업로드된 포스트의 카페에 담기, 오픈사전 등록, 프롤로그 등록은 추후 서비스될 예정 입니다."); return;
}else{
window.open(url_prologue + "/PrologueFrontSetting.nhn?blogId="+ jsv_blogid + "&logno=" + jsv_logNo, "prologue", "width=440,height=160");
}
*/
}
//===============================================================
// scrap5.jsp 끝
//===============================================================

// 요약글에서 호출.
function cm_paperInit_more(minHeight)
{
try
{
var timeArray = new Array(200, 500, 1500, 3500, 7000, 12000, 20000);
//alert("1_cm_paperInit, timeArray.length="+timeArray.length);
for(var i=0; i < timeArray.length; i++)
setTimeout('_cm_paperInit(\''+minHeight+'\')', timeArray[i]);
}catch (e) {}
}









var blogID = "idtong";
var upblog_url = "http://up.blog.naver.com";
var blog_url = "http://blog.naver.com";
var section_url = "http://section.blog.naver.com";
var image_url = "http://blogimgs.naver.com/blog20/blog/layout_photo/";
var attach_url = "http://blogfiles.naver.net";
var thumbnail_url = "http://blogthumb2.naver.net";







document.domain = "naver.com";
// PostList.jsp와 PostView.jsp에서 공통적으로 사용하고 있는 JavaScript

var arrChkopen = new Array("0","0","0","0","0","0","0","0","0","0","0");


// imageZoom.jsp에서 우클릭이 가능하게 할지를 체크한다. 1이면 불가 0이면 가능.
var rclickOpenYN = 0;

rclickOpenYN = 1;


// 덧글/엮인글 view
function sublayer(ch,no,logNo) {
var Cfrm = $('CommentFrm' + logNo);
var Rfrm = $('RewFrm' + logNo);
var Fc = $('Com' + no);
var Fc2 = $('Rew' + no);
var Fc3 = $('Comi' + no);

try {
if (ch=="1") { //덧글
if (Cfrm.style.display == "none" || arrChkopen[no] != ch){
Cfrm.src = "/PostCommentMain.nhn?blogId=idtong&fno=" + no +
"&logNo=" + logNo +
"&skinId=&skinType=";
Cfrm.style.display = "block";
Rfrm.style.display = "none";
Fc.className = 'ico1';
Fc2.className = 'pcol2';
Fc3.className = 'pcol3 on';
} else {
Cfrm.style.display = "none";
Rfrm.style.display = "none";
Fc.className = 'ico2';
Fc2.className = 'pcol2';
Fc3.className = 'pcol2';
}
} else if (ch=="2") { //엮인글
if (Rfrm.style.display == "none" || arrChkopen[no] != ch){
Rfrm.src = "/PostRelayList.nhn?blogId=idtong&fno=" + no +
"&logNo=" + logNo +
"&skinId=&skinType=";
Rfrm.style.display = "block";
Cfrm.style.display = "none";
Fc.className = 'ico1';
Fc2.className = 'pcol3 on';
Fc3.className = 'pcol2';
} else {
Rfrm.style.display = "none";
Cfrm.style.display = "none";
Fc.className = 'ico2';
Fc2.className = 'pcol2';
Fc3.className = 'pcol2';
}
}
} catch(e) {}

arrChkopen[no] = ch;
}
// 기본 기능
function funcViewScrapHistory(logNo, scrapTotCnt){
var scrapWin = open("/post/scrap/scrapHistory.jsp?blogId=idtong&logNo=" + logNo + "&scrapTotCnt=" + scrapTotCnt, "scrapWin", "width=360, height=450");
}

//edited by mj.chong 2006. 8. 23 logout data protection
function PostDelete(logNo, scode) {
var params = new Array();
params['logNo'] = logNo;
params['scode'] = scode;
ajax.loginCheck(__PostDelete, 'idtong', params, null);
}
function __PostDelete(params){
if(confirm('포스트를 삭제하시겠습니까?')){
location.href = "http://blog.naver.com/PostDelete.nhn?blogId=idtong&cpage=&categoryNo=0&scode=" + params['scode'] + "&logNo=" + params['logNo'];
}
}

function PostList(blogId, categoryNo) {
location.href = "http://blog.naver.com/PostList.nhn?blogId=" + blogId + "&categoryNo=" + categoryNo;
}

function PostUpdate(logNo, scode) {
var params = new Array();
params['logNo'] = logNo;
params['scode'] = scode;
ajax.loginCheck(__PostUpdate, 'idtong', params, null);
}
function __PostUpdate(params){
location.href = "http://blog.naver.com/PostUpdateForm.nhn?blogId=idtong&cpage=&scode=" + params['scode'] + "&logNo=" + params['logNo'];
}

function Brequest(pnum){
window.open("/main/request.jsp?blogId=idtong&pnum=" + pnum,"brequest","width=347,height=250,scrollbars=no");
}
function releaseRequest(id,service,type,detail,pnum){
window.open("/main/releaseRequest.jsp?blogId=" + id + "&service=" + service + "&type=" + type + "&detail=" + detail + "&pnum=" + pnum,"brequest","width=347,height=250,scrollbars=no");
}
function PostMove(logNo) {
window.open("postMove.jsp?blogId=idtong&logNo=" + logNo,"postMove","width=347,height=250,scrollbars=yes");
}
function scrap(num){

window.open("http://nid.naver.com/nidlogin.login?template=plogin&mode=form&url=http://blog.naver.com%2Fpost%2Fscrap%2Fretscrap.jsp?scrapnum="+num,"scrapPopSSS","width=205,height=208");
return;

scrapIn(num);
}
function scrapIn(num){
num = num -1;

if('129230' == '-1'){
alert("자신의 글을 자신의 블로그에 담을 수 없습니다 .");
return;
}
var frm = document.scrapFrm[num];
if(frm.source_title == null){
frm = document.scrapFrm;
}
if (frm.source_title.value.split(" ").join("")=="") {
alert("출처가 누락되었습니다. 다시 시도해주세요.");
return false;
}
if (frm.title.value.split(" ").join("")=="") {
alert("제목이 누락되었습니다. 다시 시도해주세요.");
return false;
}
/*
if (frm.source_contents.value.split(" ").join("")=="") {
alert("내용이 누락되었습니다. 다시 시도해주세요.");
return false;
}*/
window.open("","scrapPop","width=205,height=208");
frm.target = "scrapPop";
frm.submit();
}
// "이 포스트를.." 항목에서 "오픈사전에 등록"에서 사용.
function openbook(num) {
num = num -1;

var frm = document.scrapFrmCafe[num];
if(frm.source_title == null){
frm = document.scrapFrmCafe;
}
if(frm.isMovie.value == "1") {
alert("동영상이 업로드된 포스트의 오픈사전 등록은 추후 서비스될 예정 입니다."); return;
}
if(frm.isSlide.value == "true") {
alert("슬라이드 포토가 업로드된 포스트의 오픈사전 등록은 추후 서비스될 예정 입니다."); return;
}
if(frm.isLayout.value == "true") {
alert("레이아웃 포토가 업로드된 포스트의 오픈사전 등록은 추후 서비스될 예정 입니다."); return;
}

window.open("/export/opendic/sendData.jsp?blogId=" + frm.blogId.value + "&logNo=" + frm.logNo.value,"openbook","width=100,height=100");
}
// "이 포스트를.." 항목에서 "카페에 담기"에서 사용.
function scrap_cafe(num){
num = num -1;

var frm = document.scrapFrmCafe[num];
if(frm.source_title == null){
frm = document.scrapFrmCafe;
}
/*
if(frm.isMovie.value == "1"){
alert("동영상이 업로드된 포스트의 카페에 담기, 오픈사전 등록은 추후 서비스될 예정 입니다."); return;
}*/

if(frm.isSlide.value == "true") {
alert("슬라이드 포토가 업로드된 포스트의 카페에 담기, 오픈사전 등록은 추후 서비스될 예정 입니다."); return;
}

if(frm.isLayout.value == "true") {
alert("레이아웃 포토가 업로드된 포스트의 카페에 담기, 오픈사전 등록은 추후 서비스될 예정 입니다."); return;
}

if (frm.source_title.value.split(" ").join("")=="") {
alert("출처가 누락되었습니다. 다시 시도해주세요.");
return false;
}
if (frm.title.value.split(" ").join("")=="") {
alert("제목이 누락되었습니다. 다시 시도해주세요.");
return false;
}
/*
if (frm.source_contents.value.split(" ").join("")=="") {
alert("내용이 누락되었습니다. 다시 시도해주세요.");
return false;
}*/
window.open("","scrapPopCafe","width=400,height=410");
frm.target = "scrapPopCafe";
frm.submit();
}
function needlogon(){
alert("로그인이 필요합니다.");
parent.goLoginPage();
}
function noadmin(){
alert("관리자는 엮인글을 쓸 수 없습니다.");
}
function settop(){
window.location.href = '#';
}
function stopqmsg(){
$('mrblogcontents').style.display = "none";
$('closeMrBlog').src ="http://admin.blog.naver.com/useradmin/qmsgUpdate.jsp?blogId=idtong&flag=0";
}
function resizeImage(num){
var width = $('userImg'+num).width;
if( width > 717 ) {
$('userImg'+num).width = 717;
}
}
function popview(url){
window.open("/main/imageZoom.jsp?url=" + url,"mainview","scrollbars=yes,width=100,height=100");
}
function viewVod(url){
if (url) {
window.open( url, 'VOD','toolbar=no,location=no,directories=no,status=no,menubar=no,resizable=no,scrollbars=no,width=610,height=507,top=30,left=230');
}
}
function klink(str) {
var link_location;
if (navigator.appName == 'Netscape') link_location = "http://krdic.naver.com/search.naver?where=krdic&mode=srch_all&query="+str;
else link_location = "http://krdic.naver.com/search.naver?where=krdic&mode=srch_all&query="+escape(str);

window.open(link_location,"_blank");
}
function flink(str) {
var link_location;
if (navigator.appName == 'Netscape') link_location = "http://endic.naver.com/search.naver?where=endic&mode=srch_ke&query="+str;
else link_location = "http://endic.naver.com/search.naver?where=endic&mode=srch_ke&query="+escape(str);

window.open(link_location,"_blank");
}

function qlink(str) {
var link_location;
if (navigator.appName == 'Netscape') link_location = "http://jpdic.naver.com/search.naver?where=jpdic&mode=srch_ke&query="+str;
else link_location = "http://jpdic.naver.com/search.naver?where=jpdic&mode=srch_ke&query="+escape(str);

window.open(link_location,"_blank");
}
// 메모로그로 이동 신청을 할때 호출되며 목록보기를 reloading해줌.
function reloadtoplist(){
try {
var cpage2 = document.forms["listTopForm"].cpage2.value;
var cpage = document.forms["listTopForm"].cpage.value;
document.all.postTop.src = "http://blog.naver.com/postListTop.jsp?blogId=pupuni75&categoryNo=0&viewdate=&cpage2="+cpage2+"&cpage="+cpage;
}catch(e){}
}

function reloadByUser() {
location.href = "/PostView.nhn?blogId=idtong&logNo=130014995005";
}

//목록열기
var firstListOpen = false;
function openlist(){
var ch = $('toplist').style.display;
if (ch=='none') { // 열기
if(!firstListOpen){
firstListOpen = true;
$('postTop').src = "/PostListTop.nhn?blogId=idtong&categoryNo=0&viewdate=&postListTopCurrentPage=1";
}
$('toplist').style.display='block';
$('toplistmenu').style.display='block';
$('toplistmenudown').style.display='none';
$('toplistmenuup').style.display='block';
} else { // 닫기
$('toplist').style.display='none';
$('toplistmenu').style.display='none';
$('toplistmenudown').style.display='block';
$('toplistmenuup').style.display='none';
}
resizeIfr(parent.document.getElementById('papermain'),300);
}
// Post List Top
var bCheckAll = false;
function checkAllPost(nCnt){
if(bCheckAll) bCheckAll = false; else bCheckAll = true;
if (nCnt > 1){
for (var i = 0;i < nCnt;i++)
document.forms["listTopForm"].logNo[i].checked = bCheckAll;
}else if(nCnt == 1){
document.forms["listTopForm"].logNo.checked = bCheckAll;
}
if(typeof(document.forms["listTopForm"].checkall)=="object"){
document.forms["listTopForm"].checkall.checked = bCheckAll;
}
}

function cfmMemoMovePost(nCnt){
var nCheckedCnt = 0;
var i;
var strMsg;

if (nCnt > 1){
for(i = 0;i < nCnt; i++){
if(document.forms["listTopForm"].logNo[i].checked) nCheckedCnt++;
}
}
else if(nCnt == 1){
if(document.forms["listTopForm"].logNo.checked) nCheckedCnt = 1;
}
if (nCheckedCnt > 0){
window.open("/post/postMoveMemoConfirm.jsp?blogId=idtong&cnt="+nCnt , "_postMoveMemoCfm", "width=360,height=280");
}else{
alert("포스트를 선택하세요.");
}
}

function cfmAuthUpdatePost(nCnt){
var nCheckedCnt = 0;
var i;
var strMsg;

if (nCnt > 1){
for(i = 0;i < nCnt; i++){
if(document.forms["listTopForm"].logNo[i].checked) nCheckedCnt++;
}
}
else if(nCnt == 1){
if(document.forms["listTopForm"].logNo.checked) nCheckedCnt = 1;
}
if (nCheckedCnt > 0){
window.open("/post/postAuthUpdateConfirm.jsp" , "_postAuthUpdateCfm", "width=495,height=260");
}else{
alert("포스트를 선택하세요.");
}
}
function cfmPostRegistTagName(nCnt) {
var nCheckedCnt = 0;
var i;
var strMsg;

if (nCnt > 1){
for(i = 0;i < nCnt; i++){
if(document.forms["listTopForm"].logNo[i].checked) nCheckedCnt++;
}
}
else if(nCnt == 1){
if(document.forms["listTopForm"].logNo.checked) nCheckedCnt = 1;
}
if (nCheckedCnt > 0){
window.open("/post/tag/PostTagRegistConfirm.jsp?blogId=idtong&cnt="+nCnt , "_postTagCfm", "width=430,height=180");
}else{
alert("포스트를 선택하세요.");
}
}
function cfmDeletePost(nCnt){
var nCheckedCnt = 0;
var i;
var strMsg;

if (nCnt > 1){
for(i = 0;i < nCnt; i++){
if(document.forms["listTopForm"].logNo[i].checked) nCheckedCnt++;
}
}else if(nCnt == 1){
if(document.forms["listTopForm"].logNo.checked) nCheckedCnt = 1;
}
if (nCheckedCnt > 0){
window.open("/post/postDeleteConfirm.jsp" , "_postDeleteCfm", "width=330,height=190");
}else{
alert("포스트를 선택하세요.");
}
}

function cfmMovePost(nCnt){
var nCheckedCnt = 0;
var i;
var strMsg;

if (nCnt > 1){
for(i = 0;i < nCnt; i++){
if(document.forms["listTopForm"].logNo[i].checked) nCheckedCnt++;
}
}
else if(nCnt == 1){
if(document.forms["listTopForm"].logNo.checked) nCheckedCnt = 1;
}

if (nCheckedCnt > 0){
window.open("/post/postMoveConfirm.jsp?blogId=idtong&cnt="+nCnt , "_postMoveCfm", "width=330,height=235");
}else{
alert("포스트를 선택하세요.");
}
}

// 블링크/공감수 가져오기
function getXmlHttpRequest() {
var xmlhttp = false
if(window.XMLHttpRequest){//Mozila
xmlhttp = new XMLHttpRequest()
} else {//IE
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP")
}
return xmlhttp;
}
function loadData(path, successFunc){
var xmlhttp = getXmlHttpRequest();
xmlhttp.open("GET",path,true);
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4) {
if (xmlhttp.status == 200) {
var data = xmlhttp.responseText;
successFunc(data);
}
}
}
xmlhttp.send(null);
return false;
}
function setBlinkinfo(data){
var data = eval('('+data+')');
if(data.blist.length>0){
for(i=0; i < data.blist.length; i++){
setBlink(data.blist[i].logno, data.blist[i].blinkno, data.blist[i].blinktitle, data.blist[i].themename)
}
}
}
function setSympathyinfo(data){
var data = eval('('+data+')');
if(data.slist.length>0){
for(i=0; i < data.slist.length; i++){
setSympathy(data.slist[i].logno, data.slist[i].sympathycnt);
}
}
}
function setSympathy(logno, cnt){
try{
var symCnt = $('sympathyCnt_'+logno);
symCnt.innerHTML = '공감 '+cnt+'';
showBlinkTR(logno);
}catch(e){}
}
function setBlink(logno, blinkno, blinktitle, themename){
try{
var html = "";
var comma = "";
var blinkinfo = $('blinkinfo_'+logno);
html = blinkinfo.innerHTML;
if(html!='') comma = ",";
blinkinfo.innerHTML += comma
+" "
+blinktitle+" "
+themename+"
";
blinkinfo.style.display = "inline";
showBlinkTR(logno);
}catch(e){}
}
function setSymcnt(data){
var data = eval('('+data+')');
try{
if(data.count>0){
setSympathy(data.logno, data.count);
} else {
alert(data.message);
}
} catch(e) {}
}

function sympathy(logno){
// 공감하기
loadData("/PostSympathyAddAndCount.nhn?blogId=idtong&logNo="+logno, setSymcnt);
}

function showBlinkTR(logno){
var infoTR = document.getElementById('blink_sym_'+logno);
infoTR.style.display = "block";
}

function loadBlinkInfo(){// 블링크 리스트 가져오기
loadData("/BlinkInfoByPost.nhn?blogId=idtong", setBlinkinfo);
}
function loadSympathyInfo(){// 공감수 가져오기
loadData("/SympathyInfoByPost.nhn?blogId=idtong", setSympathyinfo);
}

function callbackSaveTagInfo(data) {
try{
var data = eval('('+data+')');
if(data.taglist.length>0){
for(i=0; i < data.taglist.length; i++){
hideTagEditBox(data.taglist[i].logno);
hideTagTopEditBox(data.taglist[i].logno);
setTagList(data.taglist[i].logno, data.taglist[i].tagName);
setTagTopList(data.taglist[i].logno, data.taglist[i].tagName);
}
}
}catch(e){};
}
function setTagListinfo(data) {
try{
var data = eval('('+data+')');
if(data.taglist.length>0){
for(i=0; i < data.taglist.length; i++){
setTagList(data.taglist[i].logno, data.taglist[i].tagName);
}
}
}catch(e){};
}

//edited by mj.chong 2006. 8. 23 logout data protection
function saveTag(logNo) {
ajax.loginCheck(__saveTag, 'idtong', logNo, null);
}

function __saveTag(logno) {
var tagNameVal = $('tagnames_'+logno);
var tagForm = $('saveTagName');
tagForm.logNo.value = logno;
tagForm.chtagname.value = tagNameVal.value;
tagForm.submit();
}
function saveTagTop(logno) {
var tagNameVal = $('tagTopnames_'+logno);
document.saveTagName.logNo.value = logno;
document.saveTagName.chtagname.value = tagNameVal.value;
document.saveTagName.submit();
}
function showTagTopEditBox(logno) {
try{
var tagElem = $('tagTopName_'+logno);
tagElem.style.display = "none";
var tagEditElem = $('edit_tagTopName_'+logno);
tagEditElem.style.display = "block";
}catch(e){}
}
function hideTagTopEditBox(logno) {
try{
var tagElem = $('tagTopName_'+logno);
tagElem.style.display = "block";
var tagEditElem = $('edit_tagTopName_'+logno);
tagEditElem.style.display = "none";
}catch(e){}
}

function setTagList(logno, tagList) {
try {
var tagNames = tagList.split(",");
var editTagStr ="";

var tagElem = $('tagName_'+logno);
var tagStr = "";
for(var i =0; i < tagNames.length; i++) {
tagStr += ""+tagNames[i]+"";
editTagStr += tagNames[i];
if(i != tagNames.length-1) {
tagStr += ", ";
editTagStr += ",";
}
}



tagElem.innerHTML = tagStr;

tagElem.style.display = "inline";
}catch(e) {}
resizeIfr(parent.document.getElementById('papermain'),300);
}
function setTagTopList(logno, tagList) {
try {
var tagNames = tagList.split(",");
var editTagStr ="";

var tagElem = $('tagTopName_'+logno);
var tagStr = "";
for(var i =0; i < tagNames.length; i++) {
tagStr += ""+tagNames[i]+"";
editTagStr += tagNames[i];
if(i != tagNames.length-1) {
tagStr += ", ";
editTagStr += ",";
}
}



tagElem.innerHTML = tagStr;

tagElem.style.display = "block";
}catch(e) {}
}

function highlightMyTag() {
return;
}
function showTagEditBox(logno) {
try{
var tagElem = $('tagName_'+logno);
tagElem.style.display = "none";
var tagEditElem = $('edit_tagName_'+logno);
tagEditElem.style.display = "block";
}catch(e){}
}
function hideTagEditBox(logno) {
try{
var tagElem = $('tagName_'+logno);
tagElem.style.display = "inline";
var tagEditElem = $('edit_tagName_'+logno);
tagEditElem.style.display = "none";
}catch(e){}
}

function loadTagInfo () {
loadData("/BlogTagListInfo.nhn?blogId=idtong&logNo=130014995005", setTagListinfo);
}

function goPostView(logNo, postListTopCurrentPage) {
var url = "blogId=idtong&logNo=" + logNo +
"&categoryNo=0&viewdate=&cpage=1&postListTopCurrentPage=" + postListTopCurrentPage;
document.location.href = "http://blog.naver.com/PostView.nhn?" + url;
}
// Post 리스트의 페이지 이동
function goPageList(page) {
var url = "blogId=idtong&postListTopCurrentPage=" + page +
"&categoryNo=0&viewdate=";
$('postTop').src = "http://blog.naver.com/PostListTop.nhn?" + url;
settop();
}

















목록열기 전체목록 (573)



























백업과 복구 - 2. 백업과 복구의 전략 DataBase

2007/02/26 11:07



http://blog.naver.com/idtong/130014995005










출처 : http://www.sqler.pe.kr


10. 백업과 복구 - 2. 백업과 복구의 전략


 


이번에 소개해 드릴 내용은 백업과 복구의 전략 입니다.


실질적인 작업을 통해 여러가지 백업과정을 진행해 보도록 하지요.


 





 

USE master
GO

--백업을 테스트할 DB 생성
CREATE DATABASE bkupTest


 


먼저 테스트할 데이터베이스를 기본 옵션으로 생성합니다.


아시다시피 가장 기본적인 세팅이지요?


CREATE DATABASE 프로세스에서 'bkupTest' 디스크에 0.75MB를 할당하는 중입니다.
CREATE DATABASE 프로세스에서 'bkupTest_log' 디스크에 0.49MB를 할당하는 중입니다.


식의 메시지가 나오면 성공한 겁니다.


간단히 데이터베이스의 정보를 보도록 하지요.





 

--생성된 DB의 정보를 봅니다.


sp_helpdb bkupTest


go


 


어떠세요? 흥미있게 보실 부분으로..


status라는 부분을 보시면? Recovery=FULL 이라는게 있을 겁니다.


기본 옵션으로 데이터베이스를 생성하면 복구 모델은 FULL이라는 거지요.


 


백업의 타겟은 크게 두가지로 나눌수 있습니다.


디바이스와 화일 입니다.


디바이스라는 가상의 장치 또는 테입장치 등을 연결해 백업을 하거나..


화일단위로 백업을 하실 수 있습니다.


최근의 상황을 볼때 디스크가 매우 저렴해졌지요. 디바이스 백업을 수행시


디바이스라는 하나의 장치에 여러 백업을 두게 되므로 편할 수 있을지 모르나..


독립적인 화일로 위치시키실 경우 조금더 눈으로 쉽게 확인이 가능하므로


코난이의 경우 유지관리계획에 등록시켜 화일로 생성해 두는 것을 좋아 한답니다.


참고로 제가 말씀 드리는 디바이스는 영구 디바이스라고도 불리며


화일 단위 백업은 임디시바이스라고도 합니다.


차근차근 보도록 하겠습니다.


먼저 화일로 백업하는 경우 입니다.





 

--테이블을 생성 합니다.


USE bkupTest
GO



CREATE TABLE tblBkupTest(
name varchar(10)
, age int
)
GO

INSERT INTO tblBkupTest(name, age) VALUES('코난', 20)
INSERT INTO tblBkupTest(name, age) VALUES('까까', 30)
GO

--화일로 백업
BACKUP DATABASE bkupTest TO DISK='c:\bkupTest_full_bkup' WITH INIT
GO


이렇게 테이블을 생성하고 데이터를 넣은후 백업을 진행 했습니다.


백업후 결과는


1 파일에서 'bkupTest' 데이터베이스, 'bkupTest' 파일에 대해 96페이지를 처리했습니다.
1 파일에서 'bkupTest' 데이터베이스, 'bkupTest_log' 파일에 대해 1페이지를 처리했습니다.
BACKUP DATABASE이(가) 97페이지를 0.549초(1.436MB/초)만에 처리했습니다.


식으로 결과를 보실 수 있을 겁니다. - 결과역시 중요합니다. 특히 백업 수행 시각을


자세히 보는 습관을 들이세요.


복구는 어떻게 할까요? 간단히 해 보도록 할까요?





 

--테이블 삭제
DROP TABLE tblBkupTest
GO

--데이터 조회 불가.
SELECT * FROM tblBkupTest

--masterDB 사용 - 해당 DB가 사용중이면 복구가 불가하기 때문
USE master
GO

--복구
restore database bkupTest from disk ='c:\bkupTest_full_bkup'
GO


USE bkupTest
GO

--데이터 조회
SELECT * FROM tblBkupTest


 


복구시 완료 메세지는 다음과 같을 겁니다.


1 파일에서 'bkupTest' 데이터베이스, 'bkupTest' 파일에 대해 96페이지를 처리했습니다.
1 파일에서 'bkupTest' 데이터베이스, 'bkupTest_log' 파일에 대해 1페이지를 처리했습니다.
RESTORE DATABASE이(가) 97페이지를 0.732초(1.075MB/초)만에 처리했습니다.


역시나 주의하실 점으로 항상 복구 완료 시각을 눈여겨 보시길 바랍니다.


위의 케이스는 단순히 데이터베이스를 풀 백업 했습니다. WITH INIT은 해당 백업 타겟을


초기화 시키고 백업을 진행하라는 의미 이지요. - 백업의 여러 옵션은 천천히


다룰 겁니다.


아울러 풀 백업을 restore 구문으로 복구 했습니다.


DROP으로 날린 테이블이 잘 복구가 되었지요?


복구하기 전에 USE master 구문으로 master DB에서 복구를 진행한 이유는..


해당하는 DB가 사용중이면 복구가 불가하기 때문입니다.


만약 넷웍을 통해 사용자가 붙을 가능성이 있다면.. 잠시 사용자를..


sp_who 명령으로 SPID를 보신후.. KILL <SPID번호>로 죽이시고 수행하시면 되며


처음 SQL서버를 시작할때.. 시작 매개변수를 주어서..


sqlservr.exe -m   


형식으로 단일사용자 모드로 SQL서버 시작을 하시고.. 복구를 하시는것도 좋은


방법 입니다.


 


계속 이야기를 진행하죠.. 화일로 백업(임시 디바이스)하고 복구하는걸 해 보셨죠..


이젠 개인적으로 별로 사용하지 않지만.. 영구 디바이스를 생성하고


백업하고 복구하는것을 해 보도록 하지요.





 

--영구 백업 디바이스 생성
sp_addumpdevice 'disk', 'bkupTestDevice', 'c:\bkupTestDevice_full_bkup'

--디바이스로 백업 할때는?
BACKUP DATABASE bkupTest TO bkupTestDevice


 


결과를 보시면?


'Disk' 장치를 추가했습니다.


라는 결과와 함께 디바이스가 추가 된걸 아실 겁니다.


아울러.. 디바이스에 백업 완료시 메세지는..


1 파일에서 'bkupTest' 데이터베이스, 'bkupTest' 파일에 대해 96페이지를 처리했습니다.
1 파일에서 'bkupTest' 데이터베이스, 'bkupTest_log' 파일에 대해 1페이지를 처리했습니다.
BACKUP DATABASE이(가) 97페이지를 0.580초(1.357MB/초)만에 처리했습니다.


식일 겁니다.





 

--테이블 삭제
DROP TABLE tblBkupTest
GO

--데이터 조회 불가.
SELECT * FROM tblBkupTest

--masterDB 사용 - 해당 DB가 사용중이면 복구가 불가하기 때문
USE master
GO

--복구
restore database bkupTest from bkupTestDevice
GO



USE bkupTest
GO

--데이터 조회
SELECT * FROM tblBkupTest


 


복구시 메세지는 


1 파일에서 'bkupTest' 데이터베이스, 'bkupTest' 파일에 대해 96페이지를 처리했습니다.
1 파일에서 'bkupTest' 데이터베이스, 'bkupTest_log' 파일에 대해 1페이지를 처리했습니다.
RESTORE DATABASE이(가) 97페이지를 0.911초(0.864MB/초)만에 처리했습니다.


식일 것입니다. 아울러 데이터를 조회해 보면 잘 된것을 아실 겁니다.


많은 분들이 여기까지는 쉽게 이해하시고 잘 하시는데..


 


다음에 보시는 로그 백업에 대해서 많이 이해를 못하시지요.


이제 전략적인 측면에서.. 전체 / 로그 / 차등 백업을 이해해 보도록 하지요.


1. 풀백업만을 진행할 경우



먼저 이러한 타임라인이 있다고 생각해 봅시다.


주단위이며.. 위는 월요일 / 화요일 / ...  식으로 나올 겁니다.


두번째로. 시각은 08시부터 회사의 업무 시간인 6시까지 있을 겁니다.


이럴때 풀백업만을 진행할 경우 입니다. 풀 백업은 매일 아침 08시 업무가 시작되기 전에


이루어 집니다. 매일매일 하루에 한번씩 08시에 풀 백업을 받는 거지요!


이렇게 운영하시는 분들이 대단히 많을 겁니다. 문제 상황을 생각해 보지요.


1. 로그를 백업하지 않으므로 로그가 계속 불어나는 상황이 발생할 수 있다.


로그는 데이터의 변경본 입니다. 백업하면 지워지지만 지우지 않으므로.. 데이터는


50메가인데.. 로그는 1기가 이런 사태가 발생하게 되지요.


2. 문제 발생시 복구 가능한 데이터가 가장 적다.


실제 문제 상황을 생각해 봅시다.



자 이렇게 12시 30분에 데이터베이스가 깨졌다고 가정해 봅시다.


언제까지의 데이터로 복구가 가능할까요? - 진짜 쉽죠? ^_^;;


가장 최근의 백업본이 월요일 08시 이니..


월요일 08시의 데이터로만 복구가 가능한 겁니다. - 물론 한번도 백업한 적이 없다면?


복구 불가 하지요. -_-;; 


08시부터 4시간 30분간의 데이터는 복구가 불가해 지는 겁니다. 아득하지요.


만약 다른 분 말씀으로.. "그렇다면 풀백업을 한시간에 하나씩 받으면 되자나요"


하지만.. 여기에 맹점이 있을 수 있지요.


SQL2000부터는 대단히 백업작업이 가벼워 진 편입니다. 온라인상에서 백업을 진행해도


큰 무리없이 진행이 가능하지요. 하지만.. 대부분의 일반적인 회사에서..


데이터의 용량은 대단히 큽니다. 어느곳은 데이터가 1기가를 훌쩍 넘기도 하지요.


만약 이럴때 한시간에 한번씩 백업을 한다면? 대단히 많은 부하가 걸려 백업만 하다가


시스템 리소스를 다 잡아 먹힐수도 있게 되겠지요. 그래서 좋은 방법이 될 수 없습니다.


다른 방법으로 풀백업 + 로그 백업의 방법이 있습니다.


 


2. 풀백업 + 로그 백업



이러한 식으로.. 매일 아침 08시 풀 백업.. 매시간마다 로그를 백업하는 겁니다.


그럼 어떨까요? - 이때의 제약 사항으로 SQL서버의 해당 DB는 반드시 단순 모델이 아니어야


합니다. SQL서버의 데이터베이스가 단순 모델이면? 로그 백업이 불가해 집니다.


- 샘플에서 보여 드릴 거구요..  - 전체 모델이나.. 또는 대량 로그(Bulk Load)모드 


이어야 합니다.


"저렇게 한시간에 한번씩 로그를 백업하는것도 부하가 대단히 많지 않나요?"


라고 생각하실지도 모르지만.. 로그는 대단히 그 크기가 작습니다.


예를들어 게시판을 생각해 보세요. INSERT UPDATE DELETE 작업은 대단히 작지만..


실제 내용은 수천건이 들어가 있을 수 있지요. 실제 회사의 기간 데이터일 경우는


더더욱 그렇습니다. 이제 실제 문제 상황을 생각해 보도록 하지요.



이럴 경우는 어디까지 복구가 가능할까요?



이렇게 보는 바와 같이.. 08시 부터의 데이터가 저렇다고 생각해 보도록 하지요.


08시에 풀 백업본이 있었지요? 풀 백업본을 리스토어 하면? 데이터는 어떻게 될까요?



네 맞습니다. 위와 같은 데이터가 살아나겠지요?


그러면.. 우리는 여기까지만 복구가 가능한 걸까요? 아니요!!!


우리에겐 로그 백업본이 있었습니다. 09시의 로그 백업본을 리스토어 하면?


네 맞습니다.



이렇게 데이터가 수정된 녀석으로 복구가 되겠지요?


즉!! 로그는 데이터의 변경이므로.. 데이터의 변경을 그대로 적용시켜 나가면?


우리의 데이터가 나오게 되겠지요!!! - 이작업을 REDO라고 말하기도 합니다.


여기서 문제 입니다. 9시, 10시, 11시, 12시 까지의 로그를 잘 리스토어 했습니다.



여기까지 데이터를 잘 복구 했군요.


그렇지만.. 이후 12시 20분의 데이터는?


로그를 백업하지 못했지요? 그러므로 복구가 불가해 지는 겁니다.


단!!! SQL2000의 전체 복구 모델일 경우는 12시 20분뿐 아니라... 12시 29분 까지 복구가


가능합니다. - 이유는? 데이터베이스가 깨졌지만!!! 만약 데이터 화일만 깨지고


로그가 깨진것이 아니라면? 로그를 데이터베이스가 깨진 후 백업할 수 있습니다.


- 안될것 같지만 됩니다. - 그후!! 이 로그를 복구하면? 12시 29분까지의 데이터를


복구할 수 있게 되는 것이지요.


이 샘플은 잠시 후 보여 드리기로 하구요.


마지막으로 차등 모델에 대해서 간략하게 말씀 드리지요.


3. 차등 백업



로그 백업의 범위는 이렇습니다. 정확히 마지막 로그 백업 이후의 로그 데이터를


백업하게 되지요. 따라서.. 09시의 로그 백업은? 08시~09시 까지의 데이터 변경만을


백업하게 되며.. 10시의 로그 백업본은 09시~10시 사이의 데이터 변경만을.. 식으로


백업을 하게 됩니다.


하지만 차등 백업은?



이러한 방식으로.. 가장 최근의 풀백업본 부터 전체 변경을 포함하게 됩니다.


즉! 09시의 차등 백업본은? 08시~09시 까지의 데이터 변경을 가지게 되며


12시의 차등 백업본은? 08시~12시 까지의 데이터 변경을 가지게 됩니다.


로그를 중복해서 가지게 된다는 의미 이지요.


하지만 중복보다도.. 어느정도의 복구 속도를 높일 수 있으며..


SQL2000부터는 비트맵 백업 방식이라고 해서 대단히 빠르게 백업이 가능하다는 장점이


있게 되었습니다. 하지만 역시 개인적으로는 풀백업 + 로그 백업을 선호하며


여러 장점이 있기 때문에 더 선호합니다.


차등 백업일 경우 역시나 12시 30분에 데이터베이스가 깨졌다고 생각해 보도록


하지요.



이럴 경우 어떻게 복구를 하면 될까요?


08시의 풀백업본을 리스토어 합니다.


이어서!!!


12시의 차등 백업본 하나만!! 복구를 하면? 가능한 데이터의 복구가 된 것이겠지요.


 


자 세가지의 복구 방법을 차근차근 보신 겁니다.


이해가 되시나요?


그렇다면!!!


조금더 다른 이야기를 해 보도록 하지요.


복구 모델에 대한 이야기 입니다.


 


복구 모델


먼저 말그대로 단순한 단순 모델부터 보도록 하지요.


1. 단순 복구 모델





 

USE pubs
GO

--pubsDB의 복구 모델을 단순으로 한다.
ALTER DATABASE pubs SET RECOVERY simple

--풀 백업 수행
BACKUP DATABASE pubs TO DISK = 'c:\pubsFull' WITH INIT

--데이터 조회
SELECT TOP 1 title_id, price FROM titles

--조회된 값은? - 꼭 적으세요.

--데이터 수정
UPDATE titles SET price = price * 2

--데이터 조회 - 조회된값 꼭 적으세요.
SELECT TOP 1 title_id, price FROM titles

--복구 모델이 단순일 경우 로그 백업이 가능한가?
BACKUP LOG pubs TO DISK = 'c:\pubsLog' WITH INIT
--불가하다.

--SQL서버 시스템 종료SHUTDOWN

--탐색기등으로 pubs의 데이터 화일인
--mdf 화일을 지우자.
--C:\Program Files\Microsoft SQL Server\MSSQL\Data
--이 기본 경로이다.

--다시 SQL서버를 시작한다.


 


SQL서버를 시작하면 당연히 문제가 있습니다. PubsDB를 로드할 수 없다고 나오지요.



이런 식으로요..


pubs - 주의대상 - 바로 공포의 서스펙트 모드라고 하는 혼수상태 입니다.


이렇게 데이터베이스 이름이 나오는 이유는? 데이터베이스 이름과 같은 정보는


바로 MasterDB에 있기 때문입니다.


여하간 우리가 mdf 화일을 지웠으니 당연한가요? 이제 복구를 해 보도록 하지요.





 


--master DB 에서 작업한다.
USE master
GO

--데이터 조회가 가능한가?
SELECT TOP 1 title_id, price FROM pubs..titles
--불가하다.

--로그 백업이 가능한가? (이후 풀모델과 비교를 위해서 입니다.)
BACKUP LOG pubs TO DISK = 'c:\pubsLogNoTrunc' WITH NO_TRUNCATE, INIT
--불가하다.

--복구를 진행하자.
RESTORE DATABASE pubs FROM DISK = 'c:\pubsFull'

--데이터를 조회해 보자.
SELECT TOP 1 title_id, price FROM pubs..titles

--조회된 값은?


자 복구를 하고 조회를 해 보았습니다. 값이 얼마가 나왔죠?


BU1032 19.9900 


의 값이 나왔을 겁니다. 왜 그렇죠?


위에서 분명히 UPDATE를 한번 하지 않았나요?


하지만.. 우리가 UPDATE를 하기 전에 풀 백업을 진행 했지요?


아울러 로그 백업도 불가했고 데이터베이스가 깨진 이후에도 아무것도 할 수 없었기


때문에 오로지 가장 최근의 풀 백업본 까지만!!! 복구가 가능한 겁니다.


이게 바로 단순 모델입니다. - 물론 로그 백업 자체가 불가합니다.


하지만 자동으로 로그를 비워주니 로그가 한없이 커지는 사태는 발생하지 않지요.


다음으로 대량 로그 모델을 봐 보도록 할까요?



2. 대량 로그 모델


먼저 샘플텍스트화된 화일  을 다운로드 받으세요.


압축을 푸시면 titles.txt와 titles2.txt 화일이 있습니다.


아래 샘플에서 사용되니 이두 녀석을 c:\ 에 두시길 바랍니다.





 

--pubs DB를 대량 로그 모델로 바꾼다.
ALTER DATABASE pubs SET RECOVERY bulk_logged

--데이터베이스를 풀 백업 한다.
BACKUP DATABASE pubs to DISK = 'c:\pubsFull' WITH INIT

--데이터를 조회한다.
SELECT TOP 1 title_id, price FROM pubs..titles
--조회된 값은?

--가격을 *2 한다.
UPDATE pubs..titles SET price = price * 2

--데이터를 조회한다.
SELECT TOP 1 title_id, price FROM pubs..titles
--조회된 값은?

--BULK 작업을 한다.
--다운로드 받은 titles.txt 화일을 c:\에 둔다. - SQL7에서
--BULK 작업은 로그에 남지 않았으나 SQL2000에서는 남는다.
--일반적인 INSERT, UPDATE, DELETE는 기본적으로 로그에 남는다.
--그리고 작업한다.
BULK INSERT pubs..titles FROM 'c:\titles.txt'

--데이터를 조회한다.
SELECT top 2 title_id, price FROM pubs..titles
--Bulk INSERT로 삽입된 값은 BU1001 에 39.98이다.
--SQL7과 틀리게 sp_dboption없이 BULK INSERT가 가능하다.

--로그를 백업하자. - BULK INSERT가 로그에 남을까 남지 않을까?
--SQL7까지는 LOG에 남지 않는 작업이었다.
BACKUP LOG pubs TO DISK = 'c:\pubsLog' WITH INIT

--다시 하나의 데이터를 BULK INSERT로 넣자.
--지금 넣는 값은 title_id가 BU1002이며 가격은 23.9 이다.
BULK INSERT pubs..titles FROM 'c:\titles2.txt'

--데이터를 조회해 보자.
SELECT top 3 title_id, price FROM pubs..titles
--조회된 값은?

--역시나 시스템을 내리고 pubs의 mdf 화일을 지우자.
SHUTDOWN


 


자 이 샘플에서 언급하는 조회되는 값을 잘 적어 두시길 바랍니다.


그래야 어디까지 복구가 가능한지 알 수 있지요.


이제 복구 작업을 진행해 보도록 하지요.





 


--다시 SQL서버를 시작 시키자.
USE master
GO

--데이터가 조회 가능한가? - 불가하다. 
SELECT TOP 3 title_id, price FROM pubs..titles

--데이터베이스를 복구하자.
--현재 풀백업본을 복구하는 것이다.
--이후 LOG를 복구할게 더 있으므로 옵션으로
--WITH NORECOVERY를 붙인다.
RESTORE DATABASE pubs FROM DISK = 'c:\pubsFull' 
WITH NORECOVERY

--로그를 복구하자.
--이때 마지막 복구본 이므로
--WITH RECOVERY 옵션을 준다.
RESTORE LOG pubs FROM DISK = 'c:\pubsLog'
WITH RECOVERY

--데이터를 조회해 보자.
SELECT TOP 3 title_id, price FROM pubs..titles


데이터를 맨 마지막에 조회해 보니 어떤가요?


대량 로그 백업 샘플에서는 분명히 마지막에 어떤 값이었지요?


BU1001, BU1002, BU1032였을 겁니다. 분명히 LOG에 BULK INSERT의 데이터가 남았기


때문에 BU1001이 보이지요? 또한 두번째 BULK INSERT한 BU1002값은?


추후 로그를 백업하지 않았기 때문에 볼 수 없지요.


따라서.. 대량로드 작업에서는 가장 최근의 로그 백업본 까지만!!! 


복구가 가능한 겁니다.


이제 전체 모델을 봐 보도록 하지요.


 


3. 전체 모델





 

--사용된 데이터베이스를 최초 상태로 복구 합니다.
--맨처음 단순모델할때 사용했던 백업본입니다.
RESTORE DATABASE pubs FROM DISK = 'c:\pubsFull'

--다음 풀모델을 위해 풀백업을 진행합니다.
BACKUP DATABASE pubs TO DISK = 'c:\pubs1' WITH INIT

--데이터를 조회해 보면?
SELECT TOP 1 title_id, price FROM pubs..title
--조회된 값은?

--price를 *2 합니다.
UPDATE pubs..titles SET price = price * 2

--BULK INSERT로 데이터를 넣습니다. 값은 BU1001입니다.
BULK INSERT pubs..titles FROM 'c:\titles.txt'

--데이터를 조회하면?
SELECT TOP 2 title_id, price FROM pubs..titles
--조회된 값은?

--로그를 백업 합니다.
BACKUP LOG pubs TO DISK = 'c:\pubsLog' WITH INIT

--또다시 BULK INSERT를 합니다.
BULK INSERT pubs..titles FROM 'c:\titles2.txt'

--데이터를 조회하면?
SELECT TOP 3 title_id, price FROM pubs..titles
--조회된 값은?

--시스템 셧다운
SHUTDOWN

--pubs의 mdf 화일을 삭제 합니다. 단!
--ldf 화일은 건드리지 마세요.


mdf 화일을 삭제 했습니다. 조회된 값은 얼마죠?


BU1001, BU1002, BU1032일 겁니다. 그렇죠?


그럼 이제 복구를 해 볼까요?





 

--복구를 진행합니다.
USE master
GO

--데이터를 조회가 가능한가요? - 불가합니다.
SELECT TOP 2 title_id, price FROM pubs..titles

--로그를 백업합니다.
--바로 풀백업의 중요한 부분으로
--문제가 발생해도 로그가 깨지지 않았다면?
--로그가 백업이 됩니다.
--이때 반드시 WITH NO_TRUNCATE 옵션이 필요합니다.
--INIT는 초기화 시켜 백업하라는 옵션이지요.
BACKUP LOG pubs TO DISK = 'c:\pubsLogNoTrunc' WITH NO_TRUNCATE, INIT
--로그 백업이 성공합니다.

--데이터베이스를 복구해 보도록 하지요.
--복구할게 더 있으니 NORECOVERY로 합니다.
RESTORE DATABASE pubs FROM DISK = 'c:\pubsFull'
WITH NORECOVERY

--로그를 복구해 보도록 하지요.
--복구할게 더 있으니 NORECOVERY로 합니다.
RESTORE LOG pubs FROM DISK = 'c:\pubsLog'
WITH NORECOVERY

--로그를 복구해 보도록 하지요.
--이 로그는? pubs가 깨진후 로그만 백업한것이죠?
--위에서 옵션인 WITH NO_TRUNCATE옵션으로 백업한 로그 입니다.
--복구할게 더이상 없으니 RECOVERY로 합니다.
RESTORE LOG pubs FROM DISK = 'c:\pubsLogNoTrunc'

--데이터를 조회해 보면?
SELECT TOP 3 title_id, price FROM pubs..titles
--어디까지 복구가 되었나요?


 


자 여기까지 보셨으면 이제 다 보신 겁니다.


어떠세요? 데이터 백업 + 로그백업 이해 되시나요?


아울러 SQL2000의 새로운 복구 모델 세가지두 이해 되시구요?


그럼 이제 많이 받는 질문인....  개발자나 관리자의 실수로..


WHERE절 없이 DELETE나 UPDATE를 쳐 버렸을때 복구하는 방법을 말씀 드리지요.


 


4. STOPAT을 이용한 복구


이때는 반드시 모델이 전체 모델 또는 대량 로그 이어야 합니다.





 

--데이터베이스를 초기화 시키기 위해 리스토어 합니다.
RESTORE DATABASE pubs FROM DISK = 'c:\pubsFull'

--데이터베이스를 풀 백업 합니다.
BACKUP DATABASE pubs TO DISK = 'c:\pubs1' WITH INIT

--데이터를 조회합니다.
SELECT TOP 1 title_id, price FROM pubs..titles
--초기화가 잘 되었는지 확인하는 겁니다.

--데이터를 하나 삽입 합니다.
BULK INSERT pubs..titles FROM 'c:\titles.txt'

--데이터를 조회하면?
SELECT TOP 2 title_id, price FROM pubs..titles
--조회된 값은?

--로그를 백업해 보도록 하지요.
BACKUP LOG pubs TO DISK = 'c:\pubsLog' WITH INIT

--역시나 데이터를 하나 더 넣도록 합니다.
BULK INSERT pubs..titles FROM 'c:\titles2.txt'

--데이터를 조회하면?
SELECT TOP 3 title_id, price FROM pubs..titles
--조회된 값은?

--!!자 이제 문제 상황입니다.
--개발자의 실수로 UPDATE를 WHERE절 없이 쳐버렸습니다.
UPDATE pubs..titles SET price = 0

--컨트롤 + Z는 아무리 눌러도 데이터는 복구 안됩니다.
SELECT title_id, price FROM pubs..titles

--바로 문제가 발생한 시각을 알아야만 합니다.
SELECT GETDATE()
--결과 시각은?
--코난이의 경우 아래와 같은 시각 입니다.
2001-08-23 16:06:14.320

--어떻게 해야 할까요?
--1. 즉시 로그를 백업 합니다.
--2. STOP AT 구문으로 복구 합니다.

--로그를 백업 합니다.
BACKUP LOG pubs TO DISK = 'c:\pubsLogNoTrunc' WITH NO_TRUNCATE, INIT

--데이터베이스를 복구합니다.
--이때 첫번째 로그 백업과.. 문제가 발생한후 로그 백업 사이로
--복구를 진행해야 합니다. 그렇지요?
--STOP AT을 적절히 사용하도록 하지요.
--풀 백업본을 리스토어 합니다.
RESTORE DATABASE pubs FROM DISK = 'c:\pubsFull'
WITH NORECOVERY

--첫번째 로그 백업본을 복구 합니다.
RESTORE LOG pubs FROM DISK = 'c:\pubsLog'
WITH NORECOVERY

--문제가 발생한후 로그를 백업한 것입니다.
--약간 특이하게 STOP AT이 있습니다.
--시각 지정은.. 문제가 발생한 시각 - 1분 정도로 하겠습니다.
--2001-08-23 16:06:14.320 빼기 1분
--그래야만.. 문제가 발생하기 바로 전 시각으로 되돌릴 수 있겠지요?
--당연히 문제가 발생한후 즉시 알아야만 데이터 손실을 그만큼 줄일수 있겠죠
--한 일주일 정도 지난후 문제가 발생한걸 알고.. 또한
--중요한 회원 데이터였다면? 생각하기도 끔찍해 지겠지요.
RESTORE LOG pubs FROM DISK = 'c:\pubsLogNoTrunc'
WITH STOPAT = '2001-08-23 16:05:14.320', RECOVERY

--데이터를 조회해 보면?
SELECT TOP 3 title_id, price FROM pubs..titles
--원하는 데이터인 BU1001, BU1002, BU1032가 맞습니까?


어떠세요?


이제 STOPAT을 어떻게 사용하는지 감이 좀 잡히시나요? ^_^


자.. 그러면!!


이제 자동화를 이용해서 이러한 백업과 리스토어를 쉽게 하는 이야기를 조금


드려 보지요.


데이터베이스 유지관리 계획은.. 총체적으로 데이터베이스를 유지 관리하기 위한


기능입니다.


백업 / 인덱스 구축 등등의 관리자의 손이 개입되어야 하는 작업들을..


자동적으로 수행할 수 있게 도움을 주는 매우 유용한 기능입니다.



이렇게 해당 DB에서.. 유지관리 계획을 선택 합니다.


 



해당 데이터베이스를 선택 하구요.


아래쪽의 트랜젝션 로그를 다른 SQL서버로 전달 - 항목은.. 로그 전달이라는 다른


모델을 구축하기 위한 것입니다. 다음 강좌에서 소개해 드릴 겁니다.


 



최적화는 인덱스에서 설명드린 FILLFACTOR를 말하는 겁니다.


10으로 잡은 것은.. FILL FACTOR 값이 90이라는 것이지요.. 일정 여유를 둔다는


것입니다. 실제 시스템일 경우 잡아 줘야 하며.. 적절히.. 아래 일정 부분을 선택해..


하루에 한번 식으로 유지해 줘야 합니다.


아래의 공간 제거는.. AUTO SHRINK로.. 빈공간 유지인데.. 사실 거의 필요 없으며..


부하를 주므로 선택하지 않는것이 좋습니다.


 



무결성 검사는..


DBCC CHECKDB 명령입니다. 데이터베이스 개체들의 무결성을 검사하는 것이지요.


예를들어.. 인덱스와 데이터를 연결하는 체인이 끊어지거나 하는 검사를 하며


고치는 기능입니다. 주기적으로 물론 해주는 것이 좋습니다. 또한..


백업전헤 하길 권장하는 이유는?


깨진 데이터를 백업하면 의미가 있을까요? 따라서.. 약간의 비용이 더 들지만..


백업전에 해주는 것이 좋습니다. 일정은 역시 적절히 잡아 주시구요.


 



이 백업 계획 지정은..


풀백업 진행 여부를 묻는 것이며 당연히 해야 겠지요. ^_^;;


완료시 백업본의 무결성 자동 검사..


또한 테입 장치 OR 디스크로 할 수 있습니다. 일정은 백업 전략대로 적절히 잡아


주셔야 겠지요?


 



디렉토리 지정이며.. 당연히.. 디스크가 통째로 깨져버리는 사태를 대비해..


데이터가 있는 디스크와는 다른 물리적인 디스크를 지정해야겠지요?


데이터베이스마다 하위 디렉 만들기는.. 개인적으로 구분이 잘되어 선호합니다.


4주 이상이 지나면 사실 별 의미가 없으니 자동으로 지우게 선택합니다.


물론 4주가 아니라.. 적절히 적용하셔도 되겠지요?


백업 화일의 확장자는 개인적으로 적었습니다. BAK라고만 하지 마세요.


 



트랜젝션 로그를 백업할지 묻는 겁니다. 풀백업과 같습니다.


적절히 일정을 잡아 주시면 되겠지요.


 



로그백업화일에 대한 정보를 지정해 주는 겁니다. 풀백업과 비슷 하지요?


 



완료 정보 등을 보고서로 쓰게 됩니다. 어렵지 않으실 것이며..


아래 보시면 운영자가 나오는데요.. 운영자를 등록하면 나타나게 되며..


메일 / NET SEND명령 등으로 알림이 가능합니다.


 



유지 관리에 대한 기록은 MSDB에 저장되는데요. 여기에 쓸것인지.. 아울러 쓴다면


로우의 갯수를 얼마로 제한할지 결정하는 것입니다.


원격서버는 MSX서버라고 해서.. 다른 시스템에 쓰는 것입니다.


 



주의하실 점으로.. 이런 유지관리계획과 같은 스케쥴 작업을 수행 하려면?


반드시 SQL SERVER 에이젼트가 실행중이어야 합니다.


확인하셔야 하는 부분이구요. 


 


실질적으로 이를 비쥬얼하게 보실 수 있습니다.


SQL7 강좌에서 같은 이야기를 드렸지요. 또한 복구를 엔터프라이즈 관리자에서


진행하는 방법 역시 있습니다. 이에 대한 글은


자동화를 이용한 관리작업


부분을 보시면 실제 온라인 시스템을 흉내 내면서 데이터를 지속적으로


계속 삽입 합니다. - 실제 시스템 흉내내기.


그러면서 스케쥴을 이용한 백업을 위의 그림들보다 좀더 상세히 표현해


실제 백업되는 데이터와 로그 백업 데이터를 확인하실 수 있으며


리스토러 하는 화면 역시 쉽게 보실 수 있으니 참고 하세요.


또한 STOPAT을 엔터프라이즈 관리자에서 하는 화면 역시 보실 수 있으니 참고 하세요.


 


이정도면 백업에 대한 이야기는 대강 마무리 된듯 하네요.


엔터프라이즈로 복구하는 샘플들은?


SQL7 기본강좌 - 백업의 전략 부분을 참고 하시길 바랍니다.


대단히 간단합니다. - 하지만..


가급적이면.. 스크립트로 구성해 두셔서.. 빠르게 복구 가능하도록 하시는 것도 좋지요


 


백업과 복구의 가장 중요한 부분은 얼마나 자주 백업할 것인가를 결정하는 부분과


어떤 백업과 복구 방식을 사용할 것인가의 적절한 선택 입니다.


이정도로 마치고.. 다음 이야기를 진행하도록 하지요.




이 포스트를..


덧글 쓰기 엮인글 쓰기


빈우산쓰기~ 백업과 복구 - 2. 백업과 복구의 전략
빈우산쓰기~ 백업과 복구 - 2. 백업과 복구의 전략
































var viewer_image_url = "http://blogimgs.naver.com/blog20/blog/layout_photo/viewer/";
var photo = new PhotoLayer(parent);
photo.Initialized();
window.onunload = function()
{
photo.oPhotoFrame.doFrameMainClose();
}.bind(this);







//cm_paperInit();
loadSympathyInfo();
loadBlinkInfo();


loadTagInfo();


/* 태그별 포스트 정보 보기 페이지 호출 */
function forwardTag(blogid, tagname) {
document.forwardTag.blogId.value = blogid;
document.forwardTag.tagName.value = tagname;
document.forwardTag.submit();
}

by 딸기아부지 | 2007/03/20 16:20 | DB관련 주워온 글 | 트랙백 | 핑백(1)
동적 SQL
동적 SQL TUNING TIP

2006/01/08 12:07

http://blog.naver.com/swinter8/130000770771

동적SQL

반복적으로 사용되는 SQL 문법을 저장해 두었다가 필요할때 조건절만 사용자로부터 입력받아 실행시킬수 있는데  이런유형의 SQL을 동적(Dymamic)SQL 이라 한다.

PL/SQL에서 동적 SQL을 실행할 때는 EXECUT IMMEDIATE 명령어를 사용한다. 또한 동적 SQL에서 정의된 조건값을 전달할 때에는 USING 절을 사용한다.  

 

예제 1)

set serveroutput on

create or replace procedure dsql_test
  (v_empno number)

is
sql_stmt varchar2(200);
emp_rec emp%ROWTYPE;


begin
sql_stmt :='SELECT * from emp where empno= :id';        -- 자주사용돠는 sql문을 변수로 저장

execute immediate sql_stmt into emp_rec using v_empno;  

                                                     -- 변수에 저장된 sql문을 호출. v-empno 가  :id로 저장

    DBMS_OUTPUT.PUT_LINE( '사원번호 : ' || emp_rec.empno );      
    DBMS_OUTPUT.PUT_LINE( '사원이름 : ' || emp_rec.ename );      
    DBMS_OUTPUT.PUT_LINE( '입 사 일 : ' || emp_rec.hiredate ); 

 

execute immediate sql_stmt into emp_rec using v_empno;    -- 변수에 저장된 sql 문 호출
    DBMS_OUTPUT.PUT_LINE( '**********************************************');
    DBMS_OUTPUT.PUT_LINE( '사원번호 : ' || emp_rec.empno );      
    DBMS_OUTPUT.PUT_LINE( '사원이름 : ' || emp_rec.ename );      
    DBMS_OUTPUT.PUT_LINE( '입 사 일 : ' || emp_rec.hiredate ); 
    DBMS_OUTPUT.PUT_LINE( '월급 : ' || emp_rec.sal ); 

end;
/

execute dsql_test(7369)

 

*************************************************************************

예제 2)

DROP TABLE BONUS;

 

DECLARE
  dept_id    NUMBER(2)  := 50;
  dept_name  VARCHAR2(14) := 'PERSONAL';
  emp_id     NUMBER(4) := 7934;
  emp_rec    EMP%ROWTYPE;
  location   VARCHAR2(13) := 'DALLAS';
  sql_stmt   VARCHAR2(200);
  salary     NUMBER(7,2);

 

BEGIN
     EXECUTE IMMEDIATE 'create table bonus (id number, amt number)';

  sql_stmt := 'insert into dept values (:1, :2, :3)';
    EXECUTE IMMEDIATE sql_stmt USING dept_id, dept_name, location;

 sql_stmt := 'select * from emp where empno = :id';
    EXECUTE IMMEDIATE sql_stmt  INTO emp_rec USING emp_id;

 sql_stmt := 'update emp set sal = 2000 where empno = :1 returning sal into :2';
    EXECUTE IMMEDIATE sql_stmt USING emp_id   RETURNING INTO salary;

END ;
/

 

DESC BONUS;
SELECT * FROM DEPT;
SELECT * FROM EMP WHERE EMPNO=7934;
ROLLBACK;

*************************************************************************

예제 3 - 동적 sql의 명시적 커서

 

DECLARE
emp_rec emp%rowtype;
sql_stmt varchar2(200);
my_job varchar2(15) := 'CLERK';

TYPE empcurtyp is ref cursor;      -- 커서의 선언
emp_cv empcurtyp;                     -- 커서를 재사용하기 위해서 재 정의 했다

 

begin
  sql_stmt := 'SELECT * FROM emp WHERE job= :j';
  OPEN emp_cv for sql_stmt using my_job;               -- 커서 시작

    LOOP  
        FETCH emp_cv into emp_rec;                         -- 조건값 인출
           exit when emp_cv%notfound;
           dbms_output.put_line(emp_rec.empno||' '||emp_rec.ename);
   end loop;
  close emp_cv;                                                    -- 커서 종료
end;
/

**********************************************************

 

             PL/SQL에서 동적 SQL 사용
                              
                                         작성일 : 2002/08/24
                                         작성자 : 오범석
                                         E-MAIL : refreshman@chollian.net
                                        
                                        
오라클의 PL/SQL에서 동적 SQL을 사용하기 위한 방법에 대해 설명한다.
우선 동적 SQL이란 무엇을 말하는 것일까?

보통 PL/SQL에서 CURSOR사용을 위해서는 선언부에 CURSOR를 선언하고
CURSOR를 생성할 SQL을 선언한다.


====================================================================

CREATE OR REPLACE PROCEDURE call_me(ICALL_ID CHAR) AS

    --커서 선언부...
    CURSOR cur1 IS
        SELECT CALL1, CALL2, CALL3
          FROM CALL_TABLE
         WHERE CALL_ID = ICALL_ID;
  
BEGIN

.............나머지 생략 .................

END;
/
SHOW ERRORS  

====================================================================


위에서의 코드에서 볼수 있듯이 CURSOR 선언시 해당 SQL을 지정하는데.
입력값인 ICALL_ID 를 WHERE 절에 조건으로 사용하는것은 가능하다.

문제는 조건에 따라 필드명이나 테이블이 바뀌거나 SQL문이 전혀 다르게
생성된다면 어떻게 할까?

이런 문제에 봉착했을때 동적 SQL을 사용한다.

 

====================================================================

CREATE OR REPLACE PROCEDURE call_me(ICALL_TYPE CHAR) AS


    our_cursor INTEGER;  --커서변수선언
    status  INTEGER;  --커서의 ID를 저장
    sql_str  VARCHAR2(100); --질의어 저장

    --바인딩 변수 선언
    v_CALL1  VARCHAR2(30);
    v_CALL2  VARCHAR2(30);
    v_CALL3  VARCHAR2(30);

BEGIN

    IF ICALL_TYPE = 'ME' THEN
        sql_str := ' SELECT CALL1, CALL2, CALL3 ' ||
                   '   FROM CALL_ME             ';
    ELSIF ICALL_TYPE = 'YOU' THEN
        sql_str := ' SELECT CALL1, CALL2, CALL3 ' ||
                   '   FROM CALL_YOU            ';
    ELSIF ICALL_TYPE = 'WE' THEN
        sql_str := ' SELECT CALL1, CALL2, CALL3 ' ||
                   '   FROM CALL_WE             ';
 
    END IF;

    --동적 쿼리 사용을 위한 커서 생성
    our_cursor := DBMS_SQL.OPEN_CURSOR;

    --SQL문 파싱
    DBMS_SQL.PARSE(our_cursor,sql_str,DBMS_SQL.V7);

    --각 컬럼을 바인딩한다.
    --인자 : (커서, 필드순번, 바인딩변수, 값의 길이)
    DBMS_SQL.DEFINE_COLUMN(our_cursor,1,v_CALL1,30);
    DBMS_SQL.DEFINE_COLUMN(our_cursor,2,v_CALL2,30);
    DBMS_SQL.DEFINE_COLUMN(our_cursor,3,v_CALL3,30);

    --커서 ID를 저장한다.
    status := DBMS_SQL.EXECUTE(our_cursor);

    --자료를 출력한다.
    LOOP
        IF DBMS_SQL.FETCH_ROWS(our_cursor) > 0 THEN
 
            --데이터를 변수에 할당한다.
            DBMS_SQL.COLUMN_VALUE(our_cursor,1,v_CALL1);
            DBMS_SQL.COLUMN_VALUE(our_cursor,2,v_CALL2);
            DBMS_SQL.COLUMN_VALUE(our_cursor,3,v_CALL3);
 
            DBMS_OUTPUT.PUT_LINE('1번째 ==> '||v_CALL1);
            DBMS_OUTPUT.PUT_LINE('1번째 ==> '||v_CALL1);
            DBMS_OUTPUT.PUT_LINE('1번째 ==> '||v_CALL1);
  
        ELSE
            EXIT; --LOOP를 빠져나간다.
        END IF;
     END LOOP;

    --커서를 닫는다.
    DBMS_SQL.CLOSE_CURSOR(our_cursor);

    --에러 처리
    EXCEPTION
    WHEN OTHERS THEN
        --사용자 정의 핸들러.
        errhandle(SQLERRM);
 

END;
/
SHOW ERRORS

====================================================================

위의 코드에서 보는것과 같이 다음과 같은 순서를 통해 동적 SQL을 실행한다.

1. 선언부에 커서, 질의어저장변수, 커서 ID, 값을 바인딩할 변수를 선언한다.
2. 로직을 통해 SQL문을 생성한다.
3. 동적쿼리 사용을 위한 커서 생성한다.]
4. SQL을 파싱하여 커서에 할당한다.
5. 해당 컬럼을 변수에 바인딩 시킨다.
6. 커서의 SQL을 실행한다.
7. 커서를 패치하면서 바인딩한 변수에 해당 필드값을 설정한다.


동적 SQL은 PL/SQL을 사용하여 시스템을 구축시 한번은 사용하게 된다.

물론 동적 SQL을 사용하지 않고 프로그램을 구현할수도 있다.

위에 예제를 동적 SQL을 사용하지 않고 구현하려면 우선 입력될 TYPE이 몇
개인지 우선 알고 해당 CURSOR를 모두 선언부에 선언하고 프로그램을
구현하는것인데.. 이것은 비효율적인 프로그램이 된다.

더 상세한 정보는 ORACLE DEVELOPER GUIDE를 참고 하길 바란다.

by 딸기아부지 | 2007/03/18 20:35 | DB관련 주워온 글 | 트랙백 | 핑백(1)
Oracle 9i : Archive log mode로 변경 |
[솔라리스] Oracle 9i : Archive log mode로 변경 | Oracle-관리하기  2006.11.14 09:49 

교(yeskko)   http://cafe.naver.com/yeskko/112 


로컬 서버의 콘솔, 터미널 또는 ssh로 접속하여 아래 순서대로 작업한다.
spfile로 인스턴스를 실행하는것으로 가정한다.
spfile 사용여부 확인과 전환은 본 게시판의 55번 글을 참고하기 바람.

1. # su - oracle
2. oracle# sqlplus /nolog
3. SQL> connect /as sysdba
4. SQL> shutdown immediate
5. SQL> startup mount
6. SQL> alter system set log_archive_start = true scope=spfile;
7. SQL> alter system set log_archive_dest = '/로그저정위치' scope = spfile;
8. SQL> alter system set log_archive_format = '파일명_%s.arc' scope = spfile;
9. SQL> alter database archivelog;
10. SQL> alter database open;


설명
1. DBA 권한을 갖고있는 시스템 계정으로 로그인한다. (오라클 설치시 생성한 계정)
2. sqlplus를 실행한다.
3. sqlplus에서 sysdba로 연결한다.
4. 실행중인 DB를 중지한다.
5. DB를 mount모드로 시작한다. (제어파일 실행)
6. archive로그를 자동으로 실행한다.
7. 로그저장 위치를 지정한다.
8. 로그 파일명을 지정한다.
9. 아카이브 로그 모드로 전환한다.
10. DB를 open모드로 전환한다. (DB 서비스 시작)
by 딸기아부지 | 2007/03/16 13:59 | DB관련 주워온 글 | 트랙백 | 핑백(1)
CLOB을 VARCHAR로 변환
CLOB을 VARCHAR로 변환
dbms_lob.substr을 사용한다.

dbms_lob.substr( clob_column, for_how_many_bytes, from_which_byte );

select dbms_lob.substr( x, 4000, 1 ) from T;

PLSQL에서는 long형 변수에 할당하여 변환할 수 있다.


declare
    my_var long;
begin
    for x in ( select X from t )
    loop
       my_var := dbms_lob.substr( x.X, 32000, 1 );
       ....
by 딸기아부지 | 2007/03/15 20:53 | DB관련 주워온 글 | 트랙백 | 핑백(1)


< 이전페이지 다음페이지 >