레이블이 java인 게시물을 표시합니다. 모든 게시물 표시
레이블이 java인 게시물을 표시합니다. 모든 게시물 표시

2024년 6월 9일 일요일

Java class file version error

 

Error: A JNI error has occurred, please check your installation and try again

Exception in thread "main" java.lang.UnsupportedClassVersionError: com/android/sdklib/tool/sdkmanager/SdkManagerCli has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 52.0


Java 클래스 파일 버전과 JDK 릴리스 버전 참고

  • 클래스 파일 버전 45.0: Java 1.1
  • 클래스 파일 버전 46.0: Java 1.2
  • 클래스 파일 버전 47.0: Java 1.3
  • 클래스 파일 버전 48.0: Java 1.4
  • 클래스 파일 버전 49.0: Java 5 (JDK 1.5)
  • 클래스 파일 버전 50.0: Java 6 (JDK 1.6)
  • 클래스 파일 버전 51.0: Java 7 (JDK 1.7)
  • 클래스 파일 버전 52.0: Java 8 (JDK 1.8)
  • 클래스 파일 버전 53.0: Java 9
  • 클래스 파일 버전 54.0: Java 10
  • 클래스 파일 버전 55.0: Java 11
  • 클래스 파일 버전 56.0: Java 12
  • 클래스 파일 버전 57.0: Java 13
  • 클래스 파일 버전 58.0: Java 14
  • 클래스 파일 버전 59.0: Java 15
  • 클래스 파일 버전 60.0: Java 16
  • 클래스 파일 버전 61.0: Java 17


2019년 12월 29일 일요일

java JAVA_HOME 설정


예전에 java는 설치하고 나면 자동으로 path를 설치해줬는것 같은데 요즘은 그런것이 없는지 실행시 오류가 나옵니다.

jdk 설치후 cmd 창에서 java 실행이 안되면 java 환경 설정을 하도록 합니다.


환경 windows 10, jdk 13.0.1 기준

java기본 설치 위치는 : C:\Program Files\Java\jdk-13.0.1


환경 변수 등록
윈도우 창에 '환경'으로 검색하여 시스템 환경 변수 편집


PATH 와 JAVA_HOME 등록 필요
JAVA_HOME => C:\Program Files\Java\jdk-13.0.1





PATH => %JAVA_HOME%\bin 추가
시스템 변수에 path 항목을 선택한후 편집



적용 후에는 cmd 창을 닫고 새로 열어야 합니다
java가 실행되는지 확인하면 됩니다.




2018년 6월 17일 일요일

analysis http server (JLHTTP) source for upload in android (파일 upload를 위한 웹서버 소스 코드 분석) #2




앞에서 https://swlock.blogspot.com/2018/06/analysis-http-server-jlhttp-source-for.html JLHTTP를 실행시키는 방법에 대해서 알아보았습니다.

최초 이글을 쓰게되는 upload 관련해서 예제가 없어서 확인이 어려웠습니다. 예제는 구하기 어려웠지만 FAQ에서 중요한 단서를 찾았습니다.

아래 내용입니다.
How do I handle uploaded files?
When an HTML form is used to upload a file or other large content, the default application/x-www-form-urlencoded encoding is insufficient. In this case, the form is submitted as a multipart body of a POST request with the multipart/form-data content type instead. The parts are sent in the same order as the form fields.

You can use a MultipartIterator to parse the request body and iterate over its parts. String values can be conveniently retrieved as such, but the file can be read directly as a stream, thus preventing various issues that would arise from holding the entire file contents in memory at once.
Here's a basic example:
String comment;
String filename;
File file;
Iterator<Part> it = new MultipartIterator(request);
while (it.hasNext()) {
    Part part = it.next();
    if ("comment".equals(part.getName())) {
        comment = part.getString()
    } else if ("file".equals(part.getName())) {
        filename = part.getFilename();
        file = File.createTempFile(filename, ".uploaded");
        FileOutputStream out = new FileOutputStream(file);
        try {
            transfer(part.getBody(), out, -1);
        } finally {
            out.close();
        }
    }
}
// now do something with the comment, filename and file
Alternatively, you can use the lower-level MultipartInputStream directly.

그렇지만 어떻게 하는것인지 해당 코드를 어떻게 넣어야 하는것인지 몰라서 만들어 보았습니다.

main 코드에 위 내용을 추가 하여 보았습니다.
아래 예제는 파일을 upload하게되면 temp영역에 파일을 저장하는 내용입니다.

    public static void main(String[] args) {
        try {
            if (args.length == 0) {
                System.err.printf("Usage: java [-options] %s <directory> [port]%n" +
                    "To enable SSL: specify options -Djavax.net.ssl.keyStore, " +
                    "-Djavax.net.ssl.keyStorePassword, etc.%n", HTTPServer.class.getName());
                return;
            }
            File dir = new File(args[0]);
            if (!dir.canRead())
                throw new FileNotFoundException(dir.getAbsolutePath());
            int port = args.length < 2 ? 80 : Integer.parseInt(args[1]);
            // set up server
            for (File f : Arrays.asList(new File("/etc/mime.types"), new File(dir, ".mime.types")))
                if (f.exists())
                    addContentTypes(f);
            HTTPServer server = new HTTPServer(port);
            if (System.getProperty("javax.net.ssl.keyStore") != null) // enable SSL if configured
                server.setServerSocketFactory(SSLServerSocketFactory.getDefault());
            VirtualHost host = server.getVirtualHost(null); // default host
            host.setAllowGeneratedIndex(true); // with directory index pages
            host.addContext("/", new FileContextHandler(dir));
            host.addContext("/api/time", new ContextHandler() {
                public int serve(Request req, Response resp) throws IOException {
                    long now = System.currentTimeMillis();
                    resp.getHeaders().add("Content-Type", "text/plain");
                    resp.send(200, String.format("%tF %<tT", now));
                    return 0;
                }
            });
            host.addContext("/upload", new ContextHandler() {
                public int serve(Request req, Response resp)  {
                 System.out.println("upload");
                 String comment="";
                 String filename="";
                 File file;
                 try {
                  Iterator<MultipartIterator.Part> it = new MultipartIterator(req);
 
                  while (it.hasNext()) {
                   MultipartIterator.Part part = it.next();
                   System.out.println(part.getName());
                      if ("comment".equals(part.getName())) {
                          comment = part.getString();
                      } else if ("file1".equals(part.getName())) {
                          filename = part.getFilename();
                          file = File.createTempFile(filename, ".uploaded");
                          System.out.println(file.getAbsolutePath());
                          FileOutputStream out = new FileOutputStream(file);
                          try {
                              transfer(part.getBody(), out, -1);
                          } finally {
                              out.close();
                          }
                      }
                  }
                 } catch (Exception e ){
                  e.printStackTrace();
                 }
                    resp.getHeaders().add("Content-Type", "text/plain");
                    try {
      resp.send(200, "Hello, World!"+comment+" "+filename);
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
                    return 0;
                }
            },"POST");
            server.start();
            System.out.println("HTTPServer is listening on port " + port);
        } catch (Exception e) {
            System.err.println("error: " + e);
        }

살펴보아햐 하는 부분은 addContext /upload 하는 부분입니다.
host.addContext("/upload", new ContextHandler() {

제작자는 이것을 context handler 라고 부르며, http로 path 요청이 들어오면 그것을 처리하기 위한 context 라고 보면 됩니다.

html 페이지도 준비하였습니다. 이때 form의 action 부분을 "upload"로 한 이유는 context 처리 페이지가 upload이기 때문에 맞추어 주어야 합니다. 그리고 form은 다음과 같이 값을 맞추어야 합니다. method="POST" enctype="multipart/form-data"

index.html
<html>
<body>
<form action="upload" method="POST" enctype="multipart/form-data" name="">
 <div>
   <label for="file">Choose file to upload</label>
   <input type="file" id="file1" name="file1" >
 </div>
 <div>
   <label for="file">Choose file to upload</label>
   <input type="file" id="file2" name="file2" >
 </div>
 <div>
   <button>Submit</button>
 </div>
</form>
</body>
</html>

JLHTTP를 실행하고 localhost로 접속을 하면 아래와 같이 나옵니다.
(실행방법을 잘 모르겠으면 이전 링크를 참고하세요.)
1.png(임의의 파일)파일을 선택해서 submit 버튼을 누르면 다음과 같이 나옵니다.


HTTP 서버측 로그 화면
HTTPServer is listening on port 8080
upload
file1
C:\Users\xxx\AppData\Local\Temp\1.png3242384259546787045.uploaded
file2


전체 소스 링크 입니다.

소스는 파일 하나로 구성되어 있어 http server의 동작을 이해하는 좋은 참고 소스가 될것이라고 생각됩니다. 참고로 라이센스는 GPL 입니다.







2018년 6월 11일 월요일

analysis http server (JLHTTP) source for upload in android (파일 upload를 위한 웹서버 소스 코드 분석)


java로 웹서버를 간단하게 만드는 것은 어렵지 않습니다. 그러나 전체 기능이 제대로 구현된 소스는 많지 않고, 대부분 서블릿이나 JSP에 촛점이 맞추어져 있어서 원하는것을 찾기가 쉽지는 않습니다.

여기에서 알아보고자 하는것은 아래와 같습니다.

1. java로 구현된 http 서버(JLHTTP) 소스 동작 모습 (이번 내용)


2. 파일 upload를 하게되면 소스코드 어디 에서 처리를 하는지? (다음 내용)


이 글을 쓰는 목적은 웹방식의 응용프로그램을 만들기 위함입니다. 최종 사용자가 보면 local web server를 접속하게되고 브라우저를 오픈하여 특정 파일들을 선택해서 submit 을 하면 처리하여 web page로 결과를 돌려주는 동작입니다.
이것을 위해서 왜 web 방식을 해야하는지는 중요하지 않습니다. 아주 특별한 환경에서 처리를 위해서, 다만 이것을 위해서는 JSP 또는 서브릿을 사용해도 관계는 없지만, 구현 환경을 최대로 단순하게 처리하기 위해서 입니다.


소스 얻기

JLHTTP https://www.freeutils.net/source/jlhttp/
License 는 GPL 입니다. 코드는 공개되어 있지만 사용시 코드를 공개해야하는 라이센스입니다.

소스 폴더 구성

받은 소스는 java소스 하나와 jar 파일 하나로 구성되어있습니다. 아래와 같이 배치되도록 프로젝트를 만듭니다. (lib의 jar 파일은 필요가 없어도 실행하는데 문제가 없었습니다.)


실행하기

실행시키기 위해서는 인자가 2개가 필요합니다. 홈페이지 폴더와 서버 포트 번호입니다.


브라우저로 다음 주소를 접속합니다. http://localhost:8080/
실행하면 아래와 같이 볼 수 있습니다. (8080 서버 포트는 실행시 두번째 인자 입니다.)

이 소스는 html 만 지원되는 소스입니다. server side script 또는 cgi 등을 지원하지 않습니다.

















2018년 5월 13일 일요일

parseInt in java


int java.lang.Integer.parseInt(String s) throws NumberFormatException


  • parseInt

    public static int parseInt(String s)
                        throws NumberFormatException
    Parses the string argument as a signed decimal integer. The characters in the string must all be decimal digits, except that the first character may be an ASCII minus sign '-' ('\u002D') to indicate a negative value or an ASCII plus sign '+' ('\u002B') to indicate a positive value. The resulting integer value is returned, exactly as if the argument and the radix 10 were given as arguments to the parseInt(java.lang.String, int) method.
    Parameters:
    s - a String containing the int representation to be parsed
    Returns:
    the integer value represented by the argument in decimal.
    Throws:
    NumberFormatException - if the string does not contain a parsable integer.

문자(String)를 숫자(integer)로 변경하는 하는 함수 입니다.
만약 당신이 함수 설계자라고 가정합시다. 리턴값을 한개밖에 전달 못하니 돌려 받는 값은 변환된 값이고 만약 숫자가 아니이서 변경하지 못할때 어떻게 할까요? 그래서 Exception을 발생 시키는 것입니다.
문자를 변환시키는것은 다른 형태의 데이터를 읽어서 변환하는 경우가 많기 때문에 입력이 숫자만이 아닌 경우도 종종 있습니다. (입력 format이 변경된다던지...)

따라서 숫자로 변환할 수 없는 경우에는 NumberFormatException 이 발생하기 때문에 NumberFormatException 꼭 catch해서 사용하기 바랍니다.


문자열 앞뒤에 공백이 있어도 안됩니다. trim() 메소드로 공백을 제거해주세요.
아래 몇가지 예를 만들었습니다. 참고하세요.

parseInt 예제
public class Test1005 {

 public static void main(String[] args) {
  int number;
  System.out.println("1)");
  number = Integer.parseInt("123");
  System.out.println(number);
  System.out.println("2)");
  number = Integer.parseInt("-123");
  System.out.println(number);
  System.out.println("3)");
  number = Integer.parseInt("+123");
  System.out.println(number);
  System.out.println("4)");
  number = Integer.parseInt(" 123 ".trim());
  System.out.println(number);
  try{
   System.out.println("5)");
   number = Integer.parseInt(" 123 ");
   System.out.println(number);
  }catch(NumberFormatException e) {
   System.out.println(e);
  }
  try{
   System.out.println("6)");
   number = Integer.parseInt("123 ");
   System.out.println(number);
  }catch(NumberFormatException e) {
   System.out.println(e);
  }
  try{
   System.out.println("7)");
   number = Integer.parseInt("1.123");
   System.out.println(number);
  }catch(NumberFormatException e) {
   System.out.println(e);
  }
  try{
   System.out.println("8)");
   number = Integer.parseInt("");
   System.out.println(number);
  }catch(NumberFormatException e) {
   System.out.println(e);
  }
  try{
   System.out.println("9)");
   number = Integer.parseInt(null);
   System.out.println(number);
  }catch(NumberFormatException e) {
   System.out.println(e);
  }
 }
}

실행결과
1)
123
2)
-123
3)
123
4)
123
5)
java.lang.NumberFormatException: For input string: " 123 "
6)
java.lang.NumberFormatException: For input string: "123 "
7)
java.lang.NumberFormatException: For input string: "1.123"
8)
java.lang.NumberFormatException: For input string: ""
9)
java.lang.NumberFormatException: null

2017년 8월 27일 일요일

문제 풀기(서로 다른 숫자를 사용해서 연산해 내기, 순열이용) in Java


어느날 우리애가 풀어보라면 들고 왔습니다. 선생님이 내줬다는 문제인데요....


과연 풀려면 어떻게 할까 생각해보다가, 오랜만에 PC로 풀어볼려고 마음먹었습니다.  정리하자면 아래와 같은 문제입니다.

문제) 1~9까지 서로 다른 숫자를 사용해 들어갈 숫자를 완성하세요.

   A B
X    C
--------
   D E
+ F G
--------
   H I

이중에 힌트로 B=7,I=3가 주어졌다고 합니다.
힌트 없이 풀어보도록 하겠습니다.

각각의 값은 중복이 되지 않으므로 순열이라고 보면됩니다.
방법은 A=1...9까지 선택하고 B=1....9 까지 선택하고... 이런식으로 I까지 선택한 후 이전에 선택된 값이라면 무시하고 식이 맞는지 확인하는 방법으로 구해보았습니다.
여러개의 루프를 사용하면서 안쪽에서 다시 루프를 사용하고 아래와 같은 코드에 의해 이미 선택된 값이라면 선택이 되지 않도록 합니다.
if(usedflag[b])continue;

여러개의 루프를 사용하는 방법:
package testProject;

public class Test3 {

 public static void main(String[] args) {
  
  test1();
  
 }
 

 private static void test1() {
  boolean usedflag[]={false,false,false,false,false,false,false,false,false,false};
  
  for(int a=1;a<=9;a++){
   usedflag[a]=true;
   for(int b=1;b<=9;b++){
    if(usedflag[b])continue;
    usedflag[b]=true;
    for(int c=1;c<=9;c++){
     if(usedflag[c])continue;
     usedflag[c]=true;
     for(int d=1;d<=9;d++){
      if(usedflag[d])continue;
      usedflag[d]=true;
      for(int e=1;e<=9;e++){
       if(usedflag[e])continue;
       usedflag[e]=true;
       for(int f=1;f<=9;f++){
        if(usedflag[f])continue;
        usedflag[f]=true;
        for(int g=1;g<=9;g++){
         if(usedflag[g])continue;
         usedflag[g]=true;
         for(int h=1;h<=9;h++){
          if(usedflag[h])continue;
          usedflag[h]=true;
          for(int i=1;i<=9;i++){
           if(usedflag[i])continue;
           usedflag[i]=true;
           if(((a*10+b)*c)==((d*10)+e)){
            if(((d*10)+e)+((f*10)+g)==(h*10)+i){
             System.out.println("a="+a+",b="+b+",c="+c+",d="+d+",e="+e+",f="+f+",g="+g+",h="+h+",i="+i);
            }
           }
           usedflag[i]=false;
          }
          usedflag[h]=false;
         }
         usedflag[g]=false;
        }
        usedflag[f]=false;
       }
       usedflag[e]=false;
      }
      usedflag[d]=false;
     }
     usedflag[c]=false;
    }
    usedflag[b]=false;
   }
   usedflag[a]=false;
  }
 }
 
 
}

결과:
a=1,b=7,c=4,d=6,e=8,f=2,g=5,h=9,i=3

위 방법대로 할경우 문제가 있습니다. 많은 변수를 사용하게 되면 굉장히 코드도 길어지고 그러다보면 실 수 할 수도 있게 됩니다.
그렇다면 코드의 중복되는 부분을 함수로 만들어서 호출해주는 방법을 고민하게 됩니다.

기본적으로 구현은 자기자신을 호출해주는 재귀부와 조건이 맞으면 더이상 재귀를 동작 안하게 하는 두 부분으로 구성됩니다.
재귀부:
  for(int i=1;i<=9;i++){
   test2(depth+1,usedflag,selected);
  }
더 이상 재귀를 동작 안하게 하는 부분:
  if(depth == 9) {
   return;
  }

재귀를 동작 안하게 하려면 얼마나 호출되었는지 관리가 필요합니다. 여기에서는 depth 변수를 이용하여 관리를 하고(자신을 호출시 depth+1 사용) 특정 조건에 맞으면 더 이상의 재귀 동작을 멈추게 합니다. (if(depth==XX) return 조건 사용)

아래는 구현한 내용입니다.

재귀 호출을 이용한 방법:
package testProject;

public class Test3 {

 public static void main(String[] args) {

  boolean usedflag[]={false,false,false,false,false,false,false,false,false,false};
  int selected[]={-1,-1,-1,-1,-1,-1,-1,-1,-1};
  test2(0, usedflag, selected);
  
 }
 
 private static void test2(int depth, boolean usedflag[], int selected[])
 {
  if(depth == 9) {
   if(((selected[0]*10+selected[1])*selected[2])==((selected[3]*10)+selected[4])){
    if(((selected[3]*10)+selected[4])+((selected[5]*10)+selected[6])==(selected[7]*10)+selected[8]){
     System.out.println("a="+selected[0]+",b="+selected[1]+",c="+selected[2]+",d="+selected[3]+",e="+selected[4]+",f="+selected[5]+",g="+selected[6]+",h="+selected[7]+",i="+selected[8]);
    }
   }
   return;
  }
  for(int i=1;i<=9;i++){
   if( usedflag[i] ) continue;
   usedflag[i]=true;
   selected[depth]=i;
   test2(depth+1,usedflag,selected);
   usedflag[i]=false;
  }
 }
 
}


순열에 대한 자세한 내용은 아래 링크를 확인해보세요.
http://swlock.blogspot.kr/2016/11/permutation-combination-algorithm_13.html

2017년 5월 21일 일요일

card shuffle in java


카드 셔플(섞는것) 시뮬레이션을 코드로 구현해 보았습니다.

트럼프 카드는 (1~10, K,Q,J ) 13*4+2(조커) = 54장입니다.

카드를 섞을때 일반적으로 카드의 아래부분을 끄집어 내어


위로 올린뒤 다시 올린부분의 일정 카드를
  다시 끄집어 내어

위로 올리고 올린 카드 중 일부를 다시 끄집어 내는 과정을 반복합니다.

위 사진은 젝스팀트 카드입니다.

0~8 까지의 카드가 있다고 할때 4,5,6,7,8 이 처음 꺼내는 카드라면

//     F   L
// 012345678
한번 하고 나면 아래와 같은 형태가 되고
//    F   L
// => 456780123
다시 한번 진행하면 6,7,8 선택되면
//      F L
// => 456780123
6,7,8이 앞으로 나가게 되고
//    F L
// => 678450123
8만선택되어 앞으로 나가게 되면 섞기 종료가 됩니다.
//   FL
// => 867450123

이 과정을 shffle() 메소드로 구현하였습니다.


card shuffle 시뮬레이션
package testProject;

public class CardGame1Shuffle {

 public static void main(String[] args) {
  
  char [] card;
  int cardCount = 54;
  card = new char[cardCount];
  for(int i=0;i<cardCount;i++){
   card[i]=(char) ('0'+i);
  }

  for(int j=0;j<54;j++){
   System.out.print("["+j+"]");
   printCard(card);
   shuffle(card);
  }
 }
 
 public static void printCard(char [] card)
 {
  int i;
  for(i=0;i<card.length;i++){
   System.out.print(card[i]);
  }
  System.out.println();  
 }
 
 public static int shuffle(char [] card)
 {
  //     F   L
  // 012345678
  //
  //    F   L
  // => 456780123
  //
  //int shffleCount = 
  int first = getRandomWithEnd(0,card.length-1);
  int last = card.length-1;
  for(;;){
   shuffleOnce(card, first, last);
   last = last-first;
   first = getRandomWithEnd(0,last);
   if(first==last) break;
  }
  return 0;
 }

 public static int shuffleOnce(char [] card, int st1, int st2)
 {
  char [] cardcp = new char[card.length];
  int i,j;
  for(i=0;i<card.length;i++)
  {
   cardcp[i]=card[i];
  }
  for(i=st1,j=0;i<=st2;i++,j++){
   card[j] = cardcp[i];
  }
  for(i=0;i<=st1-1;i++){
   card[j]=cardcp[i];
   j++;
  }
  return 0;
 }
 
 //  getRandomWithSize(0,3) => (0,1,2)
 //  getRandomWithSize(5,3) => (5,6,7)
 public static int getRandomWithSize(int start,int size)
 {
  return (int)(Math.random()*size)+start;
 }
 //  getRandomWithEnd(0,2) => (0,1,2)
 //  getRandomWithEnd(5,7) => (5,6,7)
 public static int getRandomWithEnd(int start,int end)
 {
  return (int)(Math.random()*(end-start+1))+start;
 }
}


결과
[0]0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcde
[1]cdeab\]^_`YZ[TUVWXPQRSJKLMNODEFGHI89:;<=>?@ABC01234567
[2]1234567cdeab\]^_`YZ[TUVWXPQRSJKLMNODEFGHI89:;<=>?@ABC0
[3]C0AB<=>?@1234567cdeab\]^_`YZ[TUVWXPQRSJKLMNODEFGHI89:;
[4];C0AB<=>?@1234567cdeab\]^_`YZ[TUVWXPQRSJKLMNODEFGHI89:
[5]9:8IHGFb\]^_`YZ[TUVWXPQRSJKLMNODE;C0AB<=>?@1234567cdea
[6]a9:8IHGFb\]^_`YZ[TUVWXPQRSJKLMNODE;C0AB<=>?@1234567cde
[7]de@1234567c=>?QRSJKLMNODE;C0AB<[TUVWXP`YZa9:8IHGFb\]^_
[8]]^_\:8IHGFb=>?QRSJKLMNODE;C0AB<[TUVWXP`YZa9de@1234567c
[9]4567c3UVWXP`YZa9de@12=>?QRSJKLMNODE;C0AB<[T]^_\:8IHGFb
[10]Fb8IHG^_\:4567c3UVWXP`YZa9de@12=>?QRSJKLMNODE;C0AB<[T]
[11]a9de@12=>?QRSJKLMNODE;C0AB<[T]Fb8IHG^_\:4567c3UVWXP`YZ
[12]YZ`3UVWXP\:4567c@12=>?QRSJKLMNODE;C0AB<[T]Fb8IHG^_a9de
[13]^_a9deT]Fb8IHG<[YZ`3UVWXP\:4567c@12=>?QRSJKLMNODE;C0AB
[14]ABC0DE;NOKLMSJ^_a9deT]Fb8IHG<[YZ`3UVWXP\:4567c@12=>?QR
[15]?QR>12=ABC0DE;NOKLMSJ^_a9deT]Fb8IHG<[YZ`3UVWXP\:4567c@
[16]c@:4567XP\?QR>12=ABC0DE;NOKLMSJ^_a9deT]Fb8IHG<[YZ`3UVW
[17]HG<[YZ`3UVWXP\?QR>12=ABC0DE;NOKLMSJ^_a9deT]Fb8Ic@:4567
[18]5674deT]Fb8Ic@:^_a9HG<[YZ`3UVWXP\?QR>12=ABC0DE;NOKLMSJ
[19]SJOKLMDE;N9HG<[YZ`3UVWXP\?QR>12=ABC0b8Ic@:^_a5674deT]F
[20]]FTde412=ABC0b8Ic@:^_a567SJOKLMDE;N9HG<[YZ`3UVWXP\?QR>
[21]R>KLMDE;N9HG<[YZ`3UVWXP\?Q67SJOC0b8Ic@:^_a5]FTde412=AB
[22]=AB2de41R>KLMDE;N9HG<[YZ`3UVWXP\?Q67SJOC0b8Ic@:^_a5]FT
[23]FT5]:^_aOC0b8Ic@67SJ=AB2de41R>KLMDE;N9HG<[YZ`3UVWXP\?Q
[24]WXP\?QB2de41R>KLMDE;N9HG<[YZ`3UV7SJ=AFT5]:^_aOC0b8Ic@6
[25]c@6_aOC0b8IWXP\?QB2de41R>KLMDE;N9HG<[YZ`3UV7SJ=AFT5]:^
[26]:^AFT5]9HG<[YZ`3UV7SJ=c@6_aOC0b8IWXP\?QB2de41R>KLMDE;N
[27]MDE;NKL2de41R>QB:^AFT5]9HG<[YZ`3UV7SJ=c@6_aOC0b8IWXP\?
[28]\?XPWc@6_aOC0b8IMDE;NKL2de41R>QB:^AFT5]9HG<[YZ`3UV7SJ=
[29]<[YZ`3UV7SJ=T5]9HGC0b8IMDE;NKL2de41R>QB:^AF\?XPWc@6_aO
[30]aO_c@6We41R>QB:^AF\?XPJ=T5]9HGC0b8IMDE;NKL2d<[YZ`3UV7S
[31]7S;NKL2d<[YZ`3UVIMDE5]9HGC0b8@6We41R>QB:^AF\?XPJ=TaO_c
[32]_cVIMDE5]9HGC0b8@6We41R>QB:^AF\?XPJ=TaOYZ`3U7S;NKL2d<[
[33]<[`3U7S;NKL2d_cVIMDE5]9HGC0b8@6We41R>QB:^AF\?XPJ=TaOYZ
[34]YZOaTAF\?XPJ=1R>QB:^<[`3U7S;NKL2d_cVIMDE5]9HGC0b8@6We4
[35]e4W6GC0b8@PJ=1R>QB:^<[`3U7S;NKL2d_cVIMDE5]9HYZOaTAF\?X
[36]?XAF\YZOaTMDE5]9He4W6GC0b8@PJ=1R>QB:^<[`3U7S;NKL2d_cVI
[37]_cVIdKL2He4W6GC0b8@PJ=1R>QB:^<[`3U7S;N?XAF\YZOaTMDE5]9
[38]5]93U7S;N?XAF\YZOaTMDE_cVIdKL2He4W6GC0b8@PJ=1R>QB:^<[`
[39][`0b8@PJ=1R>QB:^<dKL2He4W6GC3U7S;N?XAF\YZOaTMDE_cVI5]9
[40]]9S;N?XAF\YZOaTMDE_cVI5[`0b8@PJ=1R>QB:^<dKL2He4W6GC3U7
[41]U73CGZOaTMDE_cVI5[`0b8@PJ=1R>QB:^<dKL2He4W6]9S;N?XAF\Y
[42]F\Y]9S;N?XAL2He4W6ZOaTMDE_cVI5[`0b8@PJ=1R>QB:^<dKU73CG
[43][`0b8@PJ=1R>QB:^<dKU73CG\Y]9S;N?XAL2He4W6ZOaTMDE_cVI5F
[44]TMDE_cVI5F6ZOaW4AL2He[`0b8@PJ=1R>QB:^<dKU73CG\Y]9S;N?X
[45]?X;NdKU73CG\Y]9S@PJ=1R>QB:^<TMDE_cVI5F6ZOaW4AL2He[`0b8
[46][`0b8e2H?X;NdKU73CG\Y]9S@PJ=1R>QB:^<TMDE_cVI5F6ZOaW4AL
[47]4ALOaWDE_cVI5F6Z[`0b8e2H?X;NdKU73CG\Y]9S@PJ=1R>QB:^<TM
[48]TM>QB:^<73CG\Y]9S@PJ=1R4ALOaWDE_cVI5F6Z[`0b8e2H?X;NdKU
[49]KUdX;Ne2H?0b8=1R4ALOaWDE_cVI5F6Z[`TM>QB:^<73CG\Y]9S@PJ
[50]3CG\Y]9S@PJQB:^<7I5F6Z[`TM>KUdX;Ne2H?0b8=1R4ALOaWDE_cV
[51]cVE_3CG\Y]9S@PJQB:^<7I5F6Z[`TM>KUdX;Ne2H?0b8=1R4ALOaWD
[52]LOaWDNe2H?0b8=1R4A;JQB:^<7I5F6Z[`TM>KUdX@PcVE_3CG\Y]9S
[53]\Y]9S3CGcVE_F6Z[`TM>KUdX@PLOaWDNe2H?0b8=1R4A;JQB:^<7I5

결과를 보면 효율이 그렇게 좋지 않아서 굉장히 여러번 수행해야 함을 알 수 있습니다