2016년 12월 28일 수요일

HTTP Referer ?? HTTP Referrer ??

원래 Referrer 라고 써야하지만, 필립 할람-베이커Phillip Hallam-Baker가 HTTP스펙에 필드를 추가로 제안할때 오타로 Referer로 기재함.
오타가 그대로 표준에 반영되어 RFC-1945 문서에 포함됐고, 현재까지 Referer로 사용하고 있다.

2016년 12월 27일 화요일

제로데이 공격(Zero-Day Attack)

제로 데이 공격(또는 제로 데이 위협, Zero-Day Attack)은 컴퓨터 소프트웨어의 취약점을 공격하는 기술적 위협으로, 해당 취약점에 대한 패치가 나오지 않은 시점에서 이루어지는 공격을 말한다. 이러한 시점에서 만들어진 취약점 공격(익스플로잇)을 제로 데이 취약점 공격이라고도 한다.

2016년 12월 21일 수요일

드라이브 바이(drive by), 파밍(pharming) 공격

드라이브 바이(drive by)
~쪽으로 자동차를 운전하다 라는 의미
온라인 광고업체에서 사용자가 아무런 의심없이 동의버튼을 누르는 버릇을 악용해 광고 콘텐츠 설치 유도(드라이브 바이 인스톨 - drive by install) 또는 한번 클릭하는 선택적 설치(one click opt install)
사용자의 동의 없이 자동으로 악성코드 다운로드 및 실행하는 현상


파밍(pharming)
악성코드 또는 다른 공격으로 인해 DNS가 변경되어 피싱사이트로 유도하는 공격
c:\window\system\drivers\etc 에 존재하는 host 파일 조작 혹은 레지스트리를 변조시켜 로컬프락시 설정, 악성코드 자체가 로컬 DNS가 되는 방식도 있다.

2016년 11월 30일 수요일

페인트공 알고리즘, 마세라티 문제, 야크 털 깎기

페인트공 알고리즘

1. 페인트공이 첫날은 차선 페인트 작업을 300야드 칠함
2. 둘째날은 150야드 칠함
3. 셋째날은 30야드 칠함, 첫날은 어떻게 10배를 칠했는지 관리자가 묻자
   "저도 어쩔 수 없었습니다. 매일 페인트 통에서 점점 멀어지니까요."

- 조엘 스폴스키의 “조엘 온 소프트웨어” 중

--> 일정 이상 규모가 되면 급격히 성능 저하되고 문제를 일으키는 코드


마세라티 문제

1. 어떤 마세라티 모델과 색상을 구매할 지 고민하는 것.
2. 나중에 마세라티 살 능력이 됐을 때 할 고민을 미리 하는 것.

* 돈 많은 금융과 증권계에서는 “boat naming” 이라고 함.
* 당장 필요하지 않은 기술을 담보되지 않은 미래의 큰 성공에 대비하여 준비하는 것
* 천만명을 처리할 서비스는 사용자가 10만은 됐을 때 고민
* 엔지니어만 있는 스타트업에서 자주 발생하는 현상

야크 털깍기(Yak Shaving)
어떤 목적을 달성하기 위해 전혀 상관없는 연속된 작업을 해야 하는 상황.
그중 마지막 작업이 야크 털깍기

봄이 와서 세차를 하려는데 호스가 터졌음
차로 홈 디포우에 가서 호스를 사려보니 다리를 지나야 하는데 통행 카드가 필요
통행카드가 없어서 옆집 Bob 한테 빌리려는데
아들이 캠핑가려고 Bob 한테 베개를 빌린 후에 안 갖다 줌

그런데 베개에 있는 야크털이 많이 빠져서 지금 베개를 갖다 줄 수 없음
그래서 세차를 하기 위해 동물원에 가서 야크 털을 깍는중
       
        - 세스 고딘의 “이제는 작은 것이 큰 것이다“ 중

     
* 야크 털깍기로 배우는 것도 많지만 문제는 일정
* 예정보다 많은 시간이 소요된다면 잠시 멈출 것
* 하려고 했던게 무엇인지 떠올려 보고 야크털깍기라 생각되면 했던 일을 과감히 중지

2016년 9월 9일 금요일

datepicker 삭제 버튼(firefox 오류수정 버전)

jquery datepicker를 사용 할 경우 해당 input text를 삭제버튼으로 한번에 내용을 제거 하고 싶을때가 있다.

1.
그래서 얼마전까지 사용했던 방법은 jquery 초기화 옵션중에

            showButtonPanel: true, // 캘린더 하단에 버튼 패널을 표시한다. 

showButtonPanel 옵션을 true로 주면

이렇게 [오늘날짜]와 [닫기] 버튼이 최초에 생긴다.


2. 이 닫기 버튼의 이름을 clear로 변경
3. 닫기 버튼을 눌렀을때 해당 input text를 clear해주는 이벤트를 bind 해준다.


 closeText: 'clear'
 ,onClose: function (dateText, inst) {
   if ($(window.event.srcElement).hasClass('ui-datepicker-close'))
   {
     document.getElementById(this.id).value = '';
   }
 }

이렇게 하면 ~ie엣지, 크롬에선 정상적으로 동작한다.
문제는 firefox에서는 

라 에러가 생김 
기존에 onClose 안에 준 이벤트 자체가 현재 이벤트가 일어나는 엘리먼트의 클래스를 여부를 판단하는것인다. window.event 자체가 firefox에서는 존재 하지 않아 해당라인에서 error발생

구글링 후 가장 깔끔하게 처리되는것은


function cleanDatepicker(){

  var old_fn = $.datepicker._updateDatepicker;

  $.datepicker._updateDatepicker = function(inst) {
   old_fn.call(this, inst);

   var buttonPane = $(this).datepicker("widget").find(".ui-datepicker-buttonpane");

   $("<button type='button' class='ui-datepicker-clean ui-state-default ui-priority-primary ui-corner-all'>clear</button>").appendTo(buttonPane).click(function(ev) {
    $.datepicker._clearDate(inst.input);
   }) ;
  }
 }


위 함수를 선언 후 datepicker init 하기전에 한번 실행해주는 것이 가장 브라우저도 안타고 잘 동작하게 해결하는 방법이었습니다.

4. 해당 함수를 실행하고 
5. 기존에 clear버튼을 "닫기" 버튼으로 변경 
6. onClose에 bind했던 함수는 제거하면
   아래와 같이 버튼 3개가 생기고 각 버튼들이 잘 동작 하는걸 확인 할 수 있다.









2016년 8월 10일 수요일

Laravel 5 optimization commands

Laravel 5 optimization commands

============================
php artisan optimize
php artisan config:cache
php artisan route:cache
============================

1. storage paths optimize
optimize 명령을 사용하면 "bootstrap/cache/" 폴더 안에 컴파일 된 파일 기록

2. artisan optimize
php artisan optimize 명령어를 실행하면 "bootstrap/cache/compiled.php" 형태로 저장 하거나 덮어쓴다.
더 컴파일 하고 싶은 class가 있을경우 config/compile.php 에서 추가 할 수 있다.
--force 옵션을 사용하면 컴파일 되는 것을 피할 수 있다.

service provider는  "bootstrap/cache/services.php" 파일 생성(json) 경로를 등록해두고 최적화를 시도한다.

php artisan clear-compiled 명령을 하면 compile된 파일 캐시를 지움

artisan optimize는 "config/app.php"의 설정에 따라 달라질수 있다.
배포중에도 php artisan config:cache 명령으로 캐시 클리어 가능

3. artisan config:cache
config 파일 들에 대한 캐싱을 진행
bootstrap/cache/config.php 라는 파일명으로 생성된다.
기존에 생성되 있을경우 덮어쓴다.
삭제 하는 방법은 php artisan config:clear

4. artisan route:cache
route에 대한 정보도 cache로 등록.
bootstrap/cache/routes.php 라는 파일명으로 생성된다.
기존에 생성되 있을경우 덮어쓴다.

삭제 하는 방법은 php artisan route:clear

5. artisan view:clear
프레임워크를 통해 최초 렌더링 되는 파일을 해당 경로(storage/framework/views) 에 (MD5).php파일 형태로 컴파일 됨
캐시를 없애고 싶으면 artisan view:clear



Laravel 5.0

5.1 버전 이전에는 artisan 명령을 사용하면 vendor 폴더에 기록됨
경로를 storage/framework/ 바꾸고 싶을 경우 bootstrap/app.php안에 $app->useStoragePathForOptimizations(true);

출처 : http://sentinelstand.com/article/laravel-5-optimization-commands

2016년 7월 22일 금요일

카카오api 나에게 보내기 (REST API) classic asp

카카오api 주소 (https://developers.kakao.com/)

예제 소스는 classic asp로 구현했습니다.

나에게 보내기Copy URL

카카오톡 나에게 보내기는 사용자 중에서 카카오계정에 연결한 카카오톡 사용자에 한해 카카오톡 나와의 챗팅방으로 메시지를 보낼 수 있는 기능입니다. 해당 기능을 사용하기 위해서는 성공적인 로그인 후에 얻을 수 있는 사용자 토큰이 필요합니다.
(https://developers.kakao.com/docs/restapi#카카오톡-나에게-보내기)


1. 카카오 개발자 등록
https://accounts.kakao.com/login?continue=https://developers.kakao.com/login



2. 내 애플리케이션 추가작업



3. 사용자관리 설정


일반을 클릭하면 rest api 키를 얻을수 있습니다. 밑에 소스에서 client_id 변수에 이 값을 넣어주셔야됩니다.


4. 템플릿 추가


5. restapi key 확인 및 도메인 등록
내어플리케이션 >  설정 > 일반 > REST API 키 확인, 사이트 도메인 등록, path 등록




6. 로그인 처리
https://developers.kakao.com/docs/restapi#사용자-관리-로그인

ex>
https://kauth.kakao.com/oauth/authorize?client_id={client_id}&redirect_uri={등록한 path}&response_type=code


7. 토큰받기 처리 및 나에게 메시지 전송
등록한 path 페이지에서 code라는 request 값을 받는다.
받은 code값을 이용하여 token 값을 요청




[aaa.asp 페이지]



'async 함수
Function postFormData(url, headerArr, data) Dim xhr, i Set xhr = Server.CreateObject("MSXML2.ServerXMLHTTP.3.0") xhr.open "POST", url, false for i = 0 to ubound(headerArr) xhr.setRequestHeader headerArr(i)(0), headerArr(i)(1) next xhr.send data If (xhr.Status = 200) then postFormData = xhr.ResponseText response.write postFormData Else Err.Raise 1001, "postFormData", "Post to " & url & " failed with " & xhr.Status&" message "&xhr.responseText End If End Function


 client_id = "38c9*********************8" 
 url = "https://주소.co.kr/index22.asp"
        code = request("code")

  '토큰 요청 값 받기 
  '최초 요청을 보냈을시 access_token, refresh_token
  set tokenObj = JSON.parse(
                  postFormData("https://kauth.kakao.com/oauth/token", 
                  array(array("Content-Type","application/x-www-form-urlencoded")),
                  "grant_type=authorization_code&client_id="&client_id&"&redirect_uri="&url&"&code="&code))
  
  access_token = tokenObj.access_token  
  refresh_token = tokenObj.refresh_token

  'refresh token 요청 값 받기  
  'refresh_token은 기본 12시간~24시간이 아닌 더 긴 시간을 유지할수 있는 token임 
  set refreshTokenObj = JSON.parse(
                        postFormData("https://kauth.kakao.com/oauth/token",
                        array(array("Content-Type","application/x-www-form-urlencoded")),
                        "grant_type=refresh_token&client_id="&client_id&"&redirect_uri="&url&"&refresh_token="&refresh_token))

  'refresh token 요청시 access_token만 넘어옴 
  access_token = refreshTokenObj.access_token

  'access_token 값을 이용하여 message 보내기
  response.write postFormData("https://kapi.kakao.com/v1/api/talk/memo/send?template_id=828&args="&
                 Server.URLEncode("{""${message}"":""테스트적용완료"",""${subject}"":""적용완료""}"),
                 array(array("Authorization", "Bearer "& access_token)),"")





위와 같이 나에게 메시지가 옴 


- 나에게 보낸다는 서비스이기때문에 광범위하게 사용하기에 제약사항이 좀 있습니다. 
구현하시서 생각해보시길..

2016년 6월 20일 월요일

flyweight 패턴

■ 정의

[GOF]
 - 공유를 통한 많은 수의 소립 객체들을 효과적으로 지원

[ 실용주의 디자인패턴 ]
- 메모리 사용량을 줄이기 위해 외부 상태(상태정보 저장, 계산)를 사용하거나
  공유(객체의 복사본 대신 단일 객체에 대한 다중 참조를 이용)한다.
- 무엇을 하느냐에 의해 정의, 즉 메소드에 의해 정의됨

▶ 즉 공유하는 객체를 이용하되 상태 정보를 외부 객체가 따로 관리



■ 사용 예
- game of life를 단순하게 구현할때 '셀'이 살아있는가?는 주변 상태를 참조를 지니고 있어야된다. 1024*1024를 표현하려해도 40mb가 필요함
flywieght를 사용하면 동일한 상태를 지닌 객체가 단 하나의 객체를 통해 표현



■ 장/단점
- 장점 : flyweight를 사용하지 않으면 객체지향적으로 구현하기가 힘듬
- 장점 : flyweight 풀을 이용하면 자바의 == 연산자로 객체의동일성 여부를 결정 할 수 있다.

- 단점 : 외부상태가 계산되는 값이라면(매번 데이터베이스에 접근) 하면 접근이 느릴 수 있다.
- 단점 : 코드가 복잡해짐, 유지보수를 어렵게하고 코드가 커질 수 있음


■ 코드 예제
쉬운 예>
ElementStyle e = new ElementStyle;
e.setMargin(ElementStyleFactory.createMargin(10,10,20,10)); -> 객체는 공유하되 외부 객체가 따로 관리 되도록

게임프로그래밍 패턴예제(js로 구현)>
[origin]
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>flyweight origin</title>
</head>
<body>
경량패턴??<br>
어떤 객체의 수가 너무 많아 좀 가볍게 만들고 싶을때 사용<br>
고유상태와 외부상태로 나눔<br>
<br>
예제 : 지형 만들기<br>
타일(고유상태)과 각 타일들이 갖고 있는 정보(외부상태)<br>
<script>
    function Terrain(kind){
        return {
            "TERRAIN_CLASS" : "TERRAIN_CLASS",
            "TERRAIN_HILL" : "TERRAIN_HILL",
            "TERRAIN_RIVER" : "TERRAIN_RIVER"        }[kind];
    }

    function World(){
        this.tiles = {};
    }
    World.prototype.getMovementCost = function(x,y){
        return {
            "TERRAIN_CLASS" : 1,
            "TERRAIN_HILL" : 2,
            "TERRAIN_RIVER" : 3        }[this.tiles[x][y]];
    };

    World.prototype.getIsWater = function(x,y){
        return {
            "TERRAIN_CLASS" : false,
            "TERRAIN_HILL" : false,
            "TERRAIN_RIVER" : true        }[this.tiles[x][y]];
    };

    World.prototype.setTile = function(x,y, value){
        this.tiles = this.tiles||{};

        this.tiles[x] = this.tiles[x]||{};
        this.tiles[x][y] = this.tiles[x][y]||"";
        this.tiles[x][y] = value;

    };


    function Main(){
        var world = new World;
        var terrain_class = Terrain("TERRAIN_CLASS");
        var terrain_hill = Terrain("TERRAIN_HILL");
        var terrain_river = Terrain("TERRAIN_RIVER");

        world.setTile(1,1,terrain_class) ;
        world.setTile(1,2,terrain_hill) ;
        world.setTile(1,3,terrain_river) ;

        console.log(world.getIsWater(1,3));
        console.log(world.getMovementCost(1,2));
    }

    window.onload = function(){
        Main();
    }
</script>
</body>
</html>

[fly weight]
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>flyweight </title>
</head>
<body>
경량패턴??<br>
어떤 객체의 수가 너무 많아 좀 가볍게 만들고 싶을때 사용<br>
고유상태와 외부상태로 나눔<br>
<br>
예제 : 지형 만들기<br>
타일(고유상태)과 각 타일들이 갖고 있는 정보(외부상태)<br>
<script>
    function Terrain(movementCost, isWater, texture){

        var movementCost_;
        var isWater_;
        var texture_;

        function _Terrain(){
            this.movementCost_ = movementCost;
            this.isWater_ = isWater;
            this.texture_ = texture;

        }

        _Terrain.prototype.getMovementCost = function(){
            return this.movementCost_;
        };
        _Terrain.prototype.isWater = function(){
            return this.isWater_;
        };
        _Terrain.prototype.getTexture = function(){
            return this.texture_;
        };


        if(!(this instanceof _Terrain )){
            return new _Terrain();
        }

    }

    var CONST_GLASS_TEXTURE = "GLASS_TEXTURE";
    var CONST_HILL_TEXTURE = "HILL_TEXTURE";
    var CONST_RIVER_TEXTURE = "RIVER_TEXTURE";
    var CONST_WIDTH = 10;
    var CONST_HEIGHT = 12;

    function World(){

        var tiles = {};


        function _World(){
            this.glassTerrain_ = [1,false,CONST_GLASS_TEXTURE];
            this.hillTerrain_ = [2,false,CONST_HILL_TEXTURE];
            this.riverTerrain_ = [3,true,CONST_RIVER_TEXTURE];
            this.tiles = tiles;

        }

        _World.prototype.setTile = function(x,y, value){
            this.tiles = this.tiles||{};

            this.tiles[x] = this.tiles[x]||{};
            this.tiles[x][y] = this.tiles[x][y]||"";
            this.tiles[x][y] = value;

        };

        _World.prototype.getTile = function(x,y){

            return Terrain.apply(this, this.tiles[x][y]);
        };


        _World.prototype.generateTerrain = function(){
            for(var x=0; x < CONST_WIDTH; x++) {
                for(var y=0; y < CONST_HEIGHT; y++){
                    if(x % 2 == 0){
                        this.setTile.apply(this, [x,y,this.glassTerrain_]);
                    }else{
                        this.setTile.apply(this, [x,y,this.hillTerrain_]);
                    }
                    if(y % 3 == 1){
                        this.setTile.apply(this, [x,y,this.riverTerrain_]);
                    }
                }
            }
        };

        if(!(this instanceof _World )){
            return new _World();
        }

    }



    function Main(){
        var world = World();
        world.generateTerrain();
        console.dir(world.getTile(1,1).getMovementCost());

    }

    window.onload = function(){
        Main();
    }
</script>
</body>
</html>

2016년 6월 19일 일요일

게임프로그래밍 패턴 - 커맨드패턴을 이용한 이동키로 화면 움직이기 구현

아래는 원본 함수
handleInput에 if문으로 각각의 함수를 호출 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>command pattern</title>
    <style>
        #unit {
            position: absolute;
            background-color: olivedrab;
            top:100px;
            left:100px;
            display:block        }
    </style>
</head>
<body>
원본소스
<div id="unit">
    unit
</div>
<script>
    document.addEventListener("keydown", handleInput, false);
    function handleInput(e){
        var keyCode = e.keyCode;
        if(keyCode == 38){
            up();
        }else if(keyCode == 40){
            down();
        }else if(keyCode == 37){
            left();
        }else if(keyCode == 39){
            right();
        }
    };


    function unit(){
        var target = document.getElementById('unit');

        return {
            "x" : parseInt(getStyle(target,"left"),10),
            "y" : parseInt(getStyle(target,"top"),10),
            "body" : target.style        };
    }
window.onload= function(){
    console.log(unit().x);
};


</script>

<script>


    function getStyle(el, styleProp) {
        var value, defaultView = (el.ownerDocument || document).defaultView;
        // W3C standard way:        if (defaultView && defaultView.getComputedStyle) {
            // sanitize property name to css notation            // (hypen separated words eg. font-Size)            styleProp = styleProp.replace(/([A-Z])/g, "-$1").toLowerCase();
            return defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
        } else if (el.currentStyle) { // IE            // sanitize property name to camelCase            styleProp = styleProp.replace(/\-(\w)/g, function(str, letter) {
                return letter.toUpperCase();
            });
            value = el.currentStyle[styleProp];
            // convert other units to pixels on IE            if (/^\d+(em|pt|%|ex)?$/i.test(value)) {
                return (function(value) {
                    var oldLeft = el.style.left, oldRsLeft = el.runtimeStyle.left;
                    el.runtimeStyle.left = el.currentStyle.left;
                    el.style.left = value || 0;
                    value = el.style.pixelLeft + "px";
                    el.style.left = oldLeft;
                    el.runtimeStyle.left = oldRsLeft;
                    return value;
                })(value);
            }
            return value;
        }
    }

function up(){
    var target = unit().y;
    return unit().body.top = suffixValue(target, -3);
}

    function down(){
        var target = unit().y;
        return unit().body.top = suffixValue(target, +3);
    }

    function left(){
        var target = unit().x;
        return unit().body.left = suffixValue(target, -3);
    }

    function right(){
        var target = unit().x;
        return unit().body.left = suffixValue(target, +3);
    }

function suffixValue(target, value){
    var suffix = "px";
    return (target + value)+suffix;
}

</script>
</body>
</html>


커맨드 패턴을 이용하여 각각의 메서드 호출을 실체화 함, and undo, redo 구현

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>command pattern</title>
    <style>
        #unit {
            position: absolute;
            background-color: olivedrab;
            top:100px;
            left:100px;
            display:block        }
    </style>
</head>
<body>
메서드의 호출을 실체화 함
<div id="unit">
    unit
</div>
<script>

    function getStyle(el, styleProp) {
        var value, defaultView = (el.ownerDocument || document).defaultView;
        // W3C standard way:        if (defaultView && defaultView.getComputedStyle) {
            // sanitize property name to css notation            // (hypen separated words eg. font-Size)            styleProp = styleProp.replace(/([A-Z])/g, "-$1").toLowerCase();
            return defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
        } else if (el.currentStyle) { // IE            // sanitize property name to camelCase            styleProp = styleProp.replace(/\-(\w)/g, function(str, letter) {
                return letter.toUpperCase();
            });
            value = el.currentStyle[styleProp];
            // convert other units to pixels on IE            if (/^\d+(em|pt|%|ex)?$/i.test(value)) {
                return (function(value) {
                    var oldLeft = el.style.left, oldRsLeft = el.runtimeStyle.left;
                    el.runtimeStyle.left = el.currentStyle.left;
                    el.style.left = value || 0;
                    value = el.style.pixelLeft + "px";
                    el.style.left = oldLeft;
                    el.runtimeStyle.left = oldRsLeft;
                    return value;
                })(value);
            }
            return value;
        }
    }
    document.addEventListener("keydown", handleInput, false);
    function handleInput(e){          //메인함수
        var keyCode = e.keyCode;

        var pressDispatcher = {       //command dispatcher            37 : new LeftCommand,
            38 : new UpCommand,
            39 : new RightCommand,
            40 : new DownCommand,
            89 : new RedoCommand,
            90 : new UndoCommand        };

        var button = pressDispatcher[keyCode];
        var isPress = (keyCode in pressDispatcher);
        if(isPress) button.execute();


    };

    var Command = function(){
        var x = unit().x, y = unit().y;
        return {
                "execute" : function(){

                    console.log("origin command execute");
                },
                "undo" : function(){
                    if(this.beforeLocation.length > 0){
                        var locationData = this.beforeLocation.pop();
                            unit().move(locationData);
                            this.redoHistoryWrite(locationData);
                    }
                },

                "redo" : function(){
                    if(this.afterLocation.length > 0){
                        var locationData = this.afterLocation.pop();
                        unit().move(locationData);
                        this.undoHistoryWrite(locationData);
                    }
                },
                'beforeLocation' : [],
                "undoHistoryWrite" : function(){

                    this.beforeLocation.push([unit().x,unit().y]);
                },

                'afterLocation' : [],
                "redoHistoryWrite" : function(){

                    this.afterLocation.push([unit().x,unit().y]);
                }
            };
    }();


    function RedoCommand(){

        function _RedoCommand(){
            this.execute = function(){
                this.redo();
            };

        }
        //@extends        _RedoCommand.prototype = Command;

        if(!(this instanceof _RedoCommand )){
            return new _RedoCommand();
        }
    }


    function UndoCommand(){

        function _UndoCommand(){
            this.execute = function(){
                this.undo();
            };

        }
        //@extends        _UndoCommand.prototype = Command;

        if(!(this instanceof _UndoCommand )){
            return new _UndoCommand();
        }
    }

    function UpCommand(){

        function _UpCommand(){

            this.execute = function(){
                this.undoHistoryWrite();
                up();
            };

        }
        //@extends        _UpCommand.prototype = Command;

        if(!(this instanceof _UpCommand )){
            return new _UpCommand();
        }
    }


    function DownCommand(){

        function _DownCommand(){
            this.execute = function(){
                this.undoHistoryWrite();
                down();
            }
        }
        //@extends        _DownCommand.prototype = Command;

        if(!(this instanceof _DownCommand )){
            return new _DownCommand();
        }
    }


    function LeftCommand(){

        function _LeftCommand(){
            this.execute = function(){
                this.undoHistoryWrite();
                left();
            }
        }
        //@extends        _LeftCommand.prototype = Command;

        if(!(this instanceof _LeftCommand )){
            return new _LeftCommand();
        }
    }


    function RightCommand(){

        function _RightCommand(){
            this.execute = function(){
                this.undoHistoryWrite();
                right();
            }
        }
        //@extends        _RightCommand.prototype = Command;

        if(!(this instanceof _RightCommand )){
            return new _RightCommand();
        }
    }


    function unit(){
        var target = document.getElementById('unit');

        return {
            "x" : parseInt(getStyle(target,"left"),10),
            "y" : parseInt(getStyle(target,"top"),10),
            "body" : target.style,
            "move" : function(arr){
                target.style.left = arr[0]+"px";
                target.style.top = arr[1]+"px";

            }
        };
    }
window.onload= function(){
    /*console.log(unit().x);*/};


</script>

<script>



function up(){
    var target = unit().y;
    return unit().body.top = suffixValue(target, -3);
}

function down(){
    var target = unit().y;
    return unit().body.top = suffixValue(target, +3);
}

function left(){
    var target = unit().x;
    return unit().body.left = suffixValue(target, -3);
}

function right(){
    var target = unit().x;
    return unit().body.left = suffixValue(target, +3);
}

function suffixValue(target, value){
    var suffix = "px";
    return (target + value)+suffix;
}

</script>
</body>
</html>

2016년 2월 25일 목요일

[classic asp] 엑셀에서 alt+enter 값 추가

개행문자에 대해서 치환을 해줄때 그냥 <br />을 넣어줄경우 밑에 셀로 한개 한개씩 생김
br 스타일에 <br style='mso-data-placement:same-cell;'> 이런식으로 넣어주면
alt+enter 값 들어간거처럼 들어감

2016년 2월 22일 월요일

추상 팩토리 패턴 (abstract pattern)


추상 팩토리 패턴(Abstract factory pattern)은 다양한 구성 요소 별로 '객체의 집합'을 생성해야 할 때 유용하다. 이 패턴을 사용하여 상황에 알맞은 객체를 생성할 수 있다.
대표적인 예로, 자바 프로그래밍 언어의 GUI 구성 요소인 AWT/Swing 라이브러리의 룩 앤드 필 변경 기능을 들 수 있다. 메탈마이크로소프트 윈도맥 OS 등의 모양으로 변경할 수 있다. 이에 따라 추상 팩토리에 있는 기본 팩토리 객체가 변경된다. 그러면 이후로 생성되는 GUI 객체들은 전부 해당 룩앤필에 따른다.

------------------------------------------------------
다이어그램 

abstract factory ---> abstract product
        ↑                          ↑
concrete factory ->   concrete product

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

다이어그램 구상

가상공장   ---> 차, 신발, 시계 등등 공장 제품 
   ↑                 ↑   
  공장      ->      완제품

------------------------------------------------------
구현 

<!doctype html>
<html lang="ko">
 <head>
  <title>abstract factory</title>
 </head>
 <body>
 <script>
 // 공장에서 여러 제품들을 만든다고 생각 하면 쉬움 
 
  var AbstractFactory ;  // 추상화된 공장(생산, 이름 등등의 기능 을 갖고 있을거임)
  var ConcreteFactory ;  // 구현된 공장(실질적 공장의 이름과, 작동에 대해 기술되 있을거임)
  var AbstractProduct ;  // 공장에서 생산할 제품들의 추상화된 인터페이스 (차, 시계, 신발 등등)
  var ConcreteProduct ;  // 해당 제품을 공장에서 만든다 생각 

  AbstractFactory = function(){
   this.location ='서울';
   this.companyName = 'nice';
  }; 

  AbstractFactory.prototype = {
   create : function(){
    console.log(this.product);
   },
   set : function(product){
    this.product = product.name;
   }
  };

  function ConcreteFactory(){
   var abstractFactory = new AbstractFactory
    abstractFactory.location = '경기';
    abstractFactory.companyName = 'nic';

   return abstractFactory;
  }

  function AbstractProduct_car(){
   this.name = 'car';
  }

  function AbstractProduct_shoes(){
   this.name = 'shoes';
  }


  var concreteProduct = new ConcreteFactory;
  var car = new AbstractProduct_car;
  var shoes = new AbstractProduct_shoes;
   concreteProduct.set(car);
   concreteProduct.create();
   concreteProduct.set(shoes);
   concreteProduct.create();
  


 </script>
 </body>
</html>