2014. 10. 14. 13:11

사진출처 : http://java9s.com/wp-content/uploads/2011/05/Spring-3-MVC-Basic-Flow.jpg

 

Client ---요청---> Server ---web.xml 분석 후 제어 넘김---> DispatcherSevlet

<--- Controller 결정 ---> HandlerMapping ---> DispatcherServlet <--- View, Model 리턴 받음 --- Controller

 

1) DispatcherServlet : 모든 사용자 요청 받음

2) HandlerMapping : 해당 요청 URL과 Controller를 맵핑

3) Controller : DispatcherSevlet에서 요청을 받고 요청에 따른 로직 수행

4) Controller : Model을 생성

5) DispatcherServlet : View 호출과 Model 출력

 

 

DispatcherServlet의 역할

1) HTTP 요청을 접수

2) HandlerMapping에서 해당 요청 URL에 해당하는 Controller 선정

3) 선정된 Contoller에게 웹 요청을 위임

4) 선정된 Controller에게 View객체와 Model객체를 리턴받음

5) View객체 호출과 해당 뷰에서 Model객체를 reference

 

HandlerMapping의 역할

- URL과 요청정보를 기준으로 Controller 선정

- 하나 이상의 Handler Mapping 가능

 

HandlerMapping(Interface)의 종류

- BeanNameUrlHandlerMapping(defualt)

 : bean설정 시 name속성으로 mapping

- RequestMappingHandlerMapping(defualt)

 : Controllerannotation을 부여해서 mapping

- SimpleUrlHandlerMapping : 설정파일에 한번에 모아서 설정

- ControllerClassNameHandlerMapping : 클래스명과 메서드명으로 mapping

- ControllerBeanNameHandlerMapping : Bean이름으로 mapping

 

참고) HandlerAdapter(Interface) : Controller의 메서드를 호출할 때 사용

 

View의 종류

- InternalResourceView(forward방식)

- RedirectView(redirect방식)

- MarchallingView(XML)

- MappingJacksonJsonView(Json)

 

ViewResolver의 역할

- Controller가 리턴한 View이름을 참고하여 View를 찾는다.

 

ViewResolver의 종류

- InternalResourceViewResolver

- ContentNegotiatingViewResolver

- ResourceBundleViewResolver

- XmlViewResolver


*web.xml

(경로 : WebContent/WEB-INF/web.xml)

<!-- DispatcherServlet 설정 -->

<servlet>

<servlet-name>OOO</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>

 

<servlet-mapping>

<servlet-name> OOO </servlet-name>

<url-pattern>*.html</url-pattern>

</servlet-mapping>

 

Controller / Service / DAOFlow

요청

-> 해당 Controller(서비스에 대해 의존적-DI필요)

: 요청에 대한 서비스 호출

-> 호출받은 Service: 필요한 DAO호출, 이곳에서 TX (트랜잭션)수행

-> 호출받은 DAO: DBSQL수행 <-> DB

 

Controller에서 View 리턴 방식 고려사항

- 요청에 대한 View가 필요한가?

만약 필요하다면 forward방식(view jsp)

불필요하다면 redirect방식(기능단 jsp)

(JSP파일 경로는 WEB-INF/view/OOO.jsp)

 

InternalResourceViewResolver - 편리한 forward방식의 View 지정

-WEB-INF/view.jsp 생략가능

-redirect:index.html 등으로 redirect 지정가능

<!-- 포워드 뷰 InternalResourceView를 편리하게 사용할 수 있도록 설정 -->

<!-- 경로는 WEB-INF/해당프로젝트명-servlet.xml파일 à

<bean

p:prefix="WEB-INF/view/"

p:suffix=".jsp"

class="org.springframework.web.servlet.view.InternalResourceViewResolver"/>

 

Controller Bean 등록하기

- 해당프로젝트명-servlet.xml에 등록

() <bean class="조직구분.회사명.프로젝트명.controller.LogController"/>

- Annotation을 이용(@Controller)

- 중복된 Url이 있는지 한번에 관리하기 용이

 

Model이 필요없는 요청(View만 있는 요청)

- 우리가 직접 Controller를 생성할 필요없음

<!-- view만 있는 요청들은 Controller를 안만들고 이렇게 할 수도 있습니다. -->

<!-- 경로는 WEB-INF/해당프로젝트명-servlet.xml파일 à

 

<mvc:annotation-driven/>

<mvc:view-controller path="/content.html"/>

 

Controller단에서 메서드 설정

- annotation @RequestMapping 지정

- GET/POST방식 다르게 지정 가능

@RequestMapping(value="join.html", method=RequestMethod.GET)

@RequestMapping(value="join.html", method=RequestMethod.POST)

파라미터 편리하게 받기

- annotation @ModelAttribute 이용

- parameterVOproperty 일치 시 자동으로 setting

 

Session에 등록

- annotation @SessionAttributes(“이름”) 이용

- Model에 이름의 Attributes가 있으면 Sessionscope등록

*scope란 객체가 살아있는 범위를 말함

*4가지 scope

- context : 웹 서비스가 유지되는 동안 유지

- session : 세션이 유지되는 동안(브라우저창이 켜져있는 동안)

- request : 포워드 방식일 경우 request가 유지되는 동안만 유지

- page : 해당 페이지내에서만 유지



크리에이티브 커먼즈 라이선스


Posted by 루피아빠
2014. 10. 14. 06:43

(번역)

Spring MVC framework에서 ModelAndView class Model class View class 모두를 소유하는 클래스입니다. 두 클래스를 모두 소유하지만 이 두 클래스는 완전히 별개입니다. ModelAndView class단지 Controller Model객체와 View객체를 단 하나의 값으로 리턴하는 것이 가능하게 해줍니다. 그리고 이 클래스는 handler DispatcherServlet class에 의해 리턴됩니다. View class form ViewResolver객체를 이용해서 String view name으로 처리합니다. 다른 방법으로는 View객체로 직접 처리됩니다. Model클래스는 Map인데 이 Map name에 의해 키값화된 복수 객체의 사용이 가능하게 합니다


(부연설명)

원래는 View에 대한 리턴을 ModelAndView 객체로 해야하지만 View객체만 리턴해도 됩니다. Forward ViewInternalResourceView객체를 사용합니다. 그래서 우리가 직접InternalResourceView객체를 넘기면 그냥 그 View를 이용합니다. 하지만 이게 너무 귀찮으니까 SpringMVC는 우리에게 편리한 방법을 제공합니다. 우리가 단지 JSP의 경로를 쓰면 알아서 InternalResourceView를 자동으로 만들어서 작동해줍니다. WEB-INF/view/XXX.jsp라는 접미,접두사가 항상 똑같고 길기 때문에 우리가 String으로 넘길때 InternalResourceViewResolver가 있어서 그게 편리하게 작동해줍니다. , 우리는 String을 그냥 JSP의 이름만 넘기면 알아서 접두(prefix),접미사(suffix)를 만들어서 InternalResourceView를 생성해줍니다. 그런데 더 편리하게 하기 위해서 Spring MVC는 심지어 우리가 리턴하지 않으면 알아서 해당주소(index.html)에서 .html를 제외한 이름의(index)jsp를 알아서 찾습니다.(RequestMapping)


(원문)

외부링크 : java.lang.Object

org.springframework.web.servlet.ModelAndView

public class ModelAndView

extends Object


Holder for both Model and View in the web MVC framework. Note that these are entirely distinct. This class merely holds both to make it possible for a controller to return both model and view in a single return value.Represents a model and view returned by a handler, to be resolved by a DispatcherServlet. The view can take the form of a String view name which will need to be resolved by a ViewResolver object; alternatively a View object can be specified directly. The model is a Map, allowing the use of multiple objects keyed by name.

Author : Rod Johnson, Juergen Hoeller, Rob Harrop



크리에이티브 커먼즈 라이선스

 


Posted by 루피아빠
2014. 10. 13. 18:53

VO(Value Object)

- 정보를 담고있는 객체

- read only 속성

- 관계형 데이터베이스(Oracle, MySQL )의 레코드(table column)에 대응( 1:1이 아니어도 됨)

- 정보를 담고 있는 변수인 private형 필드와 해당 필드에 접근 할 수 있는 각각의 Getter, Setter 메소드의 조합으로 클래스를 형성


DTO(Data Transfer Object)

- 데이터가 포함된 객체(VO)를 한 시스템에서 다른 시스템으로 전달하는 작업을 처리하는 객체

- 통신 용도로 오가는 객체

 

VO DTO의 차이

- 어떤 일을 하느냐에 따라 VO DTO로 이해하면 될 것 같다.

 

DAO(Data Access Object)

- DB 접근을 목적하는 객체

- 사용자는 자신이 필요한 Interface DAO에게 던지고 DAO는 이 인터페이스를 구현한 객체를 사용자에게 편리하게 사용 할수 있도록 반환

Posted by 루피아빠
2014. 10. 10. 16:52

Express 3.x to 4.x Migration Guide 요약 원문보기


Express4는 더이상 Connect에 의존하지 않습니다. 

그리고 모든 미들웨어(middleware)를 express core에서 제거했습니다.
(express.static만 예외)

이제는 Express가 독립적인 routing/미들웨어 웹 프레임워크입니다.

따라서 이제는 독립적인 미들웨어 업데이트에 영향을 받지 않습니다.

예전에 express core에서 그 자체로는 변한게 없는데도 많은 미들웨어의 변화때문에

express를 버전업했던 것을 상상해보세요.

이제는 필요에 의해서 미들웨어를 꼭 추가해야합니다. 

다음은 Express3과 비교한 Express4의 미들웨어 리스트입니다.

 

Express 3

Express 4

express.bodyParser

body-parser + multer

express.compress

compression

express.cookieSession

cookie-session

express.cookieParser

cookie-parser

express.logger

morgan

express.session

express-session

express.favicon

serve-favicon

express.responseTime

response-time

express.errorHandler

errorhandler

express.methodOverride

method-override

express.timeout

connect-timeout

express.vhost

vhost

express.csrf

csurf

express.directory

serve-index

express.static

serve-static

express.timeout

connect-timeout



express4의 미들웨어의 대부분은 express3의 middleware에 대응하는 drop-in 교체입니다.



The routing system


이제는 라우팅 미들웨어는 암시적으로 앱 안에서 로드됩니다. 

그래서 더이상 미들웨어가 로드 되는 순서에 대해 걱정하지 않아도 됩니다. 

routes을 정의(define)하는 방식은 Express3와 동일합니다. 

라우팅시스템은 더 효과적으로 routes을 조직할 두 가지 새로운 기능을 소개합니다. 

첫 번째는 app객체의 route() 메서드 입니다. 

app.route()를 사용해서  route handlers을 route path로 묶을(chainable) 수 있습니다. 

path가 한 경로에 지정되었기 때문에, 모듈단위의 routes을 만드는 것을 도와주고

중복(redundancy)과 typos(오탈자)를 줄일 수 있게 되었습니다.


다음은 app.route()를 이용해서 정의된 chained route handlers입니다.

1

2

3

4

5

6

7

8

9

10

app.route('/book')

 .get(function(req, res) {

   res.send('Get a random book');

 })

 .post(function(req, res) {

   res.send('Add a book');

 })

 .put(function(req, res) {

   res.send('Update the book);

 })




나머지 한 기능은 routes을 조직하는 것을 돕는 새로운 클래스입니다. 

express.Router

이것을 사용해서 모듈단위로 쌓을 수 있는 route handlers을 만들 수 있습니다. 

Router 인스턴스는 완전한 미들웨어이고 routing system입니다. 그 이유는

이 인스턴스가 종종 mini apps로서 참조되기 때문입니다. 


Router 인스턴스가 독립적인 미들웨어이고 라우팅 시스템이기 때문에, 

app의 구조를 짜고 route를 모듈화하는 데 Router class를 사용하는 몇 가지 방법이 존재한다. 

다음 예에서 모듈로써 router를 만들어 보자. 그리고 그 모듈 안에서 미들웨어를 로드하자. 그리고 몇 가지 routes을 

정의하자. 그리고 main app안에 경로로 지정된 path에 그 routes을 쌓자.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

var express = require('express');

var router = express.Router();

 

// middleware specific to this router

router.use(function timeLog(req, res, next) {

 console.log('Time: ', Date.now());

 next();

})

// define the home page route

router.get('/', function(req, res) {

 res.send('Birds home page');

})

// define the about route

router.get('/about', function(req, res) {

 res.send('About birds');

})


module.exports = router;


그리고 나서 앱 안에서 라우터 모듈을 로드하자. 

1

2

3

var birds = require('./birds');

...

app.use('/birds', birds);

이제 이 앱은 /birds와 /birds/about 요청을 처리할 수 있을 것이다. 동시에 

이 라우터에 명시된 timeLog 미들웨어를 콜 한다. 


다양한 미들웨어를 path에 load하고 router handler를 통해 파라미터 값을 얻어 올 수 있다. 


1

2

3

4

app.use('/book/:id', function(req, res, next) {

 console.log('ID:', req.params.id);

 next();

})





다른 변화들 (Express4에서 중요)


1) Node : Node 0.10.x or 그 이상이 요구됨 (0.8.x 지원 drop)


2) http.createServer() : 더이상 http 모듈은 필요 없다. app에서 app.listen()을 사용한다. 

(신)

var server = app.listen(3000, function() {

console.log('Listening on port %d', server.address().port);

(구) 

http.createServer(app).listen(app.get('port'), function(){

  console.log('Express server listening on port ' + app.get('port'));

});


3)app.configure() 제거됨 (환경 감지와 앱 설정)

= > 이제는 app..get('env') 사용 (or process.env.NODE_ENV)

4)json space : 기본값으로 이용할 수 없다. 

5)req.accepted() : 

- req.accepts()

-req.acceptsEncodings()

-req.acceptsCharsets()

-req.acceptsLanguages() 를 사용한다.


6)req.location() : 더이상 relative URLs를 해결하지 않는다. 

*absolute URLs : http://www.keycode.me/index.html

*relative URLs : /index.html

=>절대경로는 //가 context, 상대경로는 /가 context


7)req.params : 예전에는 배열(array)였지만 이제는 객체다(object)

8)res.locals : 예전에 함수(function)였지만 이제는 객체다(object)

9)res.headerSent : res.headersSent로 변경

10)app.route : 이제는 app.mountpath로써 이용할 수 있다.

11)res.on('header') : 제거됨

12)res.charset : 제거됨

13)res.setHeader('Set-Cookie', val) : 기본 쿠기값 설정하는 데 기능적으로 제한됨

=>추가된 기능을 사용하려면 res.cookie()를 사용해라.



Express3 app에서 Express4 app으로 이주하는 예제들


Express4에서 변한 것들을 알아봤으니까 기존에 express3 app에서 express4 app으로 이주해보자.

우리의 관심파일인 app.js와 package.json이다. 

다음 app.js파일을 살펴보자. (./는 현재 directory를 의미)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

var express = require('express');

var routes = require('./routes');

var user = require('./routes/user');

var http = require('http');

var path = require('path');

 

var app = express();

 

// all environments

 

app.set('port', process.env.PORT || 3000);

//app.set('views', __dirname + '/views');

app.set('views', path.join(__dirname, 'views'));

app.set('view engine', 'jade');

app.use(express.favicon());

app.use(express.logger('dev'));

app.use(express.methodOverride());

//추가

app.use(express.session({ secret: 'your secret here' }));

app.use(express.bodyParser());

app.use(app.router);

app.use(express.static(path.join(__dirname, 'public')));

 

// development only 

if ('development' == app.get('env')) {

 app.use(express.errorHandler());

}

 

app.get('/', routes.index);

app.get('/users', user.list);

 

http.createServer(app).listen(app.get('port'), function(){

 console.log('Express server listening on port ' + app.get('port'));

});


이 파일을 분석해보자.

1)http 모듈은 더이상 필수가 아니다. 

2)내장된 express 미들웨어인 

express.favicon

express.logger

express.methodOverride

express..session

express.bodyParser

express.errorHandler

는 더이상 express object상에서 이용할 수 없다. 

우리는 app안에 그것들을 로드하기 위해서 그 대안으로 교체된 미들웨어를 install 해야할 것이다. 

3) app.router는 로드되야하는 필수가 아니며 Express4 app 객체로 유효하지 않다. 

4) Express4 apps은 http.createServer로 시작하지 않고 app.listen()으로 시작한다. 


예전의 package.json 파일

1

2

3

4

5

6

7

8

9

10

11

12

{

 "name": "application-name",

 "version": "0.0.1",

 "private": true,

 "scripts": {

   "start": "node app.js"

 },

 "dependencies": {

   "express": "3.12.0",

   "jade": "*"

 }

}


최신의 미들웨어 설치

$ npm install 

serve-favicon 

morgan 

method-override 

express-session 

body-parser 

multer 

errorhandler 

express@latest 

jade@latest --save

package.json 다음과 같이 update 될 것이다. 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

{

 "name": "application-name",

 "version": "0.0.1",

 "private": true,

 "scripts": {

   "start": "node app.js"

 },

 "dependencies": {

   "body-parser": "^1.5.2",

   "errorhandler": "^1.1.1",

   "express": "^4.8.0",

   "express-session": "^1.7.2",

   "jade": "^1.5.0",

   "method-override": "^2.1.2",

   "morgan": "^1.2.2",

   "multer": "^0.1.3",

   "serve-favicon": "^2.0.1"

 }

}


이제는 유효하지 않은 코드를 삭제해보자. 

그리고 필요한 미들웨어를 로드하고 다른 변경사항들을 바꿔보자.

다음은 변경한 app.js이다.


var express = require('express');

var routes = require('./routes');

var user = require('./routes/user');

var path = require('path');

 

//이제는 필요한 미들웨어를 설치해야함

//(express4에서 미들웨어가 분리)(예외,static)

var favicon = require('serve-favicon');

var logger = require('morgan');

var methodOverride = require('method-override');

var session = require('express-session');

var bodyParser = require('body-parser');

var multer = require('multer');

var errorHandler = require('errorhandler');

 

var app = express();

 

// all environments

app.set('port', process.env.PORT || 3000);

app.set('views', path.join(__dirname, 'views'));

app.set('view engine', 'jade');

app.use(favicon(__dirname + '/public/favicon.ico'));




이것으로 우리의 이주 과정은 완료됬다. 우리 앱은 이제 Express4 app이다. 

확인하기 위해서 앱을 시작하고 http://localhost:3000 에 들어가서 Express4로 렌더링되고 있는지 봐라.


Express 4 app generator

더이상 npm install express -g(글로벌 모듈로 설치) 한다고 해서 generator가 설치 되지 않는다. 

이제 generator는 독립적인 npm package인 express-generator를 설치해야한다. 

만약 이미 Express3 app generator가 시스템에 설치되어 있다면, 우선 기존의 generator uninstall이 필요하다. 

다음은 기존 Express3 app generator를 삭제하는 command이다.

> npm uninstall express -g

삭제가 됬다면 이제는 Express 4 generator를 설치하자.

> npm install express-generator -g

Command 옵션과 방법은 크게 바뀌지 않았다.(옵션에서 --sessions와 --jshtml은 제거됨, --hogan은 추가됨)

앞으로 생성되는 앱은 Express 4 app이다.


Express 4 app을 생성해보자.

> express app4

app.js파일은 이제는 Node Module이다.


이제 app.js는 Express4 generator에 의해 생성된 노드 모듈이다. 

더이상 앱으로써 독립적으로 시작할 수 없다. 

노드파일 안에서 로드되고 시작되야 한다. 

우리의 경우, 노드파일은 node ./bin/www 에서 발생한다.  


 bin directory, www directory  은 의무사항이 아니다, 

이부분을 수정해서 사용 가능하다. 


www directory를 제거하고 예전 Express 3 방식을 이용하려면

app.js에서 마지막 라인인 “module.exports = app;” 제거하고 

아래 코드를 붙여 넣어라.


1

2

3

4

5

6

app.set('port', process.env.PORT || 3000);

 

var server = app.listen(app.get('port'), function() {

 debug('Express server listening on port ' + server.address().port);

 

});


app.js 최상단에 debug 모듈을 로드하는 것이 좋다. 

var debug = require('debug')('app4');


package.json파일 안에서 "start":"node ./bin/www"을  "start":"node app.js" 로 변경해라.


위 변경을 통해서 ./bin/www 이 가진 기능적인 부분을 app.js로 되돌려 놓았다. 이것은 추천되지는 않지만 이 연습을 통해서 ./bin/www이 어떻게 작동하는 지를 이해하고 왜 app.js 그 자체로 더이상 시작하지 않을 것인지에 대해 이해하는 데 도움이 될 것이다. 







 



Posted by 루피아빠
2014. 10. 10. 01:19

출처 :Tomomi Imura on Mobile Web, Future of CSS

(해당 동영상 및 MP3를 보시려면 위 링크로 이동하세요.)


1.We are here at Craft Con 2014 in Budapest, I’m sitting here with Tomomi Imura, so Tomomi who are you?


Hi, I’m a frontend web developer and I’m focusing more on the UX side but, I would say I’m more focused on mobile because always I had a passion in mobile and I’ve been working in mobile industries for a while, the companies including like Yahoo, but Yahoo's mobile team and I use to be a developer at Palm WebOS and I worked at Nokia as well, so I’ve been in the mobile industry for a while.

 

2.And you talk a lot about UX but also about the web, in recent times people have been saying that the Mobile web is dead, do you say that they talk nonsense or do you are agree, what is the situation, what do you think?


In some way I agree, I actually I would say “Mobile is dead” is a sensational title that grabs people’s attention, so if we have a news blog that is a really cool thing to say because people react with “What?”, people wants to get attention, so I don’t really think it’s dead of course, it’s not dead, it’s there, but in sense the reason I agree with is because we don’t, we shouldn’t really separate the mobile web from the web because the web is web, so actually like back in mid 2000 I was in Yahoo Mobile and back in the time mobile web was the thing, like mobile web you had heard of, we’ve seen WAP and then we had WML languages as well, but those days are over, now the mobile browsers are just like desktop browsers, we can write HTML 5 I would say and it works with both. So when we are talking about writing for the web that we expect is that it works on any device, mobile, desktop, doesn’t matter. 

Werner: But there is still a slight difference because the mobile devices, as diverse as they are, they have certain sensors that the desktop doesn’t have, you know I can't pick up my desktop and shake it, so there are still UX differences I guess. 

Yes, so the interesting thing is that mobile has its own, I would say, a different user experience because mobile to be mobile we take mobile devices with us, so it makes more sense that, let’s say, like a location where you are saying like motion of the device, something that we can do with the device which we don’t do on the desktop when we are sitting at a desk, so working on the mobile web as a developer we can take advantage working on mobile devices such as using all the sensors, so I was talking about this earlier at the conference as well, so we have the device APIs to access that hardware; mobile is mobile, it's a different experience.

 

3.You mentioned device APIs, so at this point in 2014, how stable are they, what do they offer, it’s just accelerometers or Geolocation, what do we have?


Yes, and Geolocation is one of the stable one, so the most of browsers already have support, so you can do this to access the user's data so accessing GPS or cell id to get the user location, that is stable. And device orientation event is another thing that we can get information of motion of that device itself, so when it’s tilted we know exactly how many degrees it's moved, and has been supported wonderfully except I think Internet Explorer. And all of that interesting APIs including vibration APIs and actually yes, the vibration API was supported only by Mozilla, I mean Firefox, but now is supported by Chrome, Chrome actually Chrome 30 as well, so yes, Google is catching up and so many other APIs including like actually ambient light APIs, like a battery APIs, currently only supported by Firefox. So there are a lot of other browser vendors that need to catch up and I’m hopeful we'll see this happening this year in 2014.

 

4.You mentioned Firefox, is that Firefox OS or is that generally Firefox?


I do have couple Firefox OS devices, so I can see that Mozilla is clearly pushing those standards really because they have Firefox always, but actually Firefox as a browser is wonderful, it works as well as the Firefox OS, so it does works fine in Android phones. 

Werner: But in Firefox OS obviously they need these API’s because you can only program them in JavaScript. 

Right, so it looks like they are really trying to set the standard because they want it and if it’s not available as a W3C Standard, they are the ones who are usually proposing it to the standard body to making happen, so I really like to see what they are doing.

 

5.We talked about mobile devices; so one distinguishing factor of mobile devices is they are coming in different form factors and I think for that the keyword is responsive design. Can you gives us an idea what responsive design is. Is it an UX method, is it a technological method, what is it?


Yes, with responsive design the idea is we try to write once, not a separate mobile site like m.whatever.com and such using one URL and that should work, seamlessly across the devices, because you know, we should not discriminate users, we don’t know, users depend on mobile phones, tablets, a desktop, we don’t know, so we have to keep the best possible experience for any users we have and so far when we are talking about responsive design that’s pretty much all the devices we are seeing, but in future we might have, I don’t know about if TV is going to be big again, I know in the 90’s there was a Web TV, looks like it failed, no one is browsing the web [on TVs].

I would say it’s not really easy to browse web on TV yet but you never know what will happen and where about and now we have Pebbles, Fitbits, etc and they don’t come with Web browsers, but Google Glass does have a browser, so now that will be another challenge that web developers have about how we support those wearable devices. Maybe Internet of things would be the next, again that might not come with browsers, so the experience is different, we don’t know yet, so we have to really think ahead and responsive web to be really responsive to anything, so that’s the challenge we have.

 

6.What web technologies help me with responsive design, is it CSS, how do I do this?


So mostly I’d say CSS because we have CSS Media Queries and that is a way we can give different experiences, I mean different experiences means UI using CSS to certain, let’s say, browser window height, or maybe not height but browser width or device width, orientation because when we are using a tablet we can switch orientation around, so CSS Media Query is key.

 

7.How do media queries work, is it just a form factor or can I say “Google Glass” or something like that, how does that work?


That is really another challenging thing because we don’t really have a definite answer, we are trying to find something like a breakpoint, you know like a which, mostly we are doing with the devices width, like the iPad has a certain width, and other devices, but everything is different, so people tend to do get the width of the iPad and such popular devices to support by certain, by size I would say, but many times it doesn’t work out, because we are just guessing what users device's size is, so I would say that’s pretty challenging and we are trying not to use, I mean we are trying not to differentiate by form factors too much because it’s kind of like using user agent sniffing which is a big no-no for developers to do because user agent fails, we don’t exactly get the correct information from this, so we have to make it as generic as possible, so people are using common width of the device in a browser but still that could depend on your design.

 

8.Talking about CSS, what are some of the exciting new features that you are looking forward to in CSS, what are some of the features that might change the nature of CSS, make it easier to use?


Currently so many developers depend on preprocessors such as Sass or Less because there are so many features that we want to use that are missing from the current web standard. First of all we have so many different browsers means we need to have a browser specific prefix, so if we want to support new features like animations, we have to add browser prefix, the vendor prefix for each one of them and that can be really long, so we want to get rid of those and by using preprocessor. Or I would say variables, if we want to set some colors to certain variables we can reuse the same variable or we don’t have to keep changing each time in design I make changes, right? So this is not doable yet with current CSS but now we have a new standard that is coming, there is a proposal about CSS variables and other things that close a gap in between current standard and something that preprocessors do, so that would be really wonderful news to us.

 

9.You mentioned Sass and Less, so with these new standards would those go away those preprocessors or do you think they still offer some utility?


I think it will stay but once standards, like CSS standard catches up, this is something interesting because like maybe few years ago everybody was using jQuery, but then what the jQuery guys have done to the web standard is actually wonderful, I mean you use to have a $ but now we have a querySelector (method) as a standard, so something like this once [the features ] make it into the standard maybe we are going to depend and less and less on Less, I don’t try to joke about it, but yes, that’s what I think and that will be actually great news because it’s not like you know we are ditching them, it’s more like Sass and Less guys have contributed so much to make the standards better, so I think that will be great if it happens.

Werner: They basically helped design the standard by providing a useful workaround.

I think so, I would say so. 

Werner: That happens a lot in the web, as you say, with jQuery and all these ideas, it’s a very communal I guess design process. 

I really think web is free to the community work and everyone of us as a developer to participate, doesn’t matter if we are actually officially W3C member or not, we can always express our opinions.

 

10.Since you mention Less and Sass, what do you think of other languages that compile to JavaScript, so when you write code do you write JavaScript, do you write CoffeeScript, do you write Dart?


I can’t really say much because I haven’t really used CoffeeScript, so when I use JavaScript it’s JavaScript and it’s yes, I can’t really see if you know what I mean, I’m not saying I can’t trust how it’s get it converted and so, but I just simply haven't tried. 

Werner: You still prefer JavaScript. 

Yes, just my personal preference. 

Werner: To wrap up, a few months ago, years ago you created something involving HTTP and cats, so you bring the best two thing on the web together, what did you do there. 

So really Internet is for cats, is what everybody says, so I’m a big cat person, I do have a cat, I used to have two but now only have one, but anyway I’m a big cat lady and I love Internet as well so of course you want to bring two things together, and I don’t know how I got the idea but you know of course HTTP status errors are just something that we see all the time, maybe daily, so one day I just decide to combine them all, I never expected that was going to be so successful that gave me like 15 minutes of fame. Interesting phenomenon people do like cats. 

Werner: If you want to promote something, use cats. 

Just use cats, it’s my takeaway, cats solve everything. 

Werner: It’s a great way to end and thank you very much Tomomi!

Thank you for having me!

 

Posted by 루피아빠
2014. 10. 10. 01:02

node.js 소개 및 내부구조

<배울내용>

1) node.js 소개

2) 장점

3) 내부 작동 원리 구조

4) single thread model

-thread pool

5) event loop

6) 언제 node.js를 쓰거나 쓰지 말아야 할까?


Node.js 설치하고 개발환경 설정하기 

<배울내용>

1) node.js설치하고 개발환경 설정


Event,Module,NPM

<배울내용>

1) 비동기 이벤트 프로그래밍

2) event emitter

3) event emitter methods

4) module 개념

5) module의 경로

6) module의 종류

7) NPM

-주요 명령어

7) package.json


웹개발 프레임웍 Express 1/2

<배울내용>

1) express project 생성

- 디렉토리 구조

- app.js 환경설정 파일 분석

2) Router 개념

3) HTML Parameter Passing

- URL Param

- Query Param

- Form Param

4) Rendering & Template

- ejs, Hogan, jade

5) HTTP Head 정보처리

6) HTTP Cookie 처리

- Signed Cookie사용(암호화)

7) HTTP Session 처리

-Cluster에서 Session처리


웹개발 프레임웍 Express 2/2

<배울내용>

1) File upload & File Download

2) JSON REST API

3) Connect Module pipe line

4) Error Handling



'프로그래밍 > Node.js' 카테고리의 다른 글

Node.js 시작  (0) 2014.10.09
BEM(Block-Element-Modifier) 시작  (0) 2014.10.09
Posted by 루피아빠
2014. 10. 9. 20:34

1. NODE.JS란 무엇인가?

- NODE.JS는 서버사이드상에서 자바스크립트 언어를 이용해

확장 가능한 네트워크 애플리케이션을 만들 수 있도록 해준다.

- 엔젠으로 크롬 V8 JavaScript Runtime(대부분 C code)을 이용하기 때문에 빠르다.

 

2. NODE.JS로 구축할 수 있는 것은?

-채팅 서버같은 웹소켓 서버

-빠른 파일 업로드

-AD Server

-리얼타임 데이터 앱

 

3. Blocking vs Non-blocking 개념

1) Blocking code

var contents = fs.readFileSync('/etc/hosts');

console.log(contents); ç여기서 완료되어야 다음 수행문으로 넘어감

console.log('Doing something else');

 

2) Non-Blocking Code

fs.readFile('/etc/hosts', function(err, contents) {

console.log(contents);  ç 1

});

console.log('Doing something else');  ç 1 완료와 상관없이 수행됨(block되지 않음)

 

3) callback을 이용

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

fs.readFile('/etc/hosts', function(err, contents) {

console.log(contents);

});

----------------위 코드와 동일---------------------------

var callback = function(err, contents) {

console.log(contents);

}

fs.readFile('/etc/hosts', callback);

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


콜백 두개


var http = require('http');

http.createServer(function(request, response) { ç request

           response.writeHead(200);

response.writeHead(“Dog is running.”);

setTimeout(function(){ ç timeout

response.write("Dog is done.");

response.end();

}, 5000); 5000ms

}).listen(8080);







'프로그래밍 > Node.js' 카테고리의 다른 글

nodejs 배우기  (0) 2014.10.10
BEM(Block-Element-Modifier) 시작  (0) 2014.10.09
Posted by 루피아빠
2014. 10. 9. 01:43

BEM(Block-Element-Modifier)

- HTML 마크업 모듈화

- block요소를 독립적이고, 재사용 가능한 모듈이라는 개념으로 접근

- 대표적인 사이트 tuts+

- 예).block(전체를 감싸고 있는 블록요소)__element(내부 요소)--modifier(기능)

prefix 붙여 일종의 네임스페이스개념으로 사용

- 실제 서비스를 하면 HTML의 구조가 바뀌는 일이 다반사

- 탐색레벨은 낮고 단순하게 유지하는 것이 유지보수하기 좋음

- 최근 브라우저 테스트 자동화에 대한 요구가 커지고 있음

- 쿼리를 단순하게 하기 위해 길고 유니크한 클래스명을 사용하는 것이 좋음


장점

-class name 중복방지

-직관적 : .gnb__home--active .icon-home

-전제 DOM tree를 다시 보지 않아도 됨


환경에 대한 변경을 표시해주는 클래스명을 

root node(delegate parent)에 부여하자


1)<html class="js lt-ie10 mobile">

: js, css 지원여부와 데스크탑/모바일 등의 client 접속 환경정보

2)<body class="log-in myinfo abtest-a">

: 접근중인 컨트롤러, 실행중인 액션, 로그인, AB테스트의 대상 여부 등

3)<div class="msgbox msgbox__unread">

:BEM에서 block요소 - 개별 모듈의 상태에 대한 정보를 담는다.


페이지의 상태값을 javascript로 전달할 방법이 필요


- 자바스크립트 전역변수나 <input type="hidden">사용을 지양하자.

=> HTML5스펙의 data-* attribute를 사용하자!(장점보기)



CSS속성은 한줄에 하나만 선언!

- 가독성이 좋고 어느 속성을 어느 위치에 넣을 것인지 고민할 필요 없음

- diff 할때 좋음

빌드타임에 minify하는 전략


BEM 예


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

.block {}

.block__element {}

.block--modifier {}

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

.site-search {} /* Block */

.site-search__field {} /* Element */

.site-search--full {} /* Modifier */

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

.person {}

.person__hand {}

.person--female {}

.person--female__hand {}

.person__hand--left {}

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

<form class="site-search  site-search--full">

    <input type="text" class="site-search__field">

    <input type="Submit" value ="Search" class="site-search__button">

</form>

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

.media {}

.media__img {}

.media__img--rev {}

.media__body {}

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

<div class="media">

    <img src="logo.png" alt="Foo Corp logo" class="media__img--rev">

    <div class="media__body">

        <h3 class="alpha">Welcome to Foo Corp</h3>

        <p class="lede">Foo Corp is the best, seriously!</p>

    </div>

</div>

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

<div class="content">

    <h1 class="content__headline">Lorem ipsum dolor...</h1>

</div>logo {}

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

.site-logo {}

.site-logo--xmas {}

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

.header__logo {} 

.header__tagline {} 

.header__searchbar {}

.header__navigation {}

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

.header__navigation {}

.header__navigation--secondary {}

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

.label {}

.label--alert {}

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

with Sass

.header__navigation { 

    background: #008cba; 

    padding: 1rem 0; 

    margin: 2rem 0; 

    text-transform: uppercase; 

    } 

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

.header__navigation--secondary { 

    @extend .header__navigation;

    background: #dfe0e0; 

    }

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

.label { 

    background: #eee; 

    border-radius: 505; 

    color: #333; 

    font-size: 1rem; 

    } 

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

.label--alert { 

    @extend .label; 

    background: #da4531; 

    color: #fff; 

    }

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


하지만 어떤 BEM카테고리에 들어가지 않는 클래스는 굳이 끼워맞추지 않음

.caps { text-transform: uppercase; } 

.site-logo {}


'프로그래밍 > Node.js' 카테고리의 다른 글

nodejs 배우기  (0) 2014.10.10
Node.js 시작  (0) 2014.10.09
Posted by 루피아빠
2014. 10. 8. 17:09

화두 : 다양한 프론트 앤드 프레임워크 대두(대표적으로 angular.js)

ð    프론트 단에서도 아키텍팅 필요

     ð HTML/CSS/JavaScript 만으로도 웹 애플리케이션 구현 가능


SPA접근 방식은 JSP, PHP같은 서버 템플릿이나 스프링 프레임워크에 익숙한 개발자에게는 생소


- 앵귤러는 front-end application framework

- 스프링 MVC 패턴의 개발을 했다면 앵귤러에서도 가능

- 스프링 의존성 주입의 편리함을 누리고 있다면 앵귤러에서도 가능

 



출처 : http://mobicon.tistory.com/m/post/427





Posted by 루피아빠
2014. 9. 14. 13:47

(출처 : 임재춘의 과학기술자글쓰기 강의 자료 -글쓴이 임재춘-


자기소개서 쓰기

임재춘

 

1. 소개서도 변해야 한다

자기소개서 쓰는 법이 잘못 알려져 있다. 대부분 사람들은 성장 배경, 학과 선택 동기, 성격 및 가치관과 지원 동기를 차례대로 쓴다. 이러한 자기소개서의 형식은 대학 작문 교재와 인터넷에 예문까지 나와 있어 대다수의 사람들이 아직도 이 틀을 벗어나지 못하고 있다. 하지만 이러한 형식은 산업사회의 인재 채용 방식에나 적합한 양식이다. 산업사회에서는 채용시험으로 합격자를 많이 뽑고, 사내 교육을 통하여 이들의 전문성과 조직 문화를 키워 나갔다. 그렇기 때문에 자기소개서는 단지 회사의 조직문화에 바람직한 인재인지 아닌지 인사담당자가 판단하는 보조 자료로 필요했던 것이다.

세상이 바뀌면 자기소개서도 바뀌어야 한다. 정보사회는 지식의 창출 및 이를 원활히 소통하는 자를 더욱 중시하여 적재적소에 맞는 인재를 수시 전형으로 선발한다. 산업화 시대의 'Anybody'가 아니라 정보화 시대의 'Somebody'를 원하는 것이다. 이로 인해 회사들도 신입사원보다 경력사원을 많이 원하고 있다. 물론 대학 졸업자는 신입직원도 되어 보지 못했는데 회사가 경력사원을 선호한다니 억울하기까지 하다. 억울할 것 없다. 대부분의 회사들이 경력사원을 원한다고 해도 한계가 있기 마련이다. 그렇기 때문에 일부 회사에서는 차선책으로 경력은 없어도 그런 능력을 키우고 있는 졸업자를 애타게 찾고 있다. 그러므로 자기소개서에 자기가 어떤 배경을 가지고 자란 사람이라는 '역사'를 적거나 어떤 '포부나 인생관'을 가진 사람이라고 열심히 피력할 필요가 없다. 단지 어떤 전문적인 일을 할 수 있는 '능력', 그것도 얼마나 재미를 느끼면서 '몰두'하였는지를 적으면 되는 것이다.

 

2. 성장 배경, 성격 및 가치관은 면접 때 자연스럽게 드러난다. 수시전형에 수백 명이 몰려드는데 구시대의 자기소개서를 접수해 놓고 세상을 탓하기보다는 자신의 '능력''몰두'를 한눈에 일목요연하게 보여 주는 소개서로 승부를 걸어야 한다. 자기소개서만으로 취직에 성공한 졸업생이 보낸 내용이다.

 

2002년 저는 4학년이 되었습니다. 1학기가 끝날 때까지도 저는 취업을 희망하면서도 어떻게 준비하여야 하는지 몰랐습니다. 2학기가 되어 막상 취업을 하려니 제일 먼저 부딪치는 것이 자기소개서였습니다. 평소 글 쓰는 것에 자신이 있다고 생각한 나였는데 막상 쓰려고 하니 두서가 없어지고 얽히기만 했습니다. 그러나 2학기에 '의사소통 기술' 수업을 듣게 된 후 자신이 무엇을 할 수 있는지를 확실히 알릴 수 있는 방법과 그 많은 소개서 중에서 주목을 받을 수 있는 방법 등을 배울 수 있었습니다. 그 결과, '영창악기'100명이 넘는 지원자들 중 자기소개서만으로 면접에 오르게 되었습니다. 그리고는 1001의 경쟁률을 뚫고 당당하게 입사하였습니다.(영남대, 전자공학과, 배재형)

 

소리와 전자와 만남을 좋아하는 배형진 소개

 

귀사의 영업부서에 지원하게 됨을 기쁘게 생각합니다. 저는 어려서부터 음악과 악기를 좋아했고 직접 연주도 해보았습니다. 대학시절 밴드생활을 통해 악기 다루는 사람의 마음을 누구보다 잘 알고 있습니다. 또한 전기와 전자공학을 전공하여 이 분야에 대한 기초지식을 가지고 있습니다. 거기다 사람 만나는 것을 즐기고 이야기하는 것을 좋아하는 저로서는 이번보다 좋은 기회가 없다고 생각합니다.

 

(상세 내용은 '한국의 이공계는 글쓰기가 두렵다' 참조)

 

3. 개인 이력이나 다짐은 금물이다

자기소개서도 읽는 사람에게 필요한 정보를 담아야 한다. 자신의 이야기를, 그것도 장황하게 늘어놓으면 안 된다.

 

주위가 산으로 둘러싸이고 앞으로는 탁 트인 시야를 가진 나의 고향은 대구이다. 지금은 아파트 단지로 발 디딜 틈도 없이 변해 버린 대구 범물동에서 24년 전 봄에 가족모두에게 축복을 받으며 태어났다. 집에서 막내로 태어나 두 형들 속에서 귀여움을 받으며 커왔다. 주위환경 덕분에 어릴 때는 뭐든지 쥐고 놀면 놀이기구가 되었고 어디든지 뛰어 놀면 놀이터였다.

-> 저는 대구 근교에서 태어나 자연 속에서 마음껏 뛰놀며 자랐습니다.

 

자신의 신변잡기가 네 줄이 넘지만 읽는 사람에게 필요한 정보는 한 줄이 채 되지 않는다. 그나마 이 한 줄도 주제와 관련이 있을지 의문이다. 이러한 개인 이력뿐만 아니라 누구나 할 수 있는 경험이나 개인적인 다짐, 철학도 도움이 되지 않는다. 도움은커녕 오히려 역효과가 날 때가 많다.

 

<1> 저는 안 해본 것이 없을 정도로 많은 사회적 경험을 쌓았습니다.

<2> 군 경험과 동호회 간부 생활을 통해 리더십을 터득하였습니다.

<3> 저는 무슨 일이든지 잘 합니다. 맡겨만 주십시오.

<4> 입사를 시켜 주시면 열심히 노력하여 최고의 전문가가 되겠습니다.

<5> 저의 좌우명은 성실입니다.

<6> 저는 자신감 하나만은 뛰어납니다.

 

<예문 1>의 경우, 많은 사회 경험을 나열하면 산만하여 회사가 원하는 직무와 관련된 경험마저 돋보이지 않게 된다. <예문 2>의 경험으로 리더십을 논하기에는 무리가 있다. 리더십은 남의 객관적인 평가에 의하여 얻어지는 것이 자연스럽지, 자기가 인정할 것은 아니다. <예문 3>'팔방미인'형인데 모든 것을 잘 한다는 것은 그만큼 특정 분야에는 집중력이 떨어진다는 것도 의미한다. <예문 4>의 경우에는 하나마나한 소리이다. 누구나 가지는 입사 포부이기 때문이다. <예문 5><예문 6>은 자신의 철학을 피력한 것인데 이것도 무용지물이다. 회사는 조직이 필요로 하는 전문성에 관심이 있다. 전문성을 갖춘 응시자를 먼저 뽑은 후에 면접에서 '성실'이나 '자신감'을 보기 때문에 자기소개서에는 철저하게 자신이 무엇을 잘 할 수 있는지에 초점을 맞추어야 한다.

 

5. 하나의 주제에 집중하자

회사가 필요로 하는 인재가 자신임을 잘 드러내기 위해서는 회사의 직무와 밀접한 관계를 가진 뚜렷한 주제 하나를 선정하는 것이 좋다. 그리고 제목을 '자기소개서'라고 달기보다는 아래의 <예문 1><예문 2>와 같이 주제문을 제목으로 하는 것이 구체적인 내용을 첫눈에 전할 수 있어 좋다.

 

<1> 온라인 게임 제작의 전문가가 되고 싶습니다.

<2> 발모제에 관한 한 정성을 통해 감동을 팔고 싶습니다.

 

주제가 정해지면 성장과정, 성격, 취미 등의 모든 내용을 이 주제에 집중해야 한다.

 

<1> 제목 : 온라인 게임제작의 전문가가 되고 싶은 ㅇㅇㅇ 소개

성장과정 : 게임을 밥 먹기보다 좋아해

성격 : 꼼꼼하고 집중력 강해

특기분야 : 온 라인 게임 제작은 자신 있어

지원동기 : 최고의 전문가로서 회사와 더불어 발전하고 싶어

 

<2> 제목 : 발모제에 관한 한 감동을 팔고 싶어

 

성장과정 : 아버지의 머리와의 전쟁을 보고 자라

성격 : 명랑하고 누구와도 잘 어울려

특기분야 : 공부는 못해도 정밀화학은 좋아해

지원동기 : 정성을 통해 감동을 팔고 싶어

 

성장과정과 성격 같은 소제목내용을 나타내는 표현으로 바꾸는 것이 좋다. 그래야 읽는 사람이 많은 정보를 쉽고 빠르게 얻을 수 있다. 또한 주제와 관련이 없는 사항은 과감하게 버리고 상투적인 표현은 주제와 밀접하게 관련을 가질 수 있도록 한다.

<1> 저는 경상북도의 조그마한 마을 o oo o리에서 11녀의 장녀로 태어나 엄하신 아버지와 자상한 어머니의 가르침을 받고 초등학교는 ……, 중등학교는 ……. (상투적인 표현) -> (모두 삭제)

 

<2> 저는 11녀 중 장녀로 자랐습니다.

-> 저는 자라면서 남동생과 많이 다투었습니다만 그러한 기회를 통하여 경쟁과 협조의 의미를 배웠습니다.

 

<3> 저는 무엇이든 과감하게 처리하기를 좋아합니다. 그러다 보니 일을 세밀하게 챙기지 못할 때가 많아 이를 고치려고 노력하고 있습니다.

 

-> 저는 소극적이고 내성적입니다. 소극적인 사람은 매사를 신중히 생각하며 내성적인 사람은 남의 심정을 잘 헤아리는 경향이 있다고 합니다.

 

<예문 1>은 주제와 관련이 없으므로 삭제하는 것이 좋다.

<예문 2>는 상투적인 표현을 쓰더라도 자신의 장점을 드러낼 수 있는 수단으로 활용할 수가 있다.

<예문 3>은 성격의 장·단점을 모두 적으려니 내용 전개에 무리가 따른다. 이럴 경우에도 단점을 장점으로 바꾸어 표현하는 방안을 강구해야 한다.

 

6. 보기 좋게 만들자

자기소개서는 첫 인상에 호감이 가야 경쟁력이 있다.

물론 회사가 원하는 양식에 충실해야 하지만 반드시 따를 필요는 없으며 자기만의 개성과 창의성을 부여하는 것이 좋다. 앞에서 본 바와 같이 단순히 소제목을 '성격'이라고 표시하기보다는 '성격; 꼼꼼하고 집중력 강해'로 하면 핵심정보를 한 눈에 전달할 수도 있다. 본문 내용 가운데 꼭 강조하고 싶은 것은 두 세 개 정도의 핵심단어검게 'bold'로 처리하여 읽는 사람의 눈에 금방 들어가게 하는 것이 좋다. 인터넷 원서 접수는 한 자리를 두고 수 백 명이 지원하기 때문에 첫 인상이 나쁜 소개서는 쓰레기 통으로 직행할 가능성이 매우 높다. 그러므로 작은 글씨로 빽빽이 적는 것은 낙제감이다. 두 장의 소개서 역시 지루한 느낌을 줄 수 있으므로 한 장에 그것도 85% 정도 되는 분량에 핵심 내용을 충분히 기술해야 한다.

이 외에도 자기소개서를 쓸 때 주의할 사항은 다음과 같다.

 

<1> 솔직하게 적어야 한다.

<2> 간결하고 명료해야 한다.

<3> 내용이 서로 연관을 가지고 어울려야 한다.

<4> 문단 단위로 소주제를 나누어야 한다.

<5> 교정을 해야 한다.

 

'글쓰기' 카테고리의 다른 글

임재춘의 힘글쓰기  (0) 2014.09.13
임재춘의 파워 글쓰기  (0) 2014.09.13
Posted by 루피아빠