'기타'에 해당되는 글 131건

  1. 2018.02.14 김성훈 딥러닝 8 - 딥러닝의 기본개념
  2. 2017.11.19 김성훈 딥러닝 7 - 학습 rate, Overfitting, 일반화
  3. 2017.11.17 김성훈 딥러닝 6 - Softmax Regression
  4. 2017.11.16 김성훈 딥러닝 5 - Logistic Classification의 가설함수 정의
  5. 2017.11.16 김성훈 딥러닝 4 - 다변수(Multi-variable) Linear Regression
  6. 2017.11.15 김성훈 딥러닝 3 - Linear Regression 의 cost 최소화 알고리듬
  7. 2017.11.15 김성훈 딥러닝 2 - Linear Regression의 가설(Hypothesis)과 비용(cost) 설명
  8. 2017.11.14 김성훈 딥러닝 1 - 머신러닝 용어와 개념
  9. 2017.11.13 김성훈 Tensorflow
  10. 2017.09.07 텍스트 파일을 이북(epub)으로 변환하기 (2)
  11. 2016.06.07 샤오미 밴드 + 샤오미 체중계 간략 사용기
  12. 2016.05.05 PHP XML Parser expat을 사용하여 XML을 mySQL에 저장하기
  13. 2016.04.30 NetBeans 디버깅환경 설정
  14. 2016.04.27 easyPHP에 XDebug 설치하기
  15. 2016.04.26 easyPHP 설치 및 XAMPP 설치
  16. 2016.04.11 Git 간단 사용법
  17. 2016.04.03 자작 통돌이 로스터 제작기 2탄
  18. 2016.01.27 자작 통돌이 로스터 2탄 만들기 - 자료 (2)
  19. 2015.11.27 구글 드라이브 1TB 무료공간 확보하기 (4)
  20. 2015.03.02 앵무새 죽이기(To Kill a Mockingbird)
  21. 2015.01.02 PC의 영화를 TV에서 보는 방법 - 크롬캐스트 미러링 (20)
  22. 2014.07.23 Zend Server 설치과 에러처리방법 (4)
  23. 2014.06.26 PHP 5 투토리얼 (6) - AJAX
  24. 2014.06.26 PHP 5 투토리얼 (5) - XML
  25. 2014.06.24 PHP 5 투토리얼 (4) - Database
  26. 2014.06.23 PHP 5 투토리얼 (3) - 고급
  27. 2014.06.22 PHP 5 투토리얼 (2) - 폼
  28. 2014.06.22 PHP 5 투토리얼 (1) 기초
  29. 2014.06.15 스마트 RC카 Hammer (10)
  30. 2014.06.14 Wi-Fi 스마트 RC HAMMER!! - 제가 처음으로 만져본 RC 카. (20)
기타2018. 2. 14. 00:58

Lec 08-1 딥러닝의 기본 개념 : 시작과 XOR 문제

https://www.youtube.com/watch?v=n7DNueHGkqE

  • 인간의 궁극적 목적 : 대신 생각해주는 기계

    • 전체적으로 매우 복잡하지만, 그것을 구성하는 뉴런은 매우 단순함
    • 이것을 수학적으로 만들면 다음과 같음.
      • body에서 여러개의 신호 $ x_0 , x_1 $ 등을 가중치 $ w_0 w_1 $로 받아 모두 합치고, 
      • 여기에 bias를 추가한 값이 activation function의 일정한 threshold를 넘으면 output =1

  • 이는 Logistic regression 과 유사

  • Hardware 구현

    • AND/OR 연산을 하면 스스로 학습가능하고 재생산가능한 인공지능이 가능할 것이라고 생각함. 이는 단순한 전기적 신호처리로도 가능하다.

    • 그런데 단순한 XOR도 처리할 수 없었다.

  • MIT AI Lab에서 Perceptrons(1969) 에서 불가능함을 수학적으로 증명
    • 여러개를 합치면 MLP (MultiLayer perceptros) 가능하지만, 학습이 불가능하다고 함
    • 이후 인공지능에 대한 관심이 10년 이상 후퇴함

  • 1974년... 80년대 후반에 이르러 이 학습문제 해결가능해짐

  • 고양이 실험 LeCun
    • 특정 모양에 대해서 특정 뉴런만 반응한다는 것을 알게됨
    • 일부 신경들의 신경망들이 나중에 조합

  • Convolutional Neural Networks
    • 부분을 잘라서 보낸 뒤 나중에 합치는 방법으로
    • Alphago도 이 방법 사용
    • 글자 인식 등에 90% 이상의 성능을 발휘.

    • 84-94 : 자동주행차량 연구에 사용

    • 터미네이터2 에도 Neural-net 이 나옴.
  • 문제에 봉착함.
    • Backpropagation이 layer가 많아질수록 성능이 나빠짐.
    • SVM 등의 새로운 간단한 알고리듬이 나옴.
    • LeCun 교수도 1995 년에 비효율적이라고 하고 포기함.

Lec- 08-2 Back-propagation 과 2006/2007 '딥'의 출현

  • CIFAR (Canadian Institute for Advanced Research)
    • 당장 성과가 없어도 연구하도록 장려. 1987년 Hinton은 캐나다로 이주함.
  • 2006, 2007 년 Hinton/Bengio 가 장벽을 깨는 논문을 발표함.
    • Layer가 많을 경우에도, weight를 잘 초기화시키면 training이 가능핟.
    • 어려운 문제에 대해서는 Deep machine learning 방법이 훨씬 효율적이다.
    • 이름을 Deep Learning 으로 Rebranding
  • IMAGENET 대규모 시각인식 챌린지 대회에서 주목을 받게됨.
    • 140만개의 영상에서 1000개의 object class 를 분류하는 것.

    • 2010년에 에러율 30%. 겨우 몇 %정도씩 발전. 그런데 2012년에 급격한 발전. 박사과정 논문. 계속 발전하여, MSRA 연구에서 3% 대 오류로. 사람(스탠포드 학생) 보다 더 나음.

    • 그림을 설명할 수 있게됨

    • Deep API
      • 자연어를 해석하여 필요한 API를 자동으로 끌어와서 프로그램 생성
      • 정확도가 65% 정도로 올라갔음.

  • 소음이 많은 환경에서 음성 인식도 획기적으로 개선.

  • Alphago

  • Geoffrey Hinton 박사가 발견한 사항
    • 아직 labelled dataset이 수천분의 일 수준으로 부족하다.
    • 컴퓨터가 백만배 더 빨라야 한다.
    • 아직도 가중치 초기화가 불합리하다.
    • 비선형 유형을 잘못사용하고 있다.
  • 왜 인공지능에 신경을 써야 하나?
    • 뭔가 데이터를 만지고, 판매하고 있다면 인공지능에 대해 아는 것이 도움 많다.
      • 유튜브 자막, 페이스북 추천, 구글 검색결과
      • 네플릭스, 아마존 등의 경우도 추천.
    • 실생활에서도 활용가능. 진열품 배치 등

  • 왜 지금 해야 하나?
    • 지금 시작해도 세계적인 전문가가 되기에 늦지 않다.
    • 수학적으로도 복잡하지 않다.
    • 현재 90% 이상의 정확도.
    • 도구가 많이 공개되어 있다. 
    • Python 과 같은 쉬운 언어.
    • 매우 즐겁다!!

Lab 8 - Tensor Manipulation

  • 텐서 행렬 처리

import tensorflow as tf
import numpy as np
import pprint

tf.set_random_seed(777)

pp = pprint.PrettyPrinter(indent=4)
sess=tf.InteractiveSession()

t = np.array([0, 1, 2, 3, 4, 5, 6])

print(t.ndim) # rank -> 1
print(t.shape) #shage ->7
print(t[0], t[1], t[-2])
print(t[2:5], t[4:-1])

t = np.array([[1,2,3], [4,5,6], [7,8,9], [10,11,12]])
pp.pprint(t)
print(t.ndim)
print(t.shape)

  • Shape, Rank, Axis

t=tf.constant([1,2,3,4])
tf.shape(t).eval()  #4
t=tf.constant([[1,2,3], [5,4,6]])
tf.shape(t).eval()  # 2,3

t = tf.constant(
       [[[[ 1,  2,  3,  4],
         [ 5,  6,  7,  8],
         [ 9, 10, 11, 12]],

        [[13, 14, 15, 16],
         [17, 18, 19, 20],
         [21, 22, 23, 24]]]])
tf.shape(t).eval() # 제일 안쪽이 제일 뒷쪽. 안쪽부터 세기 (1, 2, 3, 4)

  • 축... rank =4 이므로 4개의 축이 있다.
    • 맨안쪽 [1,2,3,4]의 axis=3 (또는 -1) (0부터 시작하므로)
    • 1, 5, 9 방향이 axis=2
  • Matmul 과 multiply는 완전히 다른 개념. 주의할 것
    • 그냥 곱을 할 경우, broadcasting이 적용됨.
  • Broadcasting
    • shape가 다른 행렬에도 4칙연산이 가능하도록 확장시켜주는 것
    • 편리하지만, 잘못된 연산이 발생할 우려가 있음.

matrix1 = tf.constant([[1,2]])
matrix2 = tf.constant(3)
(matrix1+matrix2).eval()  # 3이 [3,3]으로 취급하여, [4,5]가 됨

  • Reduce mean

x = [[1., 2.],   [3,4]]
tf.reduce_mean(x).eval()   # 값 전체의 평균 : 2.5
tf.reduce_mean(x, axis=0).eval() # 세로방향 array([2., 3.])
tf.reduce_mean(x, axis=1).eval() # 가로방향 array([1.5, 3.5])

  • Reduce sum

tf.reduce_sum(x, axis=0).eval() # array([4,6], dtype=float32)
tf.reduce_mean(tf.reduce_sum(x, axis=-1)).eval() # [3, 7] -> 5.0

  • Argmax

x = [[ 0, 1, 2],
      [ 2. 1, 0]]
tf.argmax(x, axis=0).eval() # array([1, 0, 0])
tf.argmax(x, axis=1).eval() # array([2, 0])

  • Reshape ***

t = np.array([[[0, 1, 2],
                  [3, 4, 5]],
                 [[6, 7, 8],
                  [9,10,11]]])
t.shape # (2,2,3)
tf.reshape(t, shape=[-1,3]).eval()
tf.reshape(t, shape=[-1,1,3])eval()

  • Reshape(squeeze, expand)

tf.squeeze([[0], [1], [2]]).eval()   #array([0,1,2])
tf.expand_dims([0,1,2], 1).eval()  #array([[0], [1], [2]])

  • One hot

t=tf.one_hot([[0], [1], [2], [0]] , depth=3).eval() # array ([[[1,0,0]], [[0,1,0]], [[0,0,1]], [[1,0,0]]]) 
tf.reshape(t, shape=[-1,3]).eval() # array([[1,0,0], [0,1,0], [0,0,1], [1,0,0]]) 

  • Type Casting 

tf.cast([1.9, 2.2, 3.3, 4.9], tf.int32).eval()   # array ([1,2,3,4])
tf.cast([True, False, 1==1, 1==0], tf.int32).eval()   # array([1, 0, 1, 0])

  • Stack

x=[1,4]
y=[2,5]
z=[3,6]
tf.stack([x,y,z]).eval()   #array([[1,4], [2,5], [3,6]])
tf.stack([x,y,z], axis=1).eval()   #array([1,2,3], [4,5,6]])

  • Ones and Zeros like

x=[[0,1,2], [2,1,0]
tf.ones_like(x).eval()    #array([[1,1,1], [1,1,1]])
tf.zeros_like(x).eval()   #array([[0,0,0], [0,0,0]])

  • Zip

for x,y in zip([1,2,3], [4,5,6]) :
    print(x,y)                      # 1 4 / 2 5 / 3 6 으로 출력됨
for x,y,z in zip([1,2,3], [4,5,6], [7,8,9]) :
    print(x,y,z)                    # 1 4 7 / 2 5 8 / 3 6 9 로 출력됨


Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02017. 11. 19. 00:30

Lec 07-1 학습 rate, Overfitting, 일반화(Regularization)

https://www.youtube.com/watch?v=1jPjVoDV_uo

  • Learning_rate : 이제까지는 임의의 값을 사용했음
    • 이 값을 크게 할 경우, 진동하거나 발산(overshooting)할 수 있음.
    • 아주 작은 값을 사용할 경우, 시간이 너무 많이 걸리고, local minimum에서 정지
    • 어떤 값이 좋은가는 특별한 법칙은 없다. 0.01로 시작하고, 나오는 cost 값에 따라서 줄이거나 늘리는 방법을 사용하면 된다.

  • Data(X)의 전처리. (Gradient descent용)
    • 아래와 같이 x1, x2의 범위가 차이가 크면, 왜곡된 형태가 되어 데이터 처리가 힘들 수 있다.

    • 이 경우, 아래와 같이 중심을 원점에 일치시키거나(zero-centered), 각변수가 차지하는 범위가 비슷하도록(normalize) 해준다.

  • 표준화(Standardization) 방법

$$ x_j^\prime = \frac{x_j - \mu_j}{\sigma_j} $$

    • python code : X_std[:,0] = (X[:,0] -X[:,0].mean() / X[:,0].std()
  • Overfitting
    • 학습데이터에는 정말 잘 맞지만, 실제 데이터로는 잘 안맞는 경우. 예를 들어 아래그림에서 모델2는 학습데이터에서는 100%이지만 실 데이터에서는 문제가 생길 수도 있음.

    • Overfitting을 줄이는 방법 
      • 학습데이터를 늘려라
      • feature의 수를 줄여라
      • Regularization (일반화)
        • Weight를 큰 숫자를 사용하지 말라 (구부리지 말라.) 아래와 같이 Cost function 에 $ \lambda \sum W^2 $를 추가하여 Weight 항이 작아질 수록 Cost가 작아지도록 하는 방법을 사용한다. 이때, $ \lambda $ 는 Regularization Strenth라고 하여, 작은 값을 사용하면 일반화를 중요하지 않게 생각한다는 의미이다.

        • l2reg = 0.001 * tf.reduce_sum(tf.square(W) 를 cost 함수에 추가한다

Lec 07-2 Training/Testing 데이터셋

https://www.youtube.com/watch?v=KVv1nMSlPzY

  • 머신러닝의 성능 평가방법
    • training set을 사용하여 평가하는 방법? - 거의 100%에 가까울 것임.
    • 70%를 training set으로 하여 학습하여 모델을 만들고, 남은 30%를(test set) 사용하여 평가해야
    • 경우에 따라선 데이터셋을 Training/Validation/Testing 세트로 구분하여 사용.
      • Validation set는 $\alpha, \lambda $를 평가하는 데 사용

  • Online Learning : training set가 너무 많아서 한꺼번에 처리할 수 없을 때.
    • 큰 데이터를 일정갯수로 잘라서 학습시킴. 
    • 나중에 새로운 데이터가 추가되더라고 갱신만 하면 되는 잇점.
  • 정확도 측정
    • 실제 $Y$ 값과, $ \bar Y$ 를 비교
    • 이미지 인식 분야는 95%-99% 수준에 달함.

Lab 07-1 training/test dataset, learning rate, normalization

https://www.youtube.com/watch?v=oSJfejG2C3w

x_data = [[1, 2, 1],[1, 3, 2],[1, 3, 4],[1, 5, 5],[1, 7, 5],[1, 2, 5],[1, 6, 6],[1, 7, 7]]
y_data = [[0, 0, 1],[0, 0, 1],[0, 0, 1],[0, 1, 0],[0, 1, 0],[0, 1, 0],[1, 0, 0],[1, 0, 0]]

# 학습데이터와 테스트 데이터를 따로 둔다.
x_test = [[2, 1, 1],[3, 1, 2],[3, 3, 4]]
y_test = [[0, 0, 1],[0, 0, 1],[0, 0, 1]]

X=tf.placeholder(tf.float32, [None, 3])
Y=tf.placeholder(tf.float32, [None, 3])
W=tf.Variable(tf.random_normal([3, 3]))
b =tf.Variable(tf.random_normal([3]))

hypothesis = tf.nn.softmax(tf.matmul(X,W) + b)
cost = tf.reduce_mean(-tf.reduce_sum(Y * tf.log(hypothesis), axis =1))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(cost)

#Correct prediction Test model
prediction = tf.argmax(hypothesis, 1)
is_correct = tf.equal(prediction, tf.arg_max(Y,1))
accuracy = tf.reduce_mean(tf.cast(is_correct, tf.float32))

# Launch graph
with tf.Session() as sess :
    sess.run(tf.global_variables_initializer())
    for step in range (201) :
        cost_val, W_val, _ = sess.run( [cost, W, optimizer], feed_dict ={X:x_data, Y: y_data})
        if (step % 1 == 0) :
            print(step, cost_val, W_val)
    print("Prediction : ", sess.run(prediction, feed_dict={X: x_test}))
    print("Accuracy : ", sess.run(accuracy, feed_dict={X: x_test, Y: y_test}))

Learning_rate의 문제. 

  • 위의 프로그램에서 learning_rate를 1.5로 주면 발산한다.
  • 위의 프로그램에서 learning rate를 1e-10으로주면 정지한다.

Non_normalized inputs

  • 아래 그림에서, xy의 3열은 다른 열에 비해 100배 이상이다. 이로 인해, 분포가 그 아래에 있는 것처럼 한쪽만 짜부라든 모양이된다.
  • 이러한 데이터를 그냥 돌려보면, 모델 학습이 안될 가능성이 높다. 밖으로 튀어나가기 십상이기 때문에

Normalized  inputs

  • 아래와 같이 MinMaxScaler 등을 이용해서 정규화시키면 분포가 일정해져서 결과가 잘 나온다.

Lab 07-2 Meet MNIST Dataset

https://www.youtube.com/watch?v=ktd5yrki_KA

  • MNIST 데이터셋이란 - 우편번호 자동 처리를 위해 만들어 놓은 손글씨 모음 데이터셋

  • 28*28 =784 픽셀. 


import tensorflow as tf
import matplotlib.pyplot as plt
import random

# Tensorflow에서 만들어둔 라이브러리
# 자세한 내용은 https://www.tensorflow.org/tutorials/layers
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

# 처음 실행하면 지정한 폴더에 데이터가 다운로드됨

nb_classes = 10

X=tf.placeholder(tf.float32, [None, 784]) # 28*28 이 여러개 있음.
Y=tf.placeholder(tf.float32, [None, nb_classes]) # one-hot 데이터. 클래스(nb_classes)는 10개
W=tf.Variable(tf.random_normal([784, nb_classes]))
b=tf.Variable(tf.random_normal([nb_classes]))

# hypothesis : softmax를 사용
hypothesis = tf.nn.softmax(tf.matmul(X, W) + b)

# cross entropy cost
cost = tf.reduce_mean(-tf.reduce_sum(Y * tf.log(hypothesis), axis=1))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(cost)

# 정확도 테스트
is_correct = tf.equal(tf.argmax(hypothesis, 1), tf.argmax(Y,1)) # one hot 값과 hypotheis 값 일치?
accuracy = tf.reduce_mean(tf.cast(is_correct, tf.float32))

# Training epoch/batch
# epoch란 전체 training 데이터셋을 한번 돈 것.
# batch size란 한번에 training 시키는 데이터의 크기. 클수록 메모리 소요가 높아짐
# 예를들어 training 데이터가 1000개 이고, batch size가 500 이면, 1 epoch를 완수하는데 2번의 반복
# 아래와 같이 학습하는 것이 일반적인 절차임

training_epochs = 15
batch_size=100

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for epoch in range(training_epochs): #15회
        avg_cost = 0
        total_batch = int(mnist.train.num_examples / batch_size)
        for i in range(total_batch):
            batch_xs, batch_ys = mnist.train.next_batch(100) # 100개씩 읽어들임.
            c, _ = sess.run([cost, optimizer], feed_dict={X:batch_xs, Y: batch_ys})
            avg_cost += c / total_batch
        print('Epoch : ', '%04d' % (epoch +1), 'cost =', '{:.9f}'.format(avg_cost))
    print("Accuracy: ", accuracy.eval(session= sess
        feed_dict = {X: mnist.test.images, Y: mnist.test.labels})) #학습에 사용하지 않은 데이터..
    #그림 그려보기
    #하나를 가져와서 예측해보자
    r=random.randint(0,mnist.test.num_examples -1)
    print("Label:", sess.run(tf.argmax(mnist.test.labels[r : r+1],1)))
    print("Prediction : ", sess.run(tf.argmax(hypothesis,1), feed_dict={X: mnist.test.images[r:r+1]}))
    plt.imshow(mnist.test.images[r:r+1].reshape(28,28), cmap='Greys', interpolation = 'nearest')
    plt.show()

실행결과

Epoch :  0001 cost = 2.890159705
Epoch :  0002 cost = 1.087193211
Epoch :  0003 cost = 0.857237154
Epoch :  0004 cost = 0.751001975
----
Epoch :  0014 cost = 0.475028615
Epoch :  0015 cost = 0.465113584
Accuracy:  0.8902

Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02017. 11. 17. 17:11

Lec 6-1 Softmax Regression 기본개념

https://www.youtube.com/watch?v=MFAnsx1y9ZI

  • 복습
    • H(x) = WX 와 같이 Linear Regression으로부터 출발한다. 그러나, 이런 $WX$ 형태의 단점은, 출력이 $-\infty \lt H_L(x) \lt~\infty$ 이므로, 0이냐 1이냐를 고르는 문제에서는 적합하지 않다.
    • 그래서 $z = H_L (X)$라고 놓고, 이 값을 0부터 1로 압축할 수 있는 $g(z)$ 함수를 사용하여 해결한다. 

    • 이에 가장 적합한 $g(x)$는 sigmoid라고 하는 $g(z) = \frac {1}{1+e^{-z}}$ 이다. 
    • 이를 적용했을 때의 Hypothesis는 $H_R (X) = g(H_L (X))$ 가 된다.
    • 수식이 많아지므로, 이를 그림으로 나타낸다. 박스에서 S로 그린 것은 Sigmoid 함수를 통과시킨다는 의미이다.

  • Logistic Regression의 의미는 변수가 $x_1, x_2$ 두개가 있다고 할 때, 아래와 같이 분리시키는 적절한 선을 찾는 것이다.

  • 이와 비슷한 아이디어를 Multimomial Classification에도 적용할 수 있다. 즉 아래와 같이 3개로 분류를 할때, A or not, B or not, C or not 과 같이 3개의 Logistic Regression을 적용하면 된다.

  • 가설은 기본적으로 $ \begin{bmatrix}w_1 &w_2 &w_3 \end{bmatrix} {\begin{bmatrix}x_1 &x_2 &x_3 \end{bmatrix} }^T = \begin{bmatrix}w_1 x_1 &w_2 x_2 &w_3 x_3 \end{bmatrix} $ 이다. Multinomial Classification은 세개의 Logistic Classification 의 결합이므로, 3개의 식이 있으면 된다.

  • 이를 하나의 식으로 합치면 아래와 같다.

$$ \begin{bmatrix}w_A1 &w_A2 &w_A3 \\ w_B1 &w_B2 &w_B3 \\ w_C1 &w_C2 &w_C3 \end{bmatrix}    {\begin{bmatrix}x_1 \\ x_2 \\ x_3 \end{bmatrix} } = \begin{bmatrix}w_A1 x_1 &w_A2 x_2 &w_A3 x_3 \\ w_B1 x_1 &w_B2 x_2 &w_B3 x_3 \\ w_C1 x_1 &w_C2 x_2 &w_C3 x_3 \end{bmatrix} =  \begin{bmatrix} \bar{y_A} = H_A (X) \\ \bar{y_B}  = H_B (X)\\ \bar{y_C}  = H_C (X) \end{bmatrix}  $$

  • 이제 $\bar{Y_A}$ $\bar{Y_B}$ $\bar{Y_C}$ 에 각각 sigmoid 함수를 적용하면 되지만...

Lec 6-2 Softmax Classifier의 cost 함수

https://www.youtube.com/watch?v=jMU9G5WEtBc

  • Logistic Classifier를 사용하면, 출력이 $ {\begin{bmatrix} 2.0 & 1.0 & 0.1 \end{bmatrix}}^T $ 와 같은 형태가 되는데, 이것보다 $ 0 \lt \bar{y} \lt 1 $ 이고, 그 값의 합이 1이 되는 (확률처럼) 되는 것이 좋다. 이것이 Softmax 함수이다.

  • Softmax 함수 : $$ S(y_i ) = \frac {e^{y_i}}{\displaystyle \sum_{j}^{} e^{y_j}} $$
  • 적용방법 : $ \bar y $에 소프트맥스를 적용한 $ S(y) $ 하면 확률이 되는데, 여기에 "One-Hot encoding"을 적용하여 (Tensorflow에서는 argmax) 하나를 선택한다. 

  • Cost 함수...는 Cross-Entropy 함수 : $ \displaystyle - \sum_{i} L_i \log(S_i ) $를 사용함.

  • 이 함수가 적절한 함수인가? $\displaystyle  -\sum_{i} L_i \log(S_i ) = \sum_{i} (L_i ) * ( -\log (\bar {y_i}) ) $ 에서 맨 오른쪽은 예전에 본 것처럼, $\bar {y_i}$가 1일때는 0이 되고,  $\bar {y_i}$가 0이면 매우 큰수가 된다.
  • 이야기를 간단하기 위해, $Y=L= (\begin{bmatrix} 0, 1 \end{bmatrix})^T $ 와 같이 A,B 둘중 어느것인지를 고르는 문제라고 하자. (이 경우엔 실측이 B임) 
    •  $\bar{Y}= (\begin{bmatrix} 0, 1 \end{bmatrix})^T $ 로 예측된 경우(예측이 맞음)
      • $\begin{bmatrix} 0\\ 1 \end{bmatrix} \bigodot -\log \begin{bmatrix} 0\\ 1 \end{bmatrix} = \begin{bmatrix} 0\\ 1 \end{bmatrix} \bigodot \begin{bmatrix} \infty\\ 0 \end{bmatrix} = 0$ 이 된다. cost가 작으므로 OK.
    •  $\bar{Y}= (\begin{bmatrix} 1, 0 \end{bmatrix})^T $ 로 예측된 경우(예측이 틀림)
      • $\begin{bmatrix} 0\\ 1 \end{bmatrix} \bigodot -\log \begin{bmatrix} 1\\ 0 \end{bmatrix} = \begin{bmatrix} 0\\ 1 \end{bmatrix} \bigodot \begin{bmatrix} 0 \\ \infty \end{bmatrix} = \infty $ 이 된다. cost가 크므로 OK.
    • $Y=L= (\begin{bmatrix} 1, 0 \end{bmatrix})^T $ 일 경우에도 마찬가지임. 

  • Losistic의 cost 함수와 Cross-entropy 함수가 모양으로는 달라보이지만, 실제로는 동등함.

  • 여러개의 training set이 있을 때 cost 함수는...전체의 거리를 구한뒤 합하여 평균하면 된다.

$$  L = {1 \over N} \displaystyle \sum_{i} D( S (W X_i + b) , L_i ) $$

  • Gradient descent 를 사용함. (cost 함수가 concave 하므로) 미분 $ - \alpha \Delta L (w_i , w_w )$ 은 구하지 않는다.

Lab 06-1 TensorFlow로 Softmax Classification 구현하기

https://www.youtube.com/watch?v=VRnubDzIy3A

  • Cost function 을 구현하려면..  $ Y \log( \bar Y ) $를 사용하면 됨.
  • Cost 최소화는 동일.

import tensorflow as tf
x_data = [[1,2,1,1], [2,1,3,2], [3,1,3,4], [4,1,5,5], [1,7,5,5], [1,2,5,6], [1,6,6,6], [1,7,7,7]]
y_data = [[0,0,1], [0,0,1], [0,0,1], [0,1,0], [0,1,0], [0,1,0], [1,0,0], [1,0,0]]

X= tf.placeholder("float", [None, 4])
Y= tf.placeholder("float", [None, 3])
nb_classes=3

W = tf.Variable(tf.random_normal([4, nb_classes]), name = 'weight')
b = tf.Variable(tf.random_normal([nb_classes]), name = 'bias')

# tf.nn.softmax computes softmax activations
# softmax = exp(Logits) / reduce_sum(exp(Logits), dim)
hypothesis = tf.nn.softmax(tf.matmul(X, W) + b)

# cross entropy cost
cost = tf.reduce_mean(-tf.reduce_sum(Y * tf.log(hypothesis), axis=1))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(cost)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for step in range(2001):
        sess.run(optimizer, feed_dict = {X:x_data, Y:y_data})
        if step % 200 ==0:
            print(step, sess.run(cost, feed_dict = {X:x_data, Y:y_data}))
    a = sess.run(hypothesis, feed_dict={X:[[1,11,7,9], [1,3,4,3], [1,1,0,1]] })
    print(a, sess.run(tf.argmax(a,1))) #arg_max is deprecated.

#[[  4.16852683e-02   9.58304107e-01   1.06291027e-05]
# [  6.28286779e-01   3.29489440e-01   4.22237590e-02]
# [  1.50573225e-08   3.95991723e-04   9.99604046e-01]] [1 0 2]

Lab 06-2 TensorFlow로 Fancy Softmax Classification 구현하기

https://www.youtube.com/watch?v=E-io76NlsqA

  • 복습 : Softmax 구현방법
    • 다음과 같은 형태로 적용하였음
      • hypothesis = tf.nn.softmax(tf.matmul(X, W) + b)
        cost = tf.reduce_mean(-tf.reduce_sum(Y* tf.log(hypothesis), axis =1))

  • softmax_cross_entropy_with_logits 을 사용하는 방법
    • cost = tf.reduce_mean(-tf.reduce_sum(Y* tf.log(hypothesis), axis =1)) 대신으로 간단하게 사용하여 깔끔하게 다음처럼 사용 (여기에서 Y는 one_hot이어야 함)
    • logits = tf.matmul(X,W) +b       이라고 정의하고 이를 사용하여 처리함.
      hypothesis = tf.nn.softmax(logits)

      cost_i = tf.nn.softmax_cross_entropy_with_logits(logits = logits, labels = Y_one_hot)
      cost = tf.reduce_mean(cost_i)
  • 예제 : 동물의 분류
    • 표에서 마지막 열은 분류(0-6), 나머지는 특성(다리의 수, 털의 여부, 알을 낳는지 여부 등등..)

    • 읽어보는 방법은 동일
      • xy = np.loadtxt('data-04-zoo.csv', delimiter=',', dtype=np.float32)
        x_data = xy[:, 0:-1]
        y_data = xy[:, {-1]]
    • Y data에 대해서 알아보기
      • Y= tf.placeholder("tf.int32", [None, 1])    # Y의 column 수는 1임. 그런데, 파일에서 읽은 데이터는 $ {\begin{bmatrix} 0, 3, 0, 0, ..., 5 \end{bmatrix}}^T $ 으로서, 우리가 원하는 one_hot 데이터가 아님.
      • Y_one_hot = tf.one_hot(Y, nb_classes)     # nb_classes=7 (0부터 6까지). 그런데 이렇게 실행시키면 에러가 발생. tf.one_hot은 입력의 rank가 N 이면, 출력의 rank가 N+1이 된다. 
        • 예를 들어 data가  $ \begin{bmatrix} 0, 3 \end{bmatrix} $ 이라고 하면(shape는 none,1) ...  one_hot의 출력은  $ \begin{bmatrix} \begin{bmatrix} \begin{bmatrix} 1 0 0 0 0 0 0 \end{bmatrix} \end{bmatrix} \begin{bmatrix} \begin{bmatrix} 0 0 0 1 0 0 0 \end{bmatrix} \end{bmatrix} \end{bmatrix} $ (Shape는 [none, 1, 7]) 이 된다. 
        • 그래서 reshape를 통해 Shape가 [none, 7]인 형태, 즉, $ \begin{bmatrix} \begin{bmatrix} 1 0 0 0 0 0 0 \end{bmatrix} \begin{bmatrix} 0 0 0 1 0 0 0 \end{bmatrix} \end{bmatrix} $ 로 바꿔주어야 한다.
      • Y_one_hot = tf.reshape(Y_one_hot, [-1, nb_classes])

import tensorflow as tf
import numpy as np

xy = np.loadtxt('data-04-zoo.csv', delimiter=',', dtype=np.float32)
x_data = xy[:, 0:-1]
y_data = xy[:, [-1]]

nb_classes =7
X= tf.placeholder(tf.float32, [None, 16])
Y= tf.placeholder(tf.int32, [None, 1])
Y_one_hot = tf.one_hot(Y, nb_classes)        # one_hot 으로 바꿔줌.
Y_one_hot = tf.reshape(Y_one_hot, [-1, nb_classes])

W = tf.Variable(tf.random_normal([16, nb_classes]), name = 'weight')
b = tf.Variable(tf.random_normal([nb_classes]), name = 'bias')

logits = tf.matmul(X, W) +b
hypothesis = tf.nn.softmax(logits)

cost_i = tf.nn.softmax_cross_entropy_with_logits(logits = logits, labels = Y_one_hot)
cost = tf.reduce_mean(cost_i)

optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(cost)

prediction = tf.argmax(hypothesis, 1)            # 예측한 값
correct_prediction = tf.equal(prediction, tf.argmax(Y_one_hot, 1)) #원래의 값
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for step in range(2001):
        sess.run(optimizer, feed_dict = {X:x_data, Y:y_data})
        if step % 200 ==0:
            loss, acc = sess.run([cost, accuracy], feed_dict = {X:x_data, Y:y_data})
            print("Step: {:5}\tLostt: {:.3f}\tAcc: {:.2%}".format(step, loss, acc))
    pred = sess.run(prediction, feed_dict= {X: x_data})
    for p, y in zip(pred, y_data.flatten()) :
        print("[{}] Prediction : {} True Y: {}".format(p == int(y), p, int(y)))


Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02017. 11. 16. 23:08

Lec 05-1 - Logistic Classification의 가설함수 정의

https://www.youtube.com/watch?v=PIjno6paszY

  • Neural network과 관계가 깊음.
  • Binary Classification은 두가지 범주로 나누는 것 -> 0, 1 encoding
    • Spam or Ham
    • Show or Hide
    • 주식 Buy/Sell
  • Linear Regression으로 가능한가?
    • 예를 들어 0.5 정도 이하면 Fail로 두면 될텐데, 50과 같은 값으로 인해, (대칭이 이루어지지 않아) 합격/불합격 선이 바뀌게 될 수 있다.
    • 또한 출력이 0 이하나 1 이상으로 나올 수 있다.... 별로 좋지 않다.

  • 그래서 Logistic Hypothesis 가 필요. (출력 범위가 0에서 1까지)
    • 아래와 같은 logistic(sigmod) 함수를 사용하면 됨.
      • $$ g(z) = \frac{1}{\left(1+e^{-z} \right)} $$
      • 어떠한 z에 대해서도 0 < g(z) <1 가되는 특성이 있음.

Lec 5-2 Logistic Regression의 cost 함수

https://www.youtube.com/watch?v=6vzchGYEJBc

  • 이 Sigmoid 함수에 대한 cost 함수는 오른쪽과 같이 local 극소점이 많은, 울퉁불퉁한 형태이다.
    • $$ cost(W,b) = {1 \over m} \sum_{i=1}^m \left( H ( x^{(i)} ) - y^{(i)} \right)^2$$
    • 따라서, 이러한 cost 함수를 사용할 수 없다.
  • cost 함수는... 실제값과 예측값이 같으면 cost값이 작아지고, 다르면 cost가 커져야 한다. 그래서 다음과 같은 cost 함수를 사용한다.

$$\begin{matrix}cost(W) = {1 \over m} \sum c(H(x), y) \\
   (H(x), y) = \begin{cases} -log(H(x) &: y=1\\ -log(1-H(x)) &: y=0 \end{cases} \end{matrix} $$

  • 이 cost 함수는 다음과 같은 특성이 있다. 
    • y=1 이고, H(x)=1 일때... 즉 예측이 맞으면 cost(1) => 0
    • y=1 이고, H(x)= 0 이면...즉 예측이 틀리면 cost(0) => 엄청커짐.
    • y=0 이고, H(x)=0 이면... 즉 예측이 맞으면 cost(0) => 0
    • y=1 이고, H(x)=1 이면... 즉 예측이 틀리면 cost(0) => 엄청커짐.
    • 이 cost 함수도 오목한 형태여서, GradientDescent 알고리듬을 적용할 수 있다.

  • 결론 : cost 함수는 아래와 같다.
    • 맨 아래식에서 y=1 이면 앞의 항만 남고, y=0 이면 위의 항만 남아서 결론적으로 중간에 있는 식과 동일해진다.

$$ \begin{matrix} cost(W) &=& {1 \over m} \sum c(H(x), y) \\
C(H(x), y) &=& {\begin{cases} -log(H(x)) &: y=1\\ -log(1-H(x)) &: y=0\end{cases}} \\
C(H(x), y) &=& -y log(H(x)) - (1-y) log (1-H(x)) \end{matrix}$$

  • Gradient descent algorithm 적용
    • 미분이 필요하지만 생략. 아래와 같이 적용만 하면 됨.

Lab 05 : TensorFlow로 Logistic Classification을 구현하기

https://www.youtube.com/watch?v=2FeWGgnyLSw

$$\begin{matrix} Hypothesis &:& H(x) = \frac{1}{1+e^{-W^T X}} \\
Cost &:& - cost(W) = {1 \over m} \sum \left[ y log (H(x)) + (1-y) (log (1- H(x)) \right] \\
Gradient &:& W := W - \alpha {\partial \over {\partial W}} cost (W) \end{matrix}$$

예제 돌려보기.

import tensorflow as tf
tf.set_random_seed(777)

x_data = [[1,2], [2,3], [3,1], [4,3], [5,3], [6,2]]
y_data =[[0], [0], [0], [1], [1], [1]]   # output 출력이 0/1, true/false 등이라는 것이 중요함. 

X = tf.placeholder(tf.float32, shape = [None, 8])
Y = tf.placeholder(tf.float32, shape = [None, 1])

W = tf.Variable(tf.random_normal([8,1]), name = 'weight') # X,Y의 숫자와 동일
b = tf.Variable(tf.random_normal([1]), name = 'bias') #항상 나가는 숫자와 동일

hypothesis = tf.sigmoid(tf.matmul(X,W) + b) # tf.div(1., 1. + tf.exp(tf.matmul(X, W) +b)) 라고 해도 됨.
cost = -tf.reduce_mean( Y * tf.log(hypothesis) + (1- Y) * tf.log(1- hypothesis)) # 식을 옮긴 것임.
train = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(cost)

# hypothesis는 0과 1사이의 실수로 나옴. 이것을 0/1로 바꿔줌
predicted = tf.cast(hypothesis > 0.5, dtype = tf.float32)
accuracy = tf.reduce_mean(tf.cast(tf.equal(predicted, Y), dtype=tf.float32))

sess =tf.Session()
sess.run(tf.global_variables_initializer())
for step in range(10001) :
    cost_val, _ = sess.run([cost, train], feed_dict={X:x_data, Y:y_data})
    if step % 200 == 0:
        print(step, cost_val)

h, c, a = sess.run([hypothesis, predicted, accuracy], feed_dict={X:x_data, Y:y_data})
print("\nHypothesis: \n", h, "\nCorrect (Y): \n", c, "\nAccuracy: ", a)

파일에서 불러올 때

import tensorflow as tf
import numpy as np

tf.set_random_seed(777)

xy = np.loadtxt('data-03-diabetes.csv', delimiter=',', dtype=np.float32)
x_data = xy[:, 0:-1]
y_data = xy[:, [-1]]

X = tf.placeholder(tf.float32, shape = [None, 8])
Y = tf.placeholder(tf.float32, shape = [None, 1])

W = tf.Variable(tf.random_normal([8,1]), name = 'weight') # X,Y의 숫자와 동일
b = tf.Variable(tf.random_normal([1]), name = 'bias') #항상 나가는 숫자와 동일

hypothesis = tf.sigmoid(tf.matmul(X,W) + b) # tf.div(1., 1. + tf.exp(tf.matmul(X, W) +b)) 라고 해도 됨.
cost = -tf.reduce_mean( Y * tf.log(hypothesis) + (1- Y) * tf.log(1- hypothesis)) # 식을 옮긴 것임.
train = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(cost)

# hypothesis는 0과 1사이의 실수로 나옴. 이것을 0/1로 바꿔줌
predicted = tf.cast(hypothesis > 0.5, dtype = tf.float32)
accuracy = tf.reduce_mean(tf.cast(tf.equal(predicted, Y), dtype=tf.float32))

sess =tf.Session()
sess.run(tf.global_variables_initializer())
for step in range(10001) :
    cost_val, _ = sess.run([cost, train], feed_dict={X:x_data, Y:y_data})
    if step % 200 == 0:
        print(step, cost_val)

h, c, a = sess.run([hypothesis, predicted, accuracy], feed_dict={X:x_data, Y:y_data})
print("\nHypothesis: \n", h, "\nCorrect (Y): \n", c, "\nAccuracy: ", a)


data-03-diabetes.csv

-0.294118,0.487437,0.180328,-0.292929,0,0.00149028,-0.53117,-0.0333333,0
-0.882353,-0.145729,0.0819672,-0.414141,0,-0.207153,-0.766866,-0.666667,1
-0.0588235,0.839196,0.0491803,0,0,-0.305514,-0.492741,-0.633333,0
-0.882353,-0.105528,0.0819672,-0.535354,-0.777778,-0.162444,-0.923997,0,1


더 많은 데이터로 테스트 하고 싶을 경우, https://www.kaggle.com 을 가볼 것.

Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02017. 11. 16. 12:03

Lec 04 - 다변수(Multi-variable) Linear Regression

https://www.youtube.com/watch?v=kPxpJY6fRkY

  • 복습
    • 선형 회귀분석을 위해서는 1) 가설(Hypothesis)를 세우고, 2) 비용(Cost/Loss) 함수를 만든 뒤, 3) Gradient descent 알고리듬을 적용한다.
    • 비용함수를 결정하고, 이를 최소로 줄이는 W, b를 찾는 것이 학습을 시키는 과정이다.
    • 단변수 회귀분석에서는, X=[x1, x2, .... , xn],  Y=[y1, y2, ... , yn] 의 형태가 됨.
  • 다변수 회귀분석은
    • X=[[x11, x12, .... , x1m],[x21, x22, .... , x2m], ..., [xn1, xn2, .... , xnm]], Y=[y1, y2, ... , yn] 형태가 됨.

  • 가설(Hypothesis)의 행렬 표현

  • Instance 가 여러개 있을 경우에도 행렬 표현은 동일

Lab 04-1 다변수 Linear Regression

https://www.youtube.com/watch?v=fZUV3xjoZSM

  • 행렬을 사용하지 않을때의 코드

import tensorflow as tf

x1_data = [73., 93., 89., 96., 73.]
x2_data = [80., 88., 91., 98., 66.]
x3_data = [75., 93., 90., 100., 70.]
y_data = [152., 185., 180., 196., 142.]

# placeholders for a tensor that will be always fed.
x1 = tf.placeholder(tf.float32)
x2 = tf.placeholder(tf.float32)
x3 = tf.placeholder(tf.float32)
Y = tf.placeholder(tf.float32)

w1 = tf.Variable(tf.random_normal([1]), name='weight1')
w2 = tf.Variable(tf.random_normal([1]), name='weight2')
w3 = tf.Variable(tf.random_normal([1]), name='weight3')
b = tf.Variable(tf.random_normal([1]), name='bias')

hypothesis = x1 * w1 + x2 * w2 + x3 * w3 + b
cost = tf.reduce_mean(tf.square(hypothesis - Y))

# Minimize. Need a very small learning rate for this data set
optimizer = tf.train.GradientDescentOptimizer(learning_rate=1e-5)
train = optimizer.minimize(cost)

sess = tf.Session()
sess.run(tf.global_variables_initializer())

#very long routine. because it does not converge well
for step in range(500001):
    cost_val, hy_val, _ = sess.run([cost, hypothesis, train],
                                   feed_dict={x1: x1_data, x2: x2_data, x3: x3_data, Y: y_data})
    if step % 10000 == 0:
        print(step, "Cost: ", cost_val, "\nPrediction:\n", hy_val)

  • 행렬을 사용할 때의 코드

import tensorflow as tf

x_data = [[73., 80., 75.],
             [93., 88., 93.],
             [89., 91., 90.],
             [96., 98., 100.],
             [73., 76., 70.]]

y_data = [[152.], [185.], [180.], [196.], [142.]]

X = tf.placeholder(tf.float32, shape=[None, 3])    #None 이란 n, 즉, 임의로 바뀔 수 있다는 뜻.
Y = tf.placeholder(tf.float32, shape=[None, 1])

W = tf.Variable(tf.random_normal([3,1]), name='weight')
b = tf.Variable(tf.random_normal([1]), name='bias')

hypothesis = tf.matmul(X, W) + b
cost = tf.reduce_mean(tf.square(hypothesis - Y))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=1e-5)
train = optimizer.minimize(cost)

sess = tf.Session()
sess.run(tf.global_variables_initializer())

for step in range(500001) :
    cost_val, hy_val, _ = sess.run([cost, hypothesis, train],
                    feed_dict={X: x_data, Y: y_data})
    if step %10000 == 0 :
        print(step, "Cost : ", cost_val, "\nPrediction :\n", hy_val)

Lab 4-2, 파일에서 데이터 불러오기

https://www.youtube.com/watch?v=o2q4QNnoShY

  • 파일에 데이터를 작성하고 읽어서 처리.

import tensorflow as tf
import numpy as np

tf.set_random_seed(777)

xy = np.loadtxt('data-01-test-score.csv', delimiter=',', dtype=np.float32)
x_data = xy[:, 0:-1]
y_data = xy[:, [-1]]

X = tf.placeholder(tf.float32, shape=[None, 3])    #None 이란 n, 즉, 임의로 바뀔 수 있다는 뜻.
Y = tf.placeholder(tf.float32, shape=[None, 1])

W = tf.Variable(tf.random_normal([3,1]), name='weight')
b = tf.Variable(tf.random_normal([1]), name='bias')

hypothesis = tf.matmul(X, W) + b
cost = tf.reduce_mean(tf.square(hypothesis - Y))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=1e-5)
train = optimizer.minimize(cost)

sess = tf.Session()
sess.run(tf.global_variables_initializer())

for step in range(100001) :
    cost_val, hy_val, _ = sess.run([cost, hypothesis, train],
                    feed_dict={X: x_data, Y: y_data})
    if step %10000 == 0 :
        print(step, "Cost : ", cost_val, "\nPrediction :\n", hy_val)

# Ask my score
print ("Your score will be ", sess.run(hypothesis, feed_dict={X: [[100, 70, 101]]}))
print ("Our score will be ", sess.run(hypothesis, feed_dict={X: [[60, 70, 110], [90, 100, 80]]}))

  • Queue Runners : 파일이 아주 커서 한꺼번에 돌리기 힘들 때 사용하는 방법
    • A,B,C 와 같은 여러개의 파일을 읽어올 수 있다.
    • 이 파일이름들을 Queue에 쌓는다.
    • Reader 로 연결해서, 디코딩하여 Queue에 쌓는다.
    • 이 Queue에서 부분씩 잘라내어 학습을 시킨다. 
    • 이 과정은 Tensorflow가 책임을 진다.

  • 사용법은 간단. 세가지 단계
    1. 파일 이름들을 나열함으로써, filename_queue 를 만든다.
    2. Reader를 연결한다.
    3. 디코딩 한다. (여기에서는 csv 이므로... decode_csv. (default 값을 정해줌.

  • 그다음에 배치로 넘겨줌
    • x_data, y_data 대신에 x_batch, y_batch로 만들어 넘겨주고
    • coord 있는 부분은 그냥 쓴다고 생각하면 됨.

import tensorflow as tf

filename_queue = tf.train.string_input_producer(
        ['data-01-test-score.csv'], shuffle = False, name = 'filename_queue')

reader = tf.TextLineReader()
key, value = reader.read(
filename_queue)

# column이 비어 있을 경우의 default 값. decoded 결과의 type도 정해줌
record_defaults = [[0.], [0.], [0.], [0.]]
xy = tf.decode_csv(value, record_defaults=record_defaults)

# csv 의 배치를 모음
train_x_batch, train_y_batch = tf.train.batch([xy[0:-1], xy[-1:]], batch_size=10)

#placeholder
X = tf.placeholder(tf.float32, shape=[None, 3])    #None 이란 n, 즉, 임의로 바뀔 수 있다는 뜻.
Y = tf.placeholder(tf.float32, shape=[None, 1])

W = tf.Variable(tf.random_normal([3,1]), name='weight')
b = tf.Variable(tf.random_normal([1]), name='bias')

hypothesis = tf.matmul(X, W) + b
cost = tf.reduce_mean(tf.square(hypothesis - Y))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=1e-5)
train = optimizer.minimize(cost)

sess = tf.Session()
sess.run(tf.global_variables_initializer())

#Start populating the filename queue
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)

for step in range(100001) :
    x_batch, y_batch = sess.run([train_x_batch, train_y_batch])
    cost_val, hy_val, _ = sess.run([cost, hypothesis, train],
                    feed_dict={X: x_batch, Y: y_batch})
    if step %10000 == 0 :
        print(step, "Cost : ", cost_val, "\nPrediction :\n", hy_val)

coord.request_stop()
coord.join(threads)

print ("Your score will be ", sess.run(hypothesis, feed_dict={X: [[100, 70, 101]]}))
print ("Our score will be ", sess.run(hypothesis, feed_dict={X: [[60, 70, 110], [90, 100, 80]]}))

data-01-test-score.csv

73,80,75,152
93,88,93,185
89,91,90,180
96,98,100,196
73,66,70,142
53,46,55,101
69,74,77,149
47,56,60,115
87,79,90,175
79,70,88,164
69,70,73,141
70,65,74,141
93,95,91,184
79,80,73,152
70,73,78,148
93,89,96,192
78,75,68,147
81,90,93,183
88,92,86,177
78,83,77,159
82,86,90,177
86,82,89,175
78,83,85,175
76,83,71,149
96,93,95,192


Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02017. 11. 15. 21:09

Lec 03 - Linear Regression 의 cost 최소화 알고리듬의 원리

https://www.youtube.com/watch?v=TxIVr-nk1so

  • 복습 : 선형회귀분석 모델의 가설(Hypothesis)과 비용함수(Cost function)
  • 설명을 위해 H(x) = W(x)로 두고 진행
    • W=1 일때의 cost(W)는?
        • cost(W) = 1/3( (1x1 -1)^2 + (1x2 - 2)^2 + (1x3 -3)^2 ) =0
    • W=0 일때의 cost?
        • cost(W) = 1/3( (0x1 -1)^2 + (0x2 -2)^2 + (0x3 -3)^2 ) = 1/3 (1+4+9) = 4.67
    • W=2 일때... cost = 4.67... 많은 값에 대해 cost()의 그래프를 그리면

  • 널리 사용되는 알고리듬이 Gradient descent 알고리듬. (경사를 따라 내려가는 알고리듬)
    • cost 함수 최소화에 사용
    • 많은 minimization 문제에서 사용됨
    • 주어진 cost 함수 cost(W,b)에 대해, 이를 최소화시키는 W, b를 찾는 것.
    • 비용함수의 변수가 많은 일반적 경우 cost(w1, w2, ... wn) 에도 적용할 수 있다.
  • 이 알고리듬은 초기값이 무엇이든 수렴하는 장점이 있음.
  • 기울기는 편미분으로 구함
    • 즉, 한번 반복할 때마다, 아래와 같은 값으로 새로 바꿔 넣어줌. (여기에서 alpha 는 running rate)
    • 아래 그림에서 맨 아래에 있는 것이 Gradient Descent Algorithm

  • 비용함수가 아래와 같다면, 초기값에 따라 다른 해가 구해진다.

  • 하지만, Linear Regression 의 경우, cost 함수가 convex 이기때문에 초기값에 관계없이 해를 구할 수 있다.

  • Cost function을 설계할 때, convex 인지를 반드시 확인해야 한다. 확인할 수만 있다면 편하게 GDA를 사용할 수 있다.

Lab 03 - Linear Regression의 비용함수 최소화를 TensorFlow로 구현하기

  • 이번에 사용한 Hypothesis
    • $H(x) = W \cdot x \\
      cost(W) = {1 \over m} \sum_{i=1}^m (Wx^{(i)} - y^{(i)} )^2 $
  • 먼저 cost 함수를 그려보자.

import tensorflow as tf
import matplotlib.pyplot as plt

X = [1, 2, 3]
Y = [1, 2, 3]

#W 를 변경시켜가면서 확인
W = tf.placeholder(tf.float32)

# H(x) = W.x 로 둔 상태임
hypothesis = X * W
cost = tf.reduce_mean(tf.square(hypothesis - Y))

#세션 시작
sess = tf.Session()
sess.run(tf.global_variables_initializer())

#cost function을 그리기 위한 변수
W_val =[]
cost_val =[]

for i in range(-30,50) :
    feed_W = i * 0.1
    curr_cost, curr_W = sess.run([cost, W], feed_dict = {W : feed_W})
    W_val.append(curr_W)
    cost_val.append(curr_cost)

# cost 함수를그리기
plt.plot(W_val, cost_val)
plt.show()

  • 그 결과는 아래와 같음 W=1 일때 cost가 최소가 된다. 즉,"경사면따라 내려가기" 알고리듬을 적용하기 좋은 모양.

  • Gradient Descent를 자세히 살펴보자.
    • 수식 : $ W := W - \alpha {1 \over m} \sum_{i=1}^m ( W x^{(i)} - y^{(i)} ) x^{(i)} $

learning_rate = 0.1                               # $ \alpha $
gradient = tf.reduce_mean((W*X - Y) *X )  # cost 함수의 미분 : $ {1 \over m} \sum_{i=1}^m ( W x^{(i)} - y^{(i)} ) x^{(i)} $
descent = W - learning_rate * gradient
update = W.assign(descent)                   # tf는 직접 = 로 대입할 수 없어, assign을 사용

  • 아래는 Gradient Descent를 수동으로 갱신시키는 방법임.
    • learning_rate = 0.1 부터 4줄이 해당부분임.

                 

위의 GradientDescent는 간단하게 미분가능하지만, 그렇지 않은 것들도 많다. 그냥 Optimizer를 사용하면 미분하지 않고서도 해결해준다. 즉, 아래는 위의 식과 동일

optimizer = tf.train.GradientDescentOptimizer(learning_rate = 0.1)
train = optimizer.minimize(cost)

  • Optional.... 계산된 Gradient를 "약간" 변경시킨 뒤 다시 적용시키는 방법...
    • optimizer.compute_gradients()
    • optimizer.apply_gradients()
  • 오른쪽 결과에서 2,3 번째 값과, 네번째 값이 동일함을 알 수 있다.


Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02017. 11. 15. 12:46

Lec 02 - Linear Regression의 가설(Hypothesis)과 비용(cost) 설명

https://www.youtube.com/watch?v=Hax03rCn3UI

  • 시험성적 예측 (supervised learning) 선형 회귀분석
    • x(hours), y(score) ->[[10,90], [9,80], [3,50], [2,30]] 의 경우.
    • regression 모델로 training 시킴
    • (x,y) ->[[1,1], [2,2], [3,3]] 의 경우
    • 가설(Hypothesis) : linear regression.
      • 최적의 선을 찾는 것이 학습과정
  • 선형 회귀분석의 가설 : H(x) = Wx + b 에서, 가장 좋은 W와 b 를 찾아야 함.
    • 어떤 가설이 좋은지를 찾는다는 것은, 실제 데이터와, 가설 H(x)에 의한 점과의 거리가 가까울 수록 좋은 모델임. 
  • 이렇게 거리를 측정하는 것을 Cost Function, Loss Function 이라고 함. 대부분 두 값의 차이의 제곱을 구하게 됨

  •  Cost function 의 정의

    • 이 cost 함수는 W와 b 의 함수가 되는데, cost를 최소로 줄여주는 W, b를 찾는 것이 학습임.

Lab 02 TensorFlow로 간단한 linear regression을 구현하는 방법

  • TF 연산을 사용하여 그래프를 Build
    • Hypothesis

x_train = [1,2,3]
y_train = [1,2,3]

# tf의 Variable이란, TF가 t사용하는, 자체적으로 변경시키는, trainable 변수.
# [1]는 shape.
W = tf.Variable(tf.random_normal([1]), name = 'weight')
b = tf.Variable(tf.random_normal([1]), name = 'bias')

# 우리는 Linear Regression을 가정했으므로, W *x + b 가 hypothesis
hypothesis = x_train * W + b

    • Cost function

# reduce_mean 은 평균을 구하라는 연산
cost = tf.reduce_mean(tf.square(hypothesis - y_train)) 

    • GradientDescent : Minimize. 현재는 그냥 이렇게 쓴다고만 생각할 것.

# Minimize
optimizer = tf.train.GradientDescentOptimizer (learning_rate = 0.01)
train = optimizer.minimize(cost)

  • 그래프를 실행/갱신 한뒤, 결과를 출력

#  세션에서 그래프를 실행시킨다.
sess = tf.Session()
#그래프에서 글로벌 변수(W, b)를 초기화한다.
sess.run(tf.global_variables_initializer())

# train을 실행시키면 여기에 연결된 optimizer-cost-hypothesis-W/b 가 모두 실행된다.
for step in range(2001) :
    sess.run(train)
    if step % 20 ==0 :
        print(step, sess.run(cost), sess.run(W), sess.run(b))

  • 결과

0 1.65899 [ 0.83828998] [-0.95781285]
20 0.0862329 [ 1.26493335] [-0.72846115]
40 0.0654389 [ 1.29238355] [-0.67667371]

1960 6.32628e-06 [ 1.00292134] [-0.00664066]
1980 5.7456e-06 [ 1.00278401] [-0.0063286]
2000 5.21818e-06 [ 1.00265312] [-0.00603121]

=========

  • Placehoder를 사용할 경우

import tensorflow as tf

W = tf.Variable(tf.random_normal([1]), name = 'weight')
b = tf.Variable(tf.random_normal([1]), name = 'bias')
X = tf.placeholder(tf.float32, shape=[None])   # None 이면 실수. 갯수는 자유
Y = tf.placeholder(tf.float32, shape=[None])

hypothesis = X * W + b

cost = tf.reduce_mean(tf.square(hypothesis - Y))

optimizer = tf.train.GradientDescentOptimizer (learning_rate = 0.01)
train = optimizer.minimize(cost)

sess = tf.Session()

sess.run(tf.global_variables_initializer())

# 세션을 실행시킬 때, 여러개의 변수를 한꺼번에 돌릴 수 있다.
for step in range(2001) :
    cost_val, W_val, b_val, _ = sess.run([cost, W, b, train], feed_dict={X:[1,2,3,4,5], Y:[2.1, 3.1, 4.1, 5.1, 6.1]})
    if step % 20 ==0 :
        print(step, cost_val, W_val, b_val)

#여기까지는 optimize 시킨 W,b를 찾는 과정임.
#이를 사용하여 predict를 해보면...
print(sess.run(hypothesis, feed_dict={X: [5]}))
print(sess.run(hypothesis, feed_dict={X: [1.5, 5.5]}))

#이러한 답이 나온다.
[ 6.10004997]
[ 2.59992599  6.60006762]


Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02017. 11. 14. 00:41

Lec 00 - 머신/딥러닝 수업의 개요와 일정

https://www.youtube.com/watch?v=BS6O0zOGX4E

  • 알파고의 충격. 
    • Dr. Andrew Ng 님의 주장 - 머신러닝을 잘 이해하는 것이 슈퍼파워를 가지는 것.
    • 그렇지 못한 사람에 비해 앞서나갈 수 있다.
  • 누가 봐야 하나
    • 머신러닝에 대해 이해하고 싶은 사람
    • 수학이나 컴퓨터 공학에 대해 잘 모르는 사람
    • 기본적인 이해 만으로 머신러닝을 블랙박스처럼 사용하고 싶은 사람
    • Tensorflow 와 Python을 사용하고 싶은 사람.
  • 목표
    • 머신러닝 알고리듬에 대한 기본적인 이해
      • Linear regression, Logistic regression (Classification)
      • Neural networks, Convolutional Neural Network, Recurrent Neural Network
    • 머신 러닝 도구를 사용한 문제해결
      • Tensorflow와 Python
  • 수업 구조
    • 10분짜리 강좌
    • Tensorflow를 사용한 프로그래밍 실습
  • Acknowledgement
  • 스케줄
    • 머신러닝 기본 컨셉
    • 선형회귀분석(Linear Regression)
    • 로지스틱회귀분석(Logistic regression) (Classification)
    • 다변수(Vector) 선형/로지스틱 regression
    • 신경망(Neural networks)
    • 딥러닝
      • CNN
      • RNN
      • Bidiretional Neural networks

Lec 01 - 머신러닝 용어와 개념

  • 기본 개념
    • 머신러닝 이란 무엇인가
    • 학습이란 무엇인가?
      • 감독 학습
      • 무감독 학습
    • Regression 이란 무엇인가?
    • 분류(Classification)이란 무엇인가?
  •  머신러닝이란...
    • 명시적(explicit) 프로그래밍은 한계가 있음
      • 예) 스팸필터 : 법칙이 너무 많아서 프로그래밍하기 힘듦
      • 예) 자동 주행 : 법칙이 너무 많음
    • 머신러닝 : "명시적으로 프로그램하지 않고 (자료 또는 현장에서) 컴퓨터가 학습할 수 있도록 하는 분야" - Arthur Samuel (1959)
  • 감독/무감독 학습
    • 감독 학습
      • label이 정해져있는 예제(labeled example, training set)를 사용하여 학습.
      • 예: 고양이, 개, 머그, 모자 등을 사람들이 미리 제공 (labeled example)
    • 무감독 학습 : un-labeled data. 데이터를 보고 스스로 학습
      • 예: 구글뉴스 그루핑.
      • 예: Word Clustering. 비슷한 단어 모으기.
  • 감독 학습
    • 대부분의 문제 형태임. 이 코스에서 주로 다룰 내용.
      • 이미지 분류(Image labelling) - 이미지 태그를 사용하여 학습
      • 이메일 스팸필터 : labelled 이메일로부터 학습
      • 시험점수 예측 - 기존이 시험점수와 투자 시간관계를 사용한 학습
  • Training data set 이란??

    • 머신러닝의 일반적과정은, X(특징, feature) -> Y로 답(label)이 정해져있는 여러 데이터셋을 ML에 제공하고, 이를 기반으로 학습하면 모델이 생성되는데, 여기에서 모르는 Xtest와 같은 새로운 데이터를 ML에 물어보면 이에 대한 답을 제공해 주는 과정이다. 여기에서 답이 정해져 있는 데이터셋을 training data set이라고 한다.
    • AlphaGo 의 경우
      • AlphaGo는 수많은 기보를 학습하여 바둑선수가 돌을 두면, 그에 대응하는 답을 제공하는 형태로, 감독 학습이다. 여기에서 입력한 기보들이 Training data set이다.
  • 감독 학습의 유형 - 대개 아래와 같은 세가지 유형으로 구분됨
    • 공부한 시간에 근거한 시험점수 예측 - regression (범위가 있음)
      • training set X : 공부시간, Y : 점수
        • (10, 90), (9, 80), (3, 50), (2, 30)
      • 이 경우, ML 모델은 Regression. 학습을 시킴
      • 그렇다면 x=7 이면 점수는? 이라는 문제에 대해 Y=75 라고 답이 나온다.
    • 공부한 시간에 근거한 합격/불합격 - binary classification (두가지로 분류)
      • training set X : 공부시간, Y: 합격여부
        • (10, P), (9 :P), (3, F), (2, F)
    • 공부한 시간에 근거한 학점 (A,B,C,D,F) - multi-label classification (label이 많음)
      • training set X : 공부시간, Y: 합격여부
        • (10, A), (9 : B), (3, C), (2, F)

Lab 01 TensorFlow 기본

https://www.youtube.com/watch?v=-57Ne86Ia8w

  • 구글에서 만든 인공지능(Machine Intelligence)을 위한 오픈소스 소프트웨어 라이브러리
  • TensorFlow외에도 다른 라이브러리 많음. 그러나 절대적으로 TensorFlow 사용자가 많음

  • data flow graphs 를 사용하여 수치적 계산을 하기 위한 오픈소스 소프트웨어 라이브러리

  • Data Flow Graph란?
    • 그래프에서 노드들은 수학적 연산을 표현함.
    • Edge는 그 사이에서 돌아다니는 다차원 데이터 배열(tensor)을 표현함.
      • 한마디로 데이터(Tensor)
    • 이처럼 데이터의 흐름을 표현한 것이 Data Flow Graph이고, 데이터(Tensor)가 돌아다닌다라고 할 수 있음 ->Tensor Flow.
  • TensorFlow 설치
    • https://www.tensorflow.org/install/  에 있는 설명에 따라 설치하면 된다.
    • 나의 경우엔 Anaconda 설치후, 'Anaconda Prompt' 를 실행한 후 나머지 실행
      • GPU 버전의 경우, 별도의 conda environment 를 설치한 후 실행
    • 제대로 설치되었는지 확인하는 방법
      • 'Anaconda Prompt' 실행 (윈도10 검색(좌측아래 두번째)에서 찾을 것)
      • (C:\Anaconda3) C:>activate tensorflow
      • (tensorflow) C:>python
      • >>>import tensorflow as tf
      • >>> tf.__version__

  '1.4.0' 등과 같이 출력되면 성공

  • Hello Tensorflow!

hello = tf.constant("Hello, TensorFlow!")  #default graph에 node를 추가하는 operation임.
sess = tf.Session()
print(sess.run(hello)  # hello 라는 노드를 실행하라는 것.

  • Computational Graph

#먼저, 그래프를 build 함

node1 = tf.constant(3.0, tf.float32)
node2 = tf.constant(4.0)
node3 = tf.add(node1, node2) 

print("node1 : ", node1, "node2 : ", node2)
print("node3 : ", node3)

#이것을 실행시키면 결과값이 나오는 것이 아니라, node1, node2, node의 데이터형만 알려줌. 실행을 시키려면 아래와 같이 돌려야 한다.

#세션을 만들고나서, 그것을 수행시킨다.

sess =tf.Session()
print("sess.run(node1, node2) : ", sess.run([node1, node2]))
print("sess.run(node3) : ", sess.run(node3))

  • Tensorflow를 실행시키는 것은 기존의 프로그램과는 달리... 
    • 첫번째 그래프를 build 하고, 
    • 두번째 sess.run(op)를 통해서 그래프를 실행시키면
    • 그래프에 있는 변수를 갱신하거나, 값을 반환하게 된다.

  • Placeholders (상수가 아닌 변수로 사용할 때)

a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
adder_node = a + b            #이것은 tf.add(a,b)를 간단하게 쓴 것임.

print(sess.run(adder_node, feed_dict = {a:3, b:4.5}))
print(sess.run(adder_node, feed_dict ={a:[1,3], b:[2,4]}))

  • 모든 것이 Tensor다. (Everything is Tensor)
  • Tensor의 Rank

Rank 

Math entity 

Python 예 

 0

 스칼라

 s = 234

 1

 벡터

 v = [1.1, 2.3, 324]

 2

 매트릭스

 m =[[1,2,3],[4,5,6], [4,5,2]]

 3

 3-Tensor (cube)

 t = [[[2], [4], [6]], [[2],[5],[12]], [[14],[7], [12]]]

 4

 4-Tensor

 ....

  • Tensor의 Shape
    • 각각의 element에 몇개 들어 있는가...

Rank 

Shape 

차원-수 

 0

 []

 0-D

 0차원의 Tensor. 스칼라

 1

 [D0]

 1-D

 shape가 [5]인 1차원 Tensor

 2

 [D0,D1]

 2-D

 shape가 [3,4]인 2-D Tensor

 3

 [D0, D1, D2]

 3-D

 shape가 [1,5,3]인 3차원 Tensor 등

 n

 [D0, D1,... Dn-1]

 n-D

 

    • 예를 들어, t=[[1,5], [4,2], [4,4], [3,2]]의 shape는 [2,4] 이다.
  • Data Type

Data Type 

 Pythone type 

 설명

 DT_FLOAT

 tf.float32

 

 DT_DOUBLE

 tf.float64

 

 DT_INT8

 tf.int8

 

 DT_INT16

 tf.int16

 

 DT_INT32

 tf.int32

 

 DT_INT64

 tf.int64

 


Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02017. 11. 13. 21:28

Lab1 : TensorFlow 기본

TensorFlow 설치

- https://www.tensorflow.org/install/

- Anaconda 설치후, Anaconda Prompt 를 실행한 후 나머지 실행

- GPU 버전의 경우, 별도의 conda environment 를 설치한 후 실행

>>  import tensorflow as tf

TensorFlow 실행 예제

import tensorflow as tf
node1 = tf.constant(3.0)
node2 = tf.constant(4.0)
node3 = tf.add(node1, node2)

sess = tf.Session()
print(sess.run([node1, node2]))
print(sess.run(node3) 

TensorFlow 실행 단계

- TensorFlow operations를 사용하여 그래프를 build

- graph(operations)를 실행시킨다. -> sess.run(op)

- 그러면 그래프에 포함된 변수가 갱신된다.

Placeholer를 사용하여 노드만들기. 필요시 실 데이터로 교체 가능. 함수??

a = tf.placeholder(tf.float32)
b= tf.placeholder(tf.float32)
adder_node = a + b

print(sess.run(adder_node, feed_dict={a:3, b:4.5}))
print(sess.run(adder_node, feed_dict={a:[1,3], b:[2,4]}))        -> [3., 7.]

Tensor : array...

- Ranks - 몇차원? 0:scalar, 1: vector, 2:matrix, 3:3-tensor(cube) 

- Shapes -  [[1,2], [3,4], [4,5]] -> [3,2]

- Types - DT_FLOAT, DT_DOUBLE, DT_INT8, DT_INT16, DT_INT32 ...

Lab2 : Linear Regression

import tensorflow as tf

# H(x) = Wx + b
x_train = [1, 2, 3, 4, 5]
y_train = [1, 2, 3, 4, 5]

W = tf.Variable(tf.random_normal([1]), name='weight')  # trainable Variable
b = tf.Variable(tf.random_normal([1]), name='bias')

hypothesis = x_train * W +b

# cost(W,b)...
cost = tf.reduce_mean(tf.square(hypothesis - y_train))

# GradientDecent
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
train = optimizer.minimize(cost)

# Launch the graph
sess = tf.Session()

# Initailize glabal variables in the graph
sess.run(tf.global_variables_initializer())

# Fitting
for step in range(2001):
sess.run(train)
if step % 50 == 0:
print(step, sess.run(cost), sess.run(W), sess.run(b))

Lab3  : Minimizing Cost





===


Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/스마트폰2017. 9. 7. 12:10

저는 이북을 구글 플레이북으로 읽고 있습니다. 제가 2014년에 정리해 둔 글을 보면 제가 왜 구글 플레이북이 쓸만하다고 생각하는지를 아실 수 있는데, 그 이후에도 여러가지 유혹이 있었음에도 불구하고, 다른 이북 프로그램이 구지 필요하다고 생각하지 않고 잘 사용중에 있습니다. 

다음은 구글 플레이북에서 사용할 수 있는 기능들입니다.

  • 오프라인에서 읽기
  • 페이지 북마크, 텍스트 강조표시, 메모 추가
  • 우아한 3D 페이지 회전
  • 휴대전화, 태블릿, 컴퓨터에서 북마크, 메모 및 읽기 위치 동기화
  • 도서 내 검색, 사전 사용, 지리 정보 찾기, 웹 검색결과 찾기, 페이지에 위키백과 표시 
  • 맞춤 텍스트 도서에 글꼴, 글꼴 크기, 레이아웃 선택
  • 주간, 야간, 세피아 읽기 모드 선택
  • 게시자가 허용하는 경우 텍스트 음성 변환으로 책 읽기
  • PDF 또는 EPUB 파일을 라이브러리에 업로드할 수 있습니다

머... 지금봐도 그다지 새로운 기능이 추가된 것도 없고... 그냥 잘 사용중이라고 뿐이 말씀드릴 게 없네요.

===

오늘 정리할 내용은 텍스트 파일을 이북으로 변환하는 방법입니다. 원래 구글 플레이북에서는 epub 형식과 pdf 형식을 지원하지만, 소설책과 같이 주로 글씨로 이루어진 문서의 경우, pdf를 사용하면 불편하여, 반드시 epub 형식으로 변환해야 합니다.

문제는 인터넷에서 찾을 수 있는 text 파일이 문단처리가 되어 있지 않은 자유로운? 형식이라, 그냥 epub으로 변환할 경우, 아주 읽기 불편합니다.  예를 들어, 아래는 김용의 서검은구록 (이 책은 정식 전자책으로는 판매되고 있지 않습니다)이라는 소설의 text 파일을 아무런 조치 없이 변환한 결과입니다.text 파일의 한 줄이 한 문단으로 변환되는 바람에 이런 결과가 생기는 것입니다. 

그래서... text파일을 변환하기 전에 몇가지 처리를 해야합니다.

첫번째는 CRAutoFix 입니다. 구글에서 검색하면 쉽게 찾을 수 있습니다. 2010년 베타버전 뿐이 없었습니다만, 정식버전은 없는 것 같습니다. 이 프로그램은 구두점 등을 확인하여 줄단위로 되어 있는 문서를 문단단위로 바꿔줍니다. 

예를 들어, 아래와 같은 문서를

아래와 같이 여러줄을 묶어서 한줄로 이어주는 것입니다.

이 과정에서 문법을 고려한다고 하는데... 어느정도 적용되는지는 잘 모르겠네요.

아래한글에서도 텍스트문서를 읽어들이면 문단단위로 읽기 기능이 있는데, CRAutoFix 쪽이 훨씬 자연스러운 것 같습니다.

===

그 다음에는 아래 한글에서 필요한 편집을 합니다. (아래 한글을 사용하지 않는 분은 그냥 Microsoft Word에서 직접 작업을 하셔도 됩니다.) 물론 편집을 하지 않아도 보는데는 지장 없지만, 그래도 몇가지만 만지면 꽤 깔끔해 집니다. 이때 글자크기나 문단 형태를 변경하거나 필요하면 맞춤법 검사 등도 유용합니다.

첫 쪽에 그림을 넣어주면 그 그림이 대표 이미지가 됩니다.(시험을 해보니, 작은 그림은 소용이 없고, 500pixel 정도 이상의 그림을 넣어주어야 되는 것 같습니다.) 

제목처리가 필요하다면, 그냥 글자모양, 문단 모양만 바꾸지 말고, 'heading 1' 이라는 제목의 스타일로 지정하면, 전자책 내에서도 제목으로 나타납니다. 아래는 그 예입니다.


또 '새쪽으로 (^Enter)" 처리를 해두면 쪽 바꾸기로 저장됩니다. 특히 제목등이 시작되는 곳에서 새쪽 처리를 해주면 편합니다.

그런데 아래한글에서는 찾고 바꾸기가 신통치 못합니다. 특히 정규 표현식(Regular Expression)을 지원하지 않아, 예를 들면 문장 끝이 마침표 물음표 등의 구두점으로 끝나지 않은 문장 찾기 등이 불가능합니다. 저는 정규표현식을 사용하는 텍스트 에디터를 사용하는 것이 편하더군요. 아래는 그러한 예입니다.
[^.?'"]\n - 문장의 끝이 구두점이 아닌경우
^\".*[^\"]$ - 따옴표로 시작했으나 끝은 따옴표가 아닌 경우
^[^\[].*[^\?\.\"\'\!\>\*]$ - 글의 끝이 적절한 구두점이 아닌 경우
[^\n]\"[^\n] - 글의 중간에 들어 있는 따옴표 찾기

아무튼 익숙한 방식으로 편집하시면 됩니다. 

===

그 다음에는 아래 한글에서 .docx 형식으로 저장합니다. 

다음으로 아래 사이트에 들어가서 이 파일을 변환합니다. 파일 선택을 해주고 제목과 저자를 입력한 후, 아래쪽에 있는 [Convert file]을 선택해 주면 됩니다.

https://ebook.online-convert.com/convert-to-epub

잠시 기다리면 업로드가 된 후, 파일을 변환해주는데, 적당히 저장해 주면 됩니다.

마지막으로 https://play.google.com/books/uploads 으로 들어가 epub 파일을 올려주면 끝입니다.

아래는 현재의 제 구글 플레이북 서재 모습입니다. 이중에는 구입한 책도 있고, 위에서 말한 과정을 통해 업로드시킨 파일도 있습니다. 

===

이상 간략한 epub 파일 변환방법이었습니다.

민, 푸른하늘

Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

  1. 고맙습니다. 덕분에 편하게 epub으로 변경했어요. 줄간격 설정해서 저장한 txt도 그대로 잘 변환해주네요.

    2019.01.11 22:48 신고 [ ADDR : EDIT/ DEL : REPLY ]

기타/스마트폰2016. 6. 7. 17:09

며칠동안 샤오미 밴드(Mi Band)와 샤오미 체중계(Mi Scale)를 사용해 본 소감입니다. 샤오미밴드는 한 두달 정도 정도 사용해 왔고, 일주일 전 부터 체중계까지 구입해서 사용중입니다.


샤오미 제품이 거의 그렇듯이 가격은 저렴하지만, 기능은 좋습니다. 기능이 뛰어나다기 보다는 기본적인 기능에 충실하고 가성비가 뛰어나죠.


샤오미밴드 - 15000원 정도


미 밴드에는 전화나 문자, 기타 일정 설정에 따라 손목이 울리는 기능과 만보계 기능. 크게 두가지 기능이 있습니다. 만보계 기능은 블루투스로 연동되어 기록이 휴대폰에 계속 기록됩니다. 가장 좋은 건 미밴드가 아주 가벼워서 전혀 부담이 안되고, 배터리를 15일마다 한번씩만 충전하면 되는 게 장점입니다. 제가 다른 손목시계형 웨어러블을 싫어하는 이유가 미 밴드에는 해당이 안됩니다. ㅎㅎ

샤오미 체중계 - 35000원 정도


그냥 디지털 체중계인데, 이것도 블루투스로 연동되는 게 특징입니다.  그리고 스위치를 켜고 몸무게를 재는 게 아니라, 그냥 올라서기만 하면 자동적으로 켜지므로 부담없이 사용할 수 있다는 것도 장점입니다. 그래서 아무때나 생각날 때 몸무게를 잴 수 있습니다. 그 결과는 당연히 스마트폰에 기록이 되고요.

이 두가지는 모두 샤오미 앱으로 관리합니다. 현재까지 10일동안 꾸준히 매일 8천보 이상 걷고 있습니다. (그전에는 목표를 채울때도 있고 못채울 때도 있고 했는데 체중계를 구입하다보니 더 열심을 내는 중입니다.) 연휴동안에는 혼자서 열심히 지오캐싱 다니면서 걸음 수 채웠고요.

그 결과 80.6kg 에서 75.7 kg으로 떨어졌습니다. 일주일만에요. 이거는 뭐... 원래 제 목표가 75정도 수준을 지키는 것이긴 하지만, 며칠만에 이렇게 체중이 준 것은 지속될지는 알수 없는 허수에 가깝다고 보입니다. 아직까지는요. 그래도 이 상태를 보름정도는 유지시켜보려고 합니다. 그러면 제 몸이 이게 정상체중이려니... 하고 받아들이지 않을까... 하는 바램입니다.

아무튼... 샤오미 제품이 여러가지로 마음에 듭니다. 가격도 저렴하고, 스마트기기와 연동이 잘되고... 

그런데 이번에 새로 샤오미 밴드2 가 나온다고 하네요. 심장박동 센서가 달렸고, 시간을 보는 정도만 가능하지만 작은 화면? LED가 달렸다고 합니다. 나오면 구입 예정입니다. ㅎㅎㅎ

민, 푸른하늘






Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02016. 5. 5. 00:30

현재... GPX 파일(XML 파일의 일종입니다.)을 해석해서 mySQL DB에 넣기 위해 고민 중에 있었습니다. 


제가 예전에 만들어 둔 프로그램에서는 그냥 javascript - ajax로 읽어 들인 후 사용했었습니다. 원래는 이 부분을 사용하려고 했습니다. 그런데, 이 기능을 이용할 경우, 한 개의 waypoint를 추출해서 배열을 만들고, ajax를 통해 PHP로 넘겨주면, PHP속에서 mySQL에 INSERT 시키는 방법을 사용해야 합니다. 그러면 당연히 터무니 없이 속도가 떨어질 것으로 예상됩니다.


그러던 중, W3C PHP 투토리얼 사이트에서 XML Parser에 관한 내용을 보게 되었습니다. 이걸 이용하면 그냥 PHP에서 XML(GPX파일)을 Parsing 한 후, 바로 MySQL로 넣어줄 수 있으니, 훨씬 작업이 간편할 것이라 생각했습니다.


PHP XML Parser는 두 가지 종류가 있습니다. 하나는 SimpleXML Parser이고, 다른 하나는 XML expat 입니다. SimpleXML은 말 그대로 아주 간단합니다. 그냥 파일이나 string을 지정하면, 전체를 구조체로 읽어 들이는 방식입니다. 그 다음엔 $xml->book[0]->title 과 같이 간단한 참조 방식으로 사용하면 됩니다. 


이에 비해 expat는 상당히 복잡합니다. expat는 이벤트 방식의 Parser라고 하고요, 예를 들어 아래와 같은 문장이 있다면...

<from>Jani</from>

이것을 다음과 같은 3개의 이벤트(사실은 4개의 이벤트)로 보내줍니다. 이런 방식으로 파일 전체가 이벤트로 처리되는 겁니다.

    • Start element: from
    • Start CDATA section, value: Jani
    • Close element: from

언뜻 보기에는 많이 복잡해 보였습니다. 그래서 포기할까 생각했습니다. 그런데, 파일의 크기가 클 수록 이 방식이 빠르고 편하다는 설명을 보고 시도해 보기로 했습니다. (simpleXML Parser의 경우 한꺼번에 메모리로 읽어 들이는 방식이라서 시스템에 따라서 문제가 발생할 수도 있답니다.)


expat Parser는 4개의 함수만 사용하면 거의 80%의 문제는 해결할 수 있다고 합니다. 제가 설명할 것도 바로 이 4가지 함수입니다. (일단 예제는 W3C의 예제를 이용하겠습니다.)


    • $parser=xml_parser_create(); // parser를 생성합니다.
    • xml_set_element_handler($parser,"start","stop"); // 생성한 Parser에 Start event handler 와 Stop event handler를 등록. 당연히 "start"/"stop" 은 함수명입니다.
    • xml_set_character_data_handler($parser,"char"); // Parser에 Data event handler를 등록합니다. "char"가 그 함수고요, 물론 이름은 다른 이름을 사용해도 됩니다.
    • xml_parse($parser,$data,feof($fp)); // parser를 실행합니다.

아래는 W3C 사이트에 있는 예제입니다. 빨간 표시를 한게 위에서 설명한 4개의 함수입니다.

xml_parser_create() 아래로 있는 start(), stop(), char()가 바로 event 핸들러입니다. 이 함수들 3개를 적당히 이용해서 데이터를 처리해주면 됩니다.


<?php
// Initialize the XML parser
$parser=xml_parser_create();

// Function to use at the start of an element
function start($parser,$element_name,$element_attrs) {
  switch($element_name) {
    case "NOTE":
    echo "-- Note --<br>";
    break;
    case "TO":
    echo "To: ";
    break;
    case "FROM":
    echo "From: ";
    break;
    case "HEADING":
    echo "Heading: ";
    break;
    case "BODY":
    echo "Message: ";
  }
}

// Function to use at the end of an element
function stop($parser,$element_name) {
  echo "<br>";
}

// Function to use when finding character data
function char($parser,$data) {
  echo $data;
}

// Specify element handler
xml_set_element_handler($parser,"start","stop");

// Specify data handler
xml_set_character_data_handler($parser,"char");

// Open XML file
$fp=fopen("note.xml","r");

// Read data
while ($data=fread($fp,4096)) {
  xml_parse($parser,$data,feof($fp)) or 
  die (sprintf("XML Error: %s at line %d", 
  xml_error_string(xml_get_error_code($parser)),
  xml_get_current_line_number($parser)));
}

// Free the XML parser
xml_parser_free($parser);
?>


이 파일을 사용해서 note.xml을 parsing하는 순서를 보여드리면...


<?xml version="1.0" encoding="UTF-8"?>

<note>

<to>Tove</to>

<from>Jani</from>

<heading>Reminder</heading>

<body>Don't forget me this weekend!</body>

</note>


먼저 첫줄 <?xml... 은 그냥 무시됩니다. 

두번째 줄 <note>가 들어오면, start event handler로 등록된 start() 함수가 호출되는데, 이때 $element_name에는 "NOTE"가 지정됩니다. 따라서 case 문 등을 사용해 이를 처리해 줍니다.


function start($parser,$element_name,$element_attrs) {

  switch($element_name) {

    case "NOTE":

    echo "-- Note --<br>";

    break;

    case "TO":

    ....


그 다음엔 data event handler가 호출됩니다. (<NOTE>의 경우에는 data에 공백 "  " 만 전달됩니다.)


function char($parser,$data) {

  echo $data;

}


그 다음엔 <to>Tove</to>가 처리될 차례죠. 이것도 비슷한 방식으로 아래와 같은 순서로 처리됩니다.


TO ->start event

Tove -> data event

TO ->end event

" " -> data event


이런 식으로 계속 이벤트를 처리하는 방식으로 처리하면 됩니다. 하나의 노드가 여러개의 이벤트로 나눠오기 때문에 데이터를 처리하는 게 복잡합니다만, 그래도 가능합니다.


====

아래는 제가 테스트해본 프로그램입니다. W3C의 books 예제파일 을 읽어들여서 이를 mySQL 에 삽입하는 예제입니다. 


여기에서 약간 중요한 점이 두 가지 있습니다. 위의 예제와는 달리, xml에 attribute가 있어서 이를 처리하는 부분이 추가되었는데요, 여기에서 each() 함수를 사용했습니다. 또 다른 하나는, mySQL에 입력할 때, prepared statement를 사용했습니다. $stmt=$conn->prepare()를 사용하여 미리 구문만 mySQL로 보내어 미리 최적화를 시킨 후, $stmt->execute();로 실행시켰습니다. 이렇게 해야 실행속도가 빨라진 답니다.



나머지는 아래의 코멘트를 참고하세요.


민, 푸른하늘


<?php


// mySQL DB 연결

require_once 'mySQL_login.php'; //이 파일은 각자의 환경에 맞게 준비해야 함

$conn = new mysqli($db_hostname,$db_username,$db_password, $db_database);

if($conn->connect_errno) {

    die("Connection failed: " . $connection->connect_error);

}


// Table이 미리 있다면 삭제함


$sql = "DROP TABLE IF EXISTS books";

if (!$conn->query($sql)) {

die("Error droping table: " . $conn->error);

}


// Table 생성

$sql = "CREATE TABLE `books` (

  `title` varchar(50) NOT NULL,

  `category` varchar(30) NOT NULL,

  `author` varchar(30) NOT NULL,

  `lang` varchar(10) NOT NULL,

  `year` smallint(6) NOT NULL,

  `price` float NOT NULL

) ENGINE=MyISAM";


if (!$conn->query($sql)) {

die("Error creating table: " . $conn->error);

}


// bind_para 에 사용되는 변수 초기화

$b_title = $b_author = $b_category = $b_lang = "";

$b_year = $b_price = 0;


// prepared statement 준비

$stmt = $conn->prepare("INSERT INTO books (title, author, category, lang, year, price) VALUES (?, ?, ?, ?, ?, ?)");

$stmt->bind_param("ssssid", $b_title, $b_author, $b_category, $b_lang, $b_year, $b_price);


// XML parser 생성

$parser=xml_parser_create();


// XML을 parsing 한 후 저장할 array 초기화

$num_books = 0;

$book = array("TITLE"=>"", "AUTHOR"=>"", "CATEGORY" => "" , "LANG" => "", "YEAR" => 0, "PRICE" => 0);

$index = "";


// Element Start event handler. 여기에서는 $index만 저장함.

function start($parser,$element_name,$element_attrs) {


    global $index,$book;

    

    switch($element_name) {

      case "BOOK":

          break;

      case "TITLE":

          $index = "TITLE";

          break;

      case "AUTHOR":

          $index = "AUTHOR";

          break;

      case "YEAR":

          $index = "YEAR";

          break;

      case "PRICE":

          $index = "PRICE";

          break;

    }


    // attribute의 경우엔 each로 처리함. 

    if(!empty($element_attrs)){

        $temp = each($element_attrs);

        $book[$temp[0]] = $temp[1];

    }

}


// Element Stop event handler. BOOK이 끝나는 시점에서 $stmt를 실행하여 $book array에 들어 있는 내용을 mySQL로 저장. 

function stop($parser,$element_name) {

    

    global $num_books, $book, $index, $stmt;

    global $b_title, $b_author, $b_category,$b_lang, $b_year, $b_price;

    $b_title = $book['TITLE'];

    $b_author = $book['AUTHOR'];

    $b_category = $book['CATEGORY'];

    $b_lang=$book['LANG'];

    $b_year = $book['YEAR'];

    $b_price = $book['PRICE'];

    

    if($element_name == "BOOK") {

          $num_books++;

          $stmt->execute();

          print_r($book);

          echo "<br>";

    }

}


// Element Data event handler. 실제의 값을 $book 배열에 저장.

function char($parser,$data) {

  global $book, $index;

  

  if($index != "") {

    $book[$index] = $data;

    $index = "";

  }

}


// Specify element handler

xml_set_element_handler($parser,"start","stop");


// Specify data handler

xml_set_character_data_handler($parser,"char");


// Open XML file

$fp=fopen("books.xml","r");


// Read data. feof()을 만날 때까지 계속 파일을 읽어들이고 parsing 함.

while ($data=fread($fp,4096)) {

  xml_parse($parser,$data,feof($fp)) or 

    die (sprintf("XML Error: %s at line %d", 

  xml_error_string(xml_get_error_code($parser)), xml_get_current_line_number($parser)));

}


// Free the XML parser

xml_parser_free($parser);

?>




Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02016. 4. 30. 08:52

요즘 다시 PHP 연습중입니다. 하나 만들고 싶은 게 있어서요. 


예전에는 그냥 일반 텍스트에디터를 사용해서 연습을 했었습니다. 그런데 이번에 easyPHP를 설치하다보니, 디버거를 사용할 수 있다는 것을 알게 되어서 일단 easyPHP에 XDebug를 설치했습니다.


그런데, 디버거를 사용하는게 마땅치 않았습니다. eclipse PDT라는 통합개발환경 IDE에서 디버깅을 할 수 있다는 글을 따라해 보기도 했고, notepad++에 플러그인으로 설치했다는 글을 따라하기도 했습니다. 크롬 익스텐션을 설치해보기도 했고요. 물론 모두 실패했습니다. 


그래서 마지막이라는 심정으로 다시한번 검색을 해서 netbeans IDE와 XDebug를 연동할 수 있다는 글을 따라했습니다. 억지로 성공했네요. 


일단 NetBeans IDE는 여기에서 설치하실 수 있습니다. 저는 PHP x64 버전으로 설치했습니다.


설치한 후, NetBeans에서는 아래 그림처럼 설정합니다. Tools -> Options 에 있습니다. 여기에서 Debugger Port는 XDebug 설정값(php.ini)와 동일하게 설정해야 합니다.


한가지, Watches and Ballon Evaluation 을 켜면 변수들의 값을 확인하는데는 편하지만, 불안정하다고 하여 그냥 꺼뒀습니다.



다음으로 폴더설정... 이게 좀 까다로웠습니다. NetBeans의 Project 설정과 easyPHP의 실행환경하고 맞춰주어야만, NetBeans에서 디버거를 실행시킬 때 자동으로 실행시킬 수 있기 때문입니다.


먼저 아래가 easyPHP의 대시보드입니다. 여기에서 폴더가 두개 지정되어 있습니다. Workding Directories와 Portable Directory 입니다. 


여기에 각각 파일을 넣고 실행해보면 Working Directory의 경우, http://127.0.0.1/edsa-WD/ 로 실행되며, Portable Directory는 http://127.0.0.1/로 실행됩니다. 즉, Portable Directory로 지정되어 있는 위치가 root directory로 인식되는 것입니다.  따라서 NetBeans의 실행 디렉토리도 여기로 맞춰 주면 됩니다. (참고로, Working directory 의 경우 edsa-가 강제로 추가되어서 설정하기가 힘들었습니다.)


즉 NetBeans에서 프로젝트를 생성할 때... 먼저 File -> New Project 를 선택하면 아래와 같이 뜨고



다음으로... 프로젝트 이름과 소스 위치를 정하는 화면에서는 자신이 관리하는 위치를 지정해 줍니다. (그냥 프로젝트를 easyPHP의 Portable Directory로 지정된 위치 내에 만든다면 다음단계는 생략해도 됩니다.)



다음으로 실행환경을 아래와 같이 정해줍니다. 반드시 Source Folder의 내용을 다른 위치에 복사하도록 지정을 하고, 그 위치를 easyPHP의 Portable Directory와 맞춰줍니다. 이렇게 하면 자신이 관리하는 위치에서 작업을 하더라도 실행할 때는 해당위치로 복사가 되어, localhost에서 실행될 수 있습니다.



===

이렇게 해둔 상태에서 원하는 파일에서 마우스 오른쪽버튼을 누르고 Debug를 지정하면...



다음과 같이 웹브라우저에서 해당프로그램이 Debug 상태로 실행됩니다. 아래를 잘보면 localhost의 응답을 기다리는 중... 으로 표시됩니다.



아울러, Netbeans 편집화면에서는 아래와 같이 디버그용 버튼들이 활성화되고, PHP 첫라인인 <?php 에서 실행이 중지된 상태로 사용자의 입력을 기다리게 됩니다. 단추나 F7(Step into), F8(Step Over) 등을 이용해 한줄씩 실행시키고 변수의 상태를 확인하면서 디버깅하면 됩니다.



====

이상입니다. 아직 NetBeans를 잘 몰라서 억지로 여기까지만 설정을 했습니다. 앞으로 좀더 사용하다보면 좀 더 깔끔한 방법이 생길지도 모르겠습니다.


민, 푸른하늘

Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02016. 4. 27. 10:25

프로그램 개발을 위해서는 Debugger가 필수입니다. 특히 대형프로젝트가 될 수록 Debugger 없이는 거의 개발이 불가능합니다. 


제가 사용중인 easyPHP에도 디버거를 설치할 수 있습니다. (다만 실행은 별도의 환경이 필요합니다. 이건 다른 글에서...) 디버거는 널리 사용되고 있는 XDebug를 사용했습니다.


XDebug를 설치하려면 먼저 easyPHP에서 실행환경을 체크해야 합니다. 저는 아래와 같이 easyPHP 의 대시보디에서 "Portable Directory"로 등록된 곳에 원래 들어있는 phpinfo.php를 사용했습니다. 그냥 <?php echo phpinfo(); ?>와 같이 한줄 짜서 실행시켜도 됩니다.


 

그러면 다음과 같은 화면을 볼 수 있습니다. 여기에서 빨간 표시를 한 4가지를 체크해야 합니다.



이제 xdebug.org 다운로드 사이트 로 이동하여 적당한 dll을 다운받아야 합니다. 위에서 확인한 정보를 바탕으로 적당한 것을 선택하면 됩니다. PHP 5.6 버전이고, VC11이며, x86이니 32bit 버전입니다. 마지막으로 Thread Safety가 enabled로 되어 있으면 TS버전을 받으면 됩니다. 이렇게 다운로드 받은 파일을 적당한 곳에 복사해줍니다.(저는 easyPHP 디렉토리에 넣어주었습니다.)



다음은 설치된 내용을 설정화일에 반영해야 합니다. 이를 위해서 php.ini 파일을 편집합니다. php.ini 파일은 easyPHP 설치위치 ->eds-binaries -> php -> php버전명 속에 들어 있습니다. 저의 경우에는 아래와 같습니다.


\EasyPHP-Devserver-16.1\eds-binaries\php\php5619vc11x86x160426163245


이 php.ini 파일을 적당한 편집기로 열고, zend 를 검색해보면 #zend_extension 이라는  부분이 있습니다. 여기에 아래와 같이 추가해 줍니다. 물론 자신의 경로명과 파일명을 넣어야겠죠.


zend_extension="C:\Program Files (x86)\EasyPHP-Devserver-16.1\eds-binaries\php\php5619vc11x86x160426163245\php_xdebug-2.4.0-5.6-vc11.dll"



그리고 바로 아래에 다음과 같은 항목들을 추가해줍니다.


xdebug.remote_enable=1
xdebug.remote_handler=dbgp
xdebug.remote_mode=req
xdebug.remote_host=127.0.0.1
xdebug.remote_port=9000


그 다음엔 Apache 서버를 껐다가 다시 실행시키고, 다시 phpinfo.php를 실행시킵니다. 이때 아래와 같이 Zend engine 부분에 with Xdebug... 라는 행이 추가되면 성공입니다.



====

그런데, 이렇게 실행해도 아무런 변화가 없습니다. 이 상태에서는 디버거를 실행시킬 수도 없고요. 그래서 별도의 환경을 구축해야 합니다. 이건 NetBeans 디버깅환경 설정을 읽어보시기 바랍니다.



민, 푸른하늘


Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02016. 4. 26. 20:04

예전에 반쯤 공부하다가 팽겨쳐 뒀던 PHP를 다시 공부하기로 했습니다. 


먼저 예전처럼 Zend Server를 설치하기로 했습니다. 제가 공부하는 책에서 Zend Server를 설치하여 사용하기 때문이었습니다.


그런데 그동안 업그레이드가 되면서 무료버전이 사라졌더군요. Free Trial 버전은 1개월, 기타 학생용버전 등은 1년 이후에는 정식버전을 사야하는 것 같았습니다. 뭐 그래서 과감하게 포기. 설치하다가 에러가 발생하는 게 아니었으면 계속 갔을지도 모르지만...


하여튼... 그래서 best WAMP로 검색을 좀 해봤습니다. WAMP는 Windows + Apache + MySQL + PHP 로 구성된 Suite를 말합니다. 물론 Zend Server를 순위에 올린 사이트도 있었지만, 다른 제품도 많이 있더군요. 저는 그중에서 easyPHP가 제일 마음에 들었습니다. 쉽다니까. ㅎㅎ


easyPHP.org 에 접속하면 아래와 같은 화면이 보입니다. 좌측은 DevServer 즉, 개발용 서버이고, 우측은 WebServer, 즉 단순 서버용입니다. 저는 최신버전의 DevServer를 택했습니다.



버튼을 클릭하면 설치프로그램이 다운로드 되고, 그것을 실행시키면 다음과 같은 화면이 나옵니다. 아무런 설정이 필요 없습니다. 그냥 자동으로 설치됩니다.



그런데, 설치가 끝난 후 실행시키려면 다음과 같은 화면이 뜹니다. 뭔가 설치를 해야 한다고 나오네요.



원래 첫화면에도 "Visual C++ Redistributable for Visual Studio 2015 x86 or x64 required" 라고 되어 있는데, 자신의 컴퓨터에 맞게 x86 버전이나 x64 버전을 설치하면 됩니다. 



그런데... 이 두개의 파일을 모두 설치했음에도 동일한 에러가 발생하네요. 그래서 좀 더 찾아보니, "Visual C++ Redistributable for Visual Studio 2012"도 설치해야 한답니다. 그래서... ㅠㅠ 어쨌든 이렇게 다 설치를 했더니 에러가 발생하지 않았습니다. 


자... 이제 시작.!!! 바탕화면에 깔린 아이콘을 클릭!!! 그런데 아무런 변화가 없었습니다. 잠시 기다려도 감감 무소식. 무슨 화면같은게 뜨던가, 웹브라우저에 뭔가 나타나던가... 그래야 할텐데 아무것도 나타나지 않았습니다. 또한 홈페이지에는 당연히 뭔가 문서가 있겠지 싶었는데, 아무것도 안보이니 정말 황당했습니다. 


이때 아래와 같이 윈도 오른쪽 아래에 있는 '숨겨진 아이콘'에서 DevServer 아이콘을 클릭하고 Open Dashboard를 선택하면...



웹브라우저에 아래와 같은 화면이 나타납니다. 저는 여기에서 아래처럼 3가지를 먼저 설정했습니다. phpMyAdmin은 아직 제가 몰라서 나중으로...


여기에서 HTTP SERVER를 누르고 APACHE 서버를 선택해서 Start를 눌러주고요,



DB SERVER에서 MYSQL을 선택하고 Start를 눌러주면 됩니다. 그러고 나서 다시 Dashboard로 돌아오면 아래와 같은 모습이 됩니다.



이제 마지막으로 작업공간을 지정하면 됩니다. 윗쪽은 easyPHP에서 사용하는 디렉토리명이고, 아래는 실제 사용할 폴더명을 복사해서 넣어주면 됩니다. 



====

이 정도하면, 개발용 설정은 거의(아주 간략하게만) 끝났습니다. 하나만 실험을 해보죠.

먼저 아래와 같은 내용으로 hello.php 라는 파일을 만들어 작업 디렉토리에 넣어줍니다.


<?php 

echo "Hello World!"; 

?>


이제 작업 디렉토리를 확장시켜보면 아래와 같이 hello.php 가 들어있습니다.


hello.php 오른쪽에 있는 눈모양의 그림을 클릭하면, 새로운 창이 열리고 실행됩니다.


===

2016/5/14 추가


그동안 easyPHP를 계속 사용해 왔지만, 에러가 계속 발생하여 여러번 재설치하다가 오늘 드디어 XAMPP를 설치했습니다. (참고로 easyPHP는 별도로 삭제 프로그램이 없으며, 그냥 설치된 디렉토리를 찾아 지워주기만 하면 삭제가 완료됩니다.)


XAMPP도 설치는 그다지 까다로울 것이 없습니다. 그냥 AphacheFriends 사이트에서 원하는 파일을 다운로드 받아 실행만 시키면 됩니다. 저는 PHP the right way의 권고에 따라 PHP7 버전으로 설치했습니다. Backward compatibility의 문제가 거의 없고, 속도도 빠르다고 하니까요.


다만 설치 초기에 UAC 설정으로 인해 잘 돌아가지 않을 수 있다... 는 경고가 뜨는데, Program Files(x86)에 설치하지 말고 별도의 폴더 (예: c:\xampp)에 설치해주면 문제가 없다고 합니다.



그 다음에는 easyPHP와 그다지 다를 건 없었습니다. xamppcontrol.exe을 실행시켜 보면 아래와 같은 창이 뜨는데, 여기에서 Apache와 MySQL (실제로는 MariaDB)를 실행시킬 수 있고, 설정도 바꿀 수 있습니다. Port 번호만 유의하면 문제가 없습니다.



또한 XDebug 설정도 EasyPHP의 경우와 거의 동일합니다. 자신의 버전에 맞는 XDebug 파일을 복사해 두고, php.ini 파일을 적당하게 수정만 해주면 완료입니다. 


머... 이상으로 대충~~


민, 푸른하늘

Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02016. 4. 11. 00:36

이 글은 예전에도 관심은 있었지만 포기하고 있다가, 그래도 한번 배워야지 싶어서 며칠 들여다보고, 제 마음대로 정리한 글입니다.


왜 사용해야 하나?

Git은 소스관리 도구입니다. 물론 프로그램 소스 뿐만 아니라, 텍스트형식이라면 뭐든지 추적관리할 수 있습니다. Git을 사용하면 파일을의 변화를 모두 기록합니다. 따라서 언제든지 돌릴 수 있습니다. 따라서 거의 필수적이라고 생각합니다. 특히, 클라우드 저장소인 GitHub.com 와 함께사용하면 언제든 접근할 수 있고, 다른 사람들과 협업 가능해서 활용도가 높습니다.


혼자서도 필요한가? 

저는 아주 간단히 제가 필요한 프로그램을 가끔 개발합니다. 개발한다고 하기도 민망할 수준입니다. 그래도 Git이 필요한가... 라고 고민을 해봤는데, 아직 완벽하게 이해하지 못했지만, 소스관리 목적만으로도 충분히 활용할 가치가 있다고 생각합니다. 회사와 집, 그리고 노트북과 PC를 왔다갔다 하면서 개발한다면 GitHub와 같이 이용하면 좋을 것 같습니다.


아래는 제가 필요한 만큼만 정리한 겁니다. 그래서 첫번째 부분은 혼자, 하나의 기기로 개발하는 경우 (GitHub를 사용할 필요없이) 필요한 명렁어들만 정리했습니다. 두번째 부분은 역시 혼자 개발하지만, 여러 곳, 여러기기로 개발할 때 필요한 명령어들을 정리했습니다.


Git을 혼자서 사용


원한다면 Git을 혼자서 로칼에서만 작업할 수도 있다. 

    • Git 도구를 다운로드 받기
    • 초기 설정
      • 원하는 곳에 디렉토리 만들기
      • git init : 로칼 저장소가 만들어짐. 
      • git config --global user.name "Your Name Here"
      • git config --global user.email  "Your Email here"
    • 파일 보관하는 방법
      • git add <files> : 관리하기 원하는 파일을 stage(index)에 추가. 
      • git commit -m "message" : add로 추가된 파일들을 로칼 저장소(local repository)에 추가함. 이때 이유를 "message"에 명확히 담아줄 것
      • .gitignore에 추가하면 관리하고 싶지 않은 파일(*.o, *.bak 등)이 표시되는 것을 막을 수 있다.
    • 기타 자주 사용하는 명령어
      • git status -s 짧게
      • git diff : 수정했지만, staged 가 아닌 파일을 비교가능
        • git diff --cached : staged 된 파일과, commit된 파일을 비교
      • git log : commit 한 내용들 보여줌
        • git log -p : diff 도 함께 보여줌
        • git log --oneline : 한줄에 하나씩만
      • git show [hash-value]
    • 기타 필요한 명령어
      • git commit --amend : 바로전 commit을 수정. 메시지 수정 혹은 파일 추가 등등 비슷한 내용을 계속 commit 할 때, commit 숫자를 늘릴 필요 없이 바로전 commit을 수정해줌.
      • git reset HEAD --<file명> : staged 되어 있는 파일을 제외시킬 때
      • git checkout -- <file명> : 파일의 변경을 취소하고, 바로 전 commit 상태로 되돌림
      • git config --global alias.unstage 'reset HEAD --' : unstage라는 alias로 만듦. git unstage <file명>


여러 기기에서 사용할 때. 원격 저장소가 필요


    • GitHub에 원격저장소(remote repository) 만들기. 디렉토리명과 같도록 하는 것이 좋음
    • 원격저장소(remote repository)에 처음으로 저장하기
      • GitHub에 원격저장소 생성
      • 원격저장소의 주소 복사
      • git remote add origin [원격저장소 주소]
      • git push origin master : 현재까지 로칼 저장소에 저장된 내용을 원격저장소에 보관함
    • 다른 기기에서 원격저장소로부터  최초로 받아오기
      • mkdir [directory 명]
      • GitHub에서 원격저장소의 주소 복사
      • git clone [원격저장소 주소]
    • 일상 작업
      • git pull : 다른 기기에서 작업하여 원격저장소에 저장된 내용을 가져와서 Merge함
      • .... git add / commit : 기타 작업 수행 
      • git push origin master
    • remote의 상태보기
      • git remote -v
      • git remote show

Branch로 작업할 때. 


계속 수정중인 경우, master는 그대로 두고, branch를 만들어 단위작업을 수행. 완료되면 master와 합침. 수정작업을 branch로 분리하여 수행하면 여러가지 변경을 독립적으로 진행할 수 있어 좋음.

    • git branch [branch-name] : 현재 사용중인 branch를 가르키는 새로운 branch 생성
    • git checkout [branch-name] : 해당 branch로 이동. 그러면 현재 directory의 파일들이 바뀜
      • 그 다음엔 일상적인 작업을 하면 원래의 branch와 새로운 branch에 각각 따로 저장됨
      • 완전히 이상없음을 확인하면 merge하면 됨
        • git branch master -> git merge [branch-name]
      • 완료하기 전에 다른 작업이 필요하면 master branch로 돌아가 필요한 부분에서 새로운 branch를 생성하여 완료하고 다시 예전 branch로 돌아가 작업하면 됨. 완료된 후 merge.
      • merge 후 필요 없는 branch는 git branch -d [branch-name] 명령으로 삭제
    • 확인하는 방법
      • git log --oneline --decorate --graph --all
    • 충돌 발생시 처리. 
      • 각각의 branch에서 동일한 파일/위치를 편집하고 merge하면 충돌 발생

      user@user-PC MINGW64 ~/GIT/git-training (master)

      $ git merge testbranch

      Auto-merging test.txt

      CONFLICT (content): Merge conflict in test.txt

      Automatic merge failed; fix conflicts and then commit the result.

      • 이 상황에서 충돌이 발생한 파일(test.txt)을 열어보면 아래와 같이 충돌난 부분이 보임

      <<<<<<< HEAD

      This change is for master branch. Different from "testbranch"'s version

      =======

      Changed again for branch test.

      >>>>>>> testbranch

      • <<<< 부터 >>>> 까지를 편집하여 정리함
      • 완료 된 후, git commit 명령을 사용하면 두 개의 branch  merge 작업이 완료됨
    • 처리 순서
      • 로컬에서 git checkout master 명령으로 master 브랜치로 이동
      • git merge [branch name] 명령으로 브랜치를 합침
      • git push origin [branch name] 명령으로 gitHub로 송부
      • git branch -d [branch name] 명령으로 브랜치를 삭제
      • 그 다음 gitHub에 접속
        • [branch name] 브랜치에 들어감
        • Pull request 수행
        • Pull request 를 Merge 함.
    • 기타 명령
      • git branch --merge 를 하면 merge가 된 branch가 보임. *가 없는 branch는 삭제
      • git branch --no-merge


=====

1. 시작. 전반적인 개념.

    • https://rogerdudler.github.io/git-guide/index.ko.html
    • 잘 사용하려면 여기에 있는 내용을 어느 정도 이해할 수 있어야 함.
    • 하지만, 이해하기 쉽지 않음. 뭘 배워야 하는지 미리 파악하기 위함.
    • 맨 아래쪽에 안내서들 목록이 있음.

2. 기본적인 Git 사용법.

      • 일련의 설명과 함께 가장 기본적인 사용법
      • 맨 아래에 Resource 가 있음.

3. 심화 학습이 필요하다면

4. Permission denied(publickey) 에러에 대한 대처

    • 사용자의 ssh가 등록되지 않아서 발생하는 문제
    • 이 에러가 발생하면 push, clone 등이 불가능함
5. 좀 더 읽어 봐야 할 글
    • http://tmondev.blog.me/220759303637


Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타2016. 4. 3. 23:23

3년전쯤 아주 간단하게 통돌이 로스터를 제작해서 지금까지 거의 한주에 250그램 * 3번-4번씩 커피를 구워 먹었습니다. 처음엔 아무 생각 없이 만들었던 터라 불편한 점들을 약간씩 개조해서 지금까지 잘 사용해 왔습니다.


이번에 새로 통돌이 로스터를 제작했습니다. 거의 한시간씩 손으로 돌리는 게 귀찮기도 하지만, 나무재질이다보니 군데군데 타들어가서 (아직 더 쓸 수는 있지만) 할 수 없이 새로 만들게 되었습니다.


아래는 준비과정부터 최종조립까지 모든 과정을 정리한 글입니다. 이 글을 처음 쓴게 2월 9일로 되어 있으니... 거의 2개월에 걸쳐 썼네요. 오늘 조립 끝내고 이 글까지 정리하니 기분이 아주 좋습니다. ㅎㅎㅎ 로스터 자작을 생각하시는 분들께 참고가 되길 바랍니다.


==

먼저 며칠동안 네이버 커피마루 카페 자작로스터 게시판을 읽고 필요한 자료를 정리했습니다. 그러면서 어떻게 만들 것인지 궁리를 했구요. 정리된 자료는 여기를 보시면 되는데, 제가 필요한 것만 정리한 거라 별 도움은 되지 않을 것 같네요.


어쨌든 그래서... 이번에 제작할 통돌이 로스터는 아래와 같이 제작하기로 했습니다.

  • 모터 - 3년동안 열심히 핸드휠로 돌렸으니, 이번에는 자동으로 구을 예정입니다. 다만 모터축과 통돌이 축이 동일선상에 있으면 모터가 튀어나와 불편하고, 손잡이를 달 수 없어서 베벨기어를 사용하여 90도로 꺽어 설치하기로 했습니다.
  • 통돌이 한쪽에 깔대기를 달기로 했습니다. 중간에 온도도 체크하고 커피 상태로 확인할 수 있습니다. 그보다 더 중요한 것은 그 구멍으로 한꺼번에 쏟는 방식으로 바꿀 예정입니다. 예전에는 멸치다시통의 클램프를 일일이 풀어서 쏟아야 했기 때문에 약간 데일 위험도 있고, 시간도 오래 걸렸기 때문입니다.
  • 알루미늄 반사판 - 예전에는 간이식으로 반사판을 만들었는데, 이번엔 좀 튼튼하게 설치할 예정입니다.

아래가 스케치업에서 대략 그려본 모습입니다. 통의 크기는 먼저 휴대용버너를 구입하고, 그에 맞도록 결정했는데, 멸치통+깔대기를 조합하면 길이가 길어져서 약간 튀어나오게 만들었습니다.



이 설계도는 아래에서 받으시면 됩니다. 스케치업으로 만들었습니다. 구체적인 치수는 도면에서 확인하시기 바랍니다.


coffee_roaster.skp


===

먼저 제일 중요한 부품인 휴대용 버너와 드럼입니다. 휴대용버너는 아무거나 고르면 되고, 그냥 집에 있는 걸 사용해도 무방합니다. 다만, 저는 가장 가스 소비량이 많은 걸로 골랐습니다. 화력이 좀 더 셀 것 같아서요.



드럼은 이번에도 멸치다시통을 사용합니다. 오픈마켓에서 멸치다시통을 찾아보면 아주 많습니다. 저는 5호를 사용합니다. 지름은 16cm, 높이는 18cm 입니다. 5호라고 되어 있어도 회사별로 크기는 제각각이므로 잘 보고 선택하셔야 합니다. 


멸치다시통은 우선 뚜껑을 고정시켜주는 클램프를 떼어냈습니다. 그냥 무식하게 망치와 드라이버 그리고 뻰찌로 떼어냈습니다. 약간 찢어진 부분이 생기긴 했습니다만, 별로 사용에는 지장이 없을 것 같습니다.



그 다음 멸치다시통 속에 교반날개를 달아야 합니다. 멸치다시통의 폭이 화구의 크기보다 크기 때문에 그냥 사용할 경우, 가운데 부분은 타고, 바깥부분은 아직 터지지도 않은 상태가 되어버립니다. 따라서 교반날개는 콩이 안쪽으로 들어오도록 방향을 맞춰서 달아야 합니다. 아래가 교반날개를 단 모습입니다.



날개는 아래 처럼 생긴 "스텐찜기"를 사용했습니다. 약간만 힘을 주면 날개들이 각기 떨어져 나오고요, 이걸 뻰찌로 눌러주면 90도로 꺽을 수 있습니다.



아래는 찜기를 펴고 구부린 모습. 약간 지저분한 건 집에서 사용하던 걸 재활용했기 때문입니다. ㅎㅎ



아래는 멸치다시통 속에 교반날개를 단 모습입니다. 회전방향을 정하고... (저는 손잡이를 기준으로 시계방향으로 회전시키도록 했습니다. 밖에 있는 콩들이 안쪽으로 모이도록 달아주었습니다.



그런데 문제는 멸치 다시통 위에 올려진 스텐 깔대기 입니다. 넓은 쪽 크기는 멸치다시통보다 약간 큰 정도가 좋고, 좁은 쪽은 가능한 한 넓은 게 좋습니다. 스텐 깔대기도 오픈마켓에서 검색하면 많이 나오긴 하지만, 문제는 멸치다시통과 스텐깔대기의 크기가 잘 맞지 않는다는 겁니다. 그래서 한참 검색하다가 결국 이번에 저랑 같이 제작하기로 한 분이 직접 황학동에 있는 주방기구 거리에 나가서 가장 잘 맞는 녀석으로 골랐습니다. 사실은 스텐 깔대기 좁은 쪽이 손이 들어갈 정도로 좀 넓은 걸 찾았는데, 그나마 제일 넓은 게 3cm 정도가 최대였습니다. 


아래는 멸치다시통에 스텐 깔대기를 씌우고 철사로 고정한 모습입니다. 처음에 이 두개를 어떻게 고정해야 하나... 용접이 좋을까... 나사를 박으려면 안쪽에서 잡아주지 못해서 헛돌텐데... 이런 고민하다가 내부를 손봐야 할 때도 있을 테니 철사로 묶어두기로 했습니다. (같이 제작하는 분의 아이디어입니다.) 잘 보시면 다른 나사들도 보이실텐데, 교반날개를 고정한 나사입니다.



====

그 다음 나무 프레임. 원래 스텐으로 하고 싶은 생각이 꿀떡 같았지만, 그랬다가는 비용이 껑충 뛰고... 만약 스텐으로 할 경우에는 이런 모양이 아니고 밀폐식으로 가야하고... 그러다 보면 그냥 자작품을 구입하는 게 나을 정도가 되는지라... 나무로 프레임을 짜기로 했습니다.


나무프레임도 그냥 오픈마켓에서 '목재 재단' 혹은 'DIY 목재' 등으로 검색하면 많이 나옵니다. 크기만 정확하게 정해주면 원하는 크기로 재단해서 보내주니 간단하게 작업할 수 있습니다. 저는 이번에는 같이 제작하기로 한 분이 판재도 있고, 공구도 있어서 직접 재단하였습니다. 



그 다음 구동부입니다. 아래 그림처럼 회전축과 모터, 베어링 그리고 두 개를 연결할 베벨기어로 구성됩니다. 




제일 먼저 결정할 것이 회전축입니다. 베어링과 기어 모두 회전축에 맞아야 하기 때문입니다. 저는 여러번의 시행착오끝에 8/3 인치 전산볼트로 결정했습니다만, 7mm 또는 8mm 를 사용하는 것이 더 편할 것 같습니다. 


원래 회전축은 원래 볼트를 사용할 예정이었습니다. 여기에서 10mm 에 220mm 짜리 육각볼트가 있어서 구매를 했는데, 나중에 결합하려고 봤더니 문제가 있었습니다. 다름이 아니라, 나사가 중간부분부터 시작되어서... 이걸 멸치통에 결합하려면 용접이든 납땜이든 별도의 조치가 필요한 것이었습니다. 


그래서 결국.... 머리가 없이 전체가 나사산으로만 이루어진 전산볼트를 사용하게 되었습니다. 원래는 그것도 10mm 짜리가 되어야 하는데, 미리 제작해둔 손잡이의 구멍이 9mm 로 만들어져서, 10mm짜리를 전혀 끼울 수 없다보니 8/3인치(약 9.5mm) 1m 짜리 로 구매하였습니다. 물론 이에 맞는 너트와 와샤도 새로 구입했고요. 처음부터 전산볼트를 사용할 걸.... 그냥 쇠톱으로 자르면 되는데, 좀 편하고자 했다가 망쳤네요.



그 다음 베어링입니다. 베어링은 두 가지가 필요합니다. 회전축에는 내경은 10mm, 외경은 30mm짜리 볼 베어링을 구입했습니다. 깔대기쪽은 약간 작은 베어링 2개를 설치해서 그 위에 깔대기 입구를 올려놓는 방식으로 설치하기로 했고요(내경 10mm, 외경 25mm). (** 그런데 깔대기쪽은 베어링 없이도 소음이 별로 없어 그냥 설치하지 않았습니다.)



다음은 모터. 회전속도는 60 RPM 정도가 좋다고 합니다. 그래서 속도는 상대적으로 늦으면서 힘이 받쳐주는 기어드 모터(geared motor)를 사용해야 합니다. AC 방식과 DC 방식이 있는데, 컨버터가 필요 없도록 AC 방식을 사용하기로 했습니다. 물론 회전축 내경은 10mm 로요. 그런데 우리나라 제품들은 대부분 회전축 내경이 7mm 혹은 8mm 가 많았고, 10mm는 찾지 못했습니다. 그래서 중국 알리바바를 검색해서 하나 찾긴 했습니다. 그런데 문의를 해도 답도 없고... 값도 싼것도 아니고... (하나당 40달러정도) 그래서 그냥 포기하고 구로공구상가에 나가서 하나 사왔습니다.


아래가 구입한 모터입니다. DC 모터이고, 12볼트짜리입니다. 문제는 원래 회전축이 10mm 짜리를 원했는데, 그런건 어디에도 없더군요. 그래서서 모터집 사장님이 권해주신 싼 걸로 (15,000원) 구입했습니다. 회전축 직경은 7mm.



아래는 DC 전원입니다. 12볼트 DC 전원은 많이 구할 수 있어서 가격부담도 그다지 없습니다.



모터는 아래 그림과 같이 벽면에 수직으로 붙일 예정입니다. 제가 구상중인 통돌이는 손잡이로 들어서 옮기는 걸 생각하고 있는데, 한쪽은 손잡이, 다른쪽은 쏟는 구멍이 있어서 모터 축을 회전축과 일치 시킬 수 없기 때문입니다. 그래서 아래와 같이 베벨기어가 필요합니다.



베벨기어도 Aliexpress에서 찾았습니다. 회전축이 10mm 인 것도 여러가지가 있어서 구하기 어렵지 않았습니다. 여기에 들어가보시면 됩니다. 



기타 여러가지 부자재들. 베어링은 위에서 설명했으니 설명하고... 왼쪽 아래 테이프는 알루미늄 테이프입니다. 베벨기어와 베어링이 회전축보다 약간 크기가 커서 헐렁거리지 않도록 알루미늄테이프로 감아준 후 양쪽에서 볼트로 조여주었습니다. 볼트 - 스프링와샤 - 베어링 - 스프링와샤 - 볼트 이런 순서로요.



그리고 위 사진 오른쪽에 있는 건 배관 자재로 판매하는 새들, 혹은 양새들이라고 부르는 물건입니다. 관을 고정시키기 위한 용도인데, 제 모터가 실린더 형으로 생겨서 이걸로 고정했습니다. 


=====

이제 조립에 들어갑니다. 먼저 통과 회전축 등을 조립했습니다.



아래는 좀더 자세한 모습입니다. 보시는 것처럼, 모든 걸 볼트-와샤로 고정했습니다. 먼저 이렇게 대충 설치한 후, 통에 설치하면서 간격을 조절했습니다. 맨 오른쪽에 있는 손잡이... 이게 가장 럭셔리한겁니다. 호두나무로 깍은 겁니다. 아주 비쌉니다. 이걸로 하실 필요 없습니다. ㅎㅎㅎ



아... 이때 통 밑바닥을 뚫는 방법... 처음은 위치를 잡아서 못으로 살짝 찍어둔 후, 드릴 작은 걸로 구멍을 뚫어줍니다. 하지만, 대부분 가정용 드릴엔 10mm 구멍용 비트가 없기 때문에, 아래와 같은 스텝드릴비트가 필요합니다. 저는 여기에서 구입했습니다. 참고하세요.




그 다음은 모터부. 대충 아래와 같이 설치했습니다. 구입한 양새들의 크기가 좀 작다보니, 중간에 간격을 매워줄 게 필요해서, 3D 프린터로 찍었습니다. 잘 보시면 모터와 베벨 기어 사이에도 3D 프린터로 만들어 끼운 게 보이실 겁니다. 모터의 축은 7mm, 기어의 회전축은 10mm 이다보니, 두개를 꽉 맞물려 돌아가도록 하기 위해서는 어댑터가 필요했거든요.



아래가 베벨기어 어댑터의 모습입니다. 아마도 이번에 3D 프린터가 없었더라면 불가능은 아니더라도 많이 괴로웠을 것 같습니다. 




아래는 모터부를 조립한 모습입니다. 모터와 기어의 위치를 조정해서 잘 맞추는 게 사실 제일 까다로운 작업이었습니다. 베어링 앞에 있는 건 베어링을 비롯해 회전축이 앞쪽으로 나오지 않도록 고정해주는 Stopper 입니다. 그냥 통조림 깡통을 잘라 붙였습니다. ㅎㅎ



=====

추가 : 여기에 정리한 내용은 엄청난 시행착오를 그냥 적은 것이므로, 이걸 그대로 따라하는 것은 좋지도, 현실적이지 않습니다. 특히, 모터/회전축/베어링/베벨기어를 맞추기위해 상당한 삽질이 이루어졌기 때문입니다. 설계를 끝내면 그걸 가지고 (구로공구상가 말고) 청계천으로 가보는 게 좋을 것 같습니다. 아래의 글을 참고하세요.


중앙유통단지, 청계천에 가다(모터집, 체인기어집, 금속가공집 탐방기)

====

아래가 이런 과정을 통해 만들어진 완성품입니다. 오늘 조립했습니다. 조립에 걸린 시간은 두 시간 정도. 사실 준비 과정이 길었지, 조립하는 건 그냥 드라이버만 있으면 되는 수준. ㅎ





깨끗하죠? 딱 생각한 만큼 만들어졌습니다. 아니 생각한 것보다 훨씬 이쁘게 만들어져서 너무 기분이 좋네요.


아래는 만들자 마자 시범으로 볶는 모습. 좀 지저분합니다. 체프가 날리다보니 청소를 간단히 하려면 어쩔 수가 없습니다.



마지막으로 동영상입니다. 이걸로 세번 구워봤습니다. 



물론 만족입니다. 소음이 약간 거슬리기는 하지만, 손으로 돌려줄 필요 없고, 그냥 쏟아부으면 되니, 아주 간단해 졌습니다. 물론 옆에서 지켜야 하는 건 변함이 없지만, 이제는 혼자 해도 문제가 없을 것 같습니다.


아무튼... 너무 기분이 좋습니다. 두어달 생각해 왔던 걸 마무리 지으니, 십년묵은 체증이 쑥 내려간 느낌이네요. ㅎㅎㅎ


민, 푸른하늘

Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타2016. 1. 27. 01:08

3년전쯤 아주 간단하게 통돌이 로스터를 제작해서 지금까지 거의 한주에 250그램 * 3번-4번씩 커피를 구워 먹었습니다. 아무 생각 없이 만들었던 터라 약간씩 개조해서 지금까지 잘 사용해 왔습니다.


이제 새로 통돌이 로스터를 제작하려고 합니다. 거의 한시간씩 손으로 돌리는 게 귀찮기도 하지만, 나무재질이다보니 군데군데 타들어가서 (아직 더 쓸 수는 있지만) 새로 만들기로 했습니다.


이번에는 모터를 달기로했습니다. 그리고 (별로 필요는 없을 것 같지만) 중간에 온도도 체크하고 커피 상태로 확인할 수 있도록 구멍을 내기로 했고, 그 구멍으로 한꺼번에 쏟는 방식으로 바꿀 예정입니다.


일단 그 전에 기존 자작기 들을 훝어봤습니다. 네이버 커피마루 카페 자작로스터 게시판에서 2000년 이후의 글들을 읽으면서 필요한 부분만 정리한 것입니다. 본격적인 제작기는 다음에~



재료...


원형 소켓. http://cafe.naver.com/coffeemaru/165580 (파이프 소켓으로 검색) 

          스텐소켓


교반날개 - 찜기 



전산 볼트 - 8mm 정도가 좋음



서클커터


바이메탈 온도계 (7500원) 튀김용 온도계



강화유리 창 35파이




판재 - 브라질 레드파인 집성목 - 변형에 상대적으로 강함


재료 사는 곳. devicemart.co.kr - http://cafe.naver.com/coffeemaru/87994 참조



기어드 모터 (6W 면 충분. 60RPM)

AC220 모터. 싱크러너스 모터(부화기 모터) 6와트 28회전


베어링 - 카트리지 베어링. 내열 베어링. 베어링 홀더. 유니트베어링으로 하면 스토퍼가 필요없음. 베어링 쇼핑몰에서 한꺼번에 찾아볼 것. 샤우드/커플링 까지. 세라믹 베어링

베어링 몰 - http://www.ebearing.co.kr/

베어링 쓰는법 - 덧글에서 확인 - http://cafe.naver.com/coffeemaru/152778



스텐 깔대기 -  호퍼. 곡물용. 고점도용. stainless funnel


멸치다시통 - 5호 16cm x 18cm


알루미늄 테이프 -


부싱 - 



핸들 - 핸드휠 http://www.hanats.co.kr/


커플링 - 


단열재 - 세라크울 - http://cafe.naver.com/coffeemaru/101788 

          세라믹 보드.

단열로 효율 올리기


스텐 구멍확장... 스텝 드릴 - 파이프 리머 http://cafe.naver.com/coffeemaru/102188



알루미늄 판. - 옆면은 1.5T 뚜껑은 3T


DC 모터 전후진 방법 - http://cafe.naver.com/coffeemaru/106345



탐침봉 - 샘플러 - http://itempage3.auction.co.kr/DetailView.aspx?ItemNo=B259372759&keyword=%c5%bd%c4%a7%ba%c0&scoredtype=0


http://item2.gmarket.co.kr/item/detailview/Item.aspx?goodscode=278730708&pos_shop_cd=SH&pos_class_cd=111111111&pos_class_kind=T&keyword_order=%c5%bd%c4%a7%ba%c0&keyword_seqno=8998222205&search_keyword=%c5%bd%c4%a7%ba%c0


손잡이 - 망치자루. 망치손잡이

원목옷걸이 - http://item2.gmarket.co.kr/item/detailview/Item.aspx?goodscode=644503977&pos_shop_cd=SH&pos_class_cd=111111111&pos_class_kind=T&keyword_seqno=8998487805&search_keyword=%bf%f8%b8%f1%bc%d5%c0%e2%c0%cc



=====


구매가이드 - http://cafe.naver.com/coffeemaru/65859

열풍식, 준 열풍식, 준전도식, 직화-타공드럼식


간편 스텐 통돌이 - http://cafe.naver.com/coffeemaru/110847



일체형로스터 제작방법. -http://cafe.naver.com/coffeemaru/119328

http://cafe.naver.com/coffeemaru/119332



일체형 로스터 설계자료 http://cafe.naver.com/coffeemaru/125356




참고할 만한 글


커씨로 - http://cafe.naver.com/coffeemaru/52699



초간지된장남 - 싸이클론 제작기 - http://cafe.naver.com/coffeemaru/76553

중국 소형 싸이클론 http://cafe.naver.com/coffeemaru/147984


통큰이 - http://cafe.naver.com/coffeemaru/76717



budwizer = 하이로스터 튜닝 - http://cafe.naver.com/coffeemaru/77673



초간지된장남 - 쿨러 자작기 - http://cafe.naver.com/coffeemaru/81238



알파 - 알루미늄 통돌이 - http://cafe.naver.com/coffeemaru/84592

설계도면 있음. dxf 파일. 특히 교반날개 참고할 것



진악산 - 코끼리 로스터기 - http://cafe.naver.com/coffeemaru/87092

알루미늄판재로 꺽어서 제작

리벳건/리벳못, 60방 헝겁사포. 쇠톱으로 제작



galmegi - 학교프로젝트 - http://cafe.naver.com/coffeemaru/88384

이런식으로 만들 예정임


빵쟁이 - 수동 로스터에 모터달기 - http://cafe.naver.com/coffeemaru/90750



카브리올레 - 통째로 쏟아붇는 식 - http://cafe.naver.com/coffeemaru/91015

스텐 깔대기 (헤라시보리로 제작하면 비쌈)



바리스타진 - 분석해보자 꼬마로스터!! - http://cafe.naver.com/coffeemaru/91139


꽉군 - 통돌이 개조 - 베어링 다는 법 - http://cafe.naver.com/coffeemaru/94743



주님향기 - 로스터 따라하기 2호 - http://cafe.naver.com/coffeemaru/95655



부장 - 유니온 샘플로스터 개조 -http://cafe.naver.com/coffeemaru/31526



위드마루 통돌이 1.10 - http://cafe.naver.com/coffeemaru/101756



위드마루 통돌이 누구 따라하기 - http://cafe.naver.com/coffeemaru/102108

http://cafe.naver.com/coffeemaru/102188

http://cafe.naver.com/coffeemaru/102626



mixkj 자작로스터 - http://cafe.naver.com/coffeemaru/102357

http://cafe.naver.com/coffeemaru/103967



빠삐융 - 밀폐식 나무 로스터 - http://cafe.naver.com/coffeemaru/105891

자세한 제작법 있음.



쩌로 - 쩌로분해기 http://cafe.naver.com/coffeemaru/107988



사진여행 - 독돌이 - http://cafe.naver.com/coffeemaru/149116



on1914 - 상세 자작 - 너트연결 - http://cafe.naver.com/coffeemaru/162704



하조사 - 상세가이드 - http://cafe.naver.com/coffeenarucafe/17357



Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

  1. 내용 잘 봤습니다.
    요즘 자작로스터 만드는 중이라... 결국 스텐판을 제대로 못잘라서 드릴로 구멍송송뚫어 자르는 바람에 개판되었지만.. 알루미늄판으로 해볼까 하고 검색하다 들어왔네요. 마지막에 제가올린글이 링크가 되어있어 반가움에 댓글 올립니다.
    제 글 빼고 좋은내용 감사드립니다.^^
    참.. 강화유리창은 어디서 구할 수 있나요? 링크한번 걸어주실 수 있으신지...

    2016.02.22 17:53 [ ADDR : EDIT/ DEL : REPLY ]

기타/웹 2.02015. 11. 27. 11:40

저는 구글 서비스를 많이 사용하는 편입니다. 클라우드 서비스가 본격적으로 시작되기 전.. 구글어스/구글지도로 부터 시작해서 gmail 이 1GB 제공할 때부터 본격적으로 구글 서비스를 써왔습니다. 


요즘은 훨씬 더 의존도가 높습니다. 구글 오피스... 라고까지 부르기엔 아직 많이 약하지만, 구글 스프레드시트, 구글 독스도 많이 사용중입니다. 스마트폰을 사용하면서부터는 메일/주소록/일정표 등을 모두 구글 클라우드에 동기화 시키고 있습니다.


그중 구글 드라이브도 아주 많이 사용하고 있습니다. 다음이나 네이버에서 훨씬 많은 용량을 제공해준다고 했을 때도, 고작 15GB 를 제공해주는(그것도 메일용량까지 합해서) 구글 드라이브를 사용해 왔습니다. 그런데 최근 구글포토(Google Photo) 서비스로 고해상도 사진까지 무료로 올릴 수 있게 되고, PC 자동백업도 지원되면서 이제 드롭박스 같은 서비스도 별 필요성을 못느끼고 있습니다.


지금 보니 구글포토로 백업받은 사진이 30GB 나 되네요. ㅎㅎ


하지만, 15GB는 여전히 문제입니다. 좀 큰 파일을 공유하려면 여전히 신경이 쓰이고... gmail과 공간을 공유하다보니, 가끔 보관하고 있던 메일 중에서 첨부파일 크기가 큰 것을 지워줘야 했습니다. 아래가 현재 사용중인 현황인데... 역시나 제일 많이 차지하는 게 Gmail 이네요. 그렇다고 유료용량을 쓰기는 아무래도 아깝죠.



그런데 며칠전 우연하게 구글 드라이브를 1TB까지 공짜로 사용할 수 있다는 걸 알게 되었습니다. 원래 소식은 Google Maps Official Blog 입니다. 무조건은 아니고, 일정 자격을 획득하면 평생 1TB를 무료로 사용할 수 있다는 것입니다.


간단히 이야기해서... Local Guide(지역 가이드) 프로그램에 가입을 한 후, 자기 주변에 있는 여러가지 지역 정보를 구글맵에 올려서 4레벨이 되면 1TB를 제공한다는 것입니다. 지역가이드에 가입을 하면 아래와 같은 안내문이 나타납니다.



그다음 구글지도에 들어가서 좌측 맨 위에 있는 메뉴(줄4개)를 눌러보면 아래와 같이 표시되는데 여기에서 참여를 누르면 됩니다.




그 다음엔 할일에 들어 있는 자신의 위치기록을 검토해 리뷰를 남기거나, 새로운 장소를 추가하거나, 내용이 잘못된 것을 수정하는 등의 작업을 할때마다 1점씩 올라가게 됩니다.



이런식으로 점수를 쌓으면 레벨이 올라갑니다. 아래가 기준인데, 레벨4, 즉 200점 이상이면 2년동안 구글 드라이브 용량을 1TB 무료로 제공한다고 되어 있습니다. 자세한 내용은 여기를 읽어보세요.

  • Level 1 (0 - 4 points): Enter exclusive contests (think new Google devices!) in select countries. 
  • Level 2 (5 - 49 points): Get early access to new Google products and features. 
  • Level 3 (50 - 199 points): Show up in the Google Maps app with your official Local Guides badge. 
  • Level 4 (200 - 499 points): Receive a free 1 TB upgrade of your Drive storage, allowing you to keep all the stories, photos, and videos from your travels in one safe place. 
  • Level 5 (500+ points): The very top Local Guides will become eligible to apply to attend our inaugural summit in 2016, where you’ll be able to meet other top Guides from around the world, explore the Google campus, and get the latest info about Google Maps. Look out for details early next year.

아래는 제 현황입니다. 현재 3레벨. 아이콘 오른쪽 아래에 십자 모양이 지역가이드라는 표시입니다. 현재 66점이니 134점만 더 채우면 구글드라이브가 1TB로 늘어나게 된 답니다. 



머... 주변에 잘 다니는 음식점 같은 곳에 들르면 사진을 찍은 뒤에 장소를 추가하고, 사진을 추가하고, 리뷰를 남기면 3점 정도 됩니다. 서두를 필요도 없이 천천히 하다보면 언젠간 채워지겠죠.


그런데... 2년간이라... 2년뒤에는? 어떻게 될까요? 머... 설마... 하는 기분으로 시작합니다. 


이상입니다.

Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

  1. dd

    평생 아니랍니다. 2년동안 TB 준다네요

    2015.11.30 14:49 [ ADDR : EDIT/ DEL : REPLY ]
  2. 크레닌

    2년이라고 합니다.
    https://support.google.com/drive/answer/6320721?hl=ko

    2015.12.16 14:42 [ ADDR : EDIT/ DEL : REPLY ]

기타2015. 3. 2. 13:22

To Kill a Mockingbird (Harper Lee)

앵무새 죽이기(하퍼 리)


며칠전 재미있는 기사를 읽었습니다. "1960년 7월 출간돼 4000만부 이상 팔린 ‘앵무새 죽이기’의 후속편이 발견" 되었고, 이 책을 발견한 변호사는 출간한다고 하고 정작 본인은 발간을 원하지 않는다는 내용이었습니다.


제가 별로 책을 많이 읽는 편은 아니라서 그렇겠지만, 오래전에 제목 정도만 들은 듯한 '앵무새 죽이기'라는 책이 퓰리처 상을 수상했고 4000만부 이상이 팔린 베스트셀러라는 점에 놀랐습니다. 그보다 더 놀라웠던 것은 이 속편("가서 파수꾼을 세워라(Go set a Watchman)")이 앵무새 죽이기 보다 먼저 쓰여 졌는데, 그 동안 원고를 잃어버렸다가 최근에 다시 찾았다는 것이었습니다. 아무리 하퍼 리 란 분이 평생에 책한권으로 족하다라고 했다지만, 기왕 써놓은 원고를 잃어버렸다가 다시 찾는다는 게 말이 되나 싶거든요.


또, 앵무새 죽이기는 이 '속편'속에 들어 있는 작은 에피소드에 관심을 가진 출판업자가 별도의 소설로 쓰도록 권한 결과였다고 하네요. 이 소설에 얽힌 이야기야 말로 정말 소설이지 않을까... 싶을 정도였습니다. 



'앵무새 이야기'의 공간적 배경은 앨라배마 주에 있는 메이컴이라는 가상 도시입니다. 시대적 배경은 1930년대 대공황 전후이고요. 참고로 속편(Go set a Watchman)은 시대적 배경만 20년 후인 1950년대라고 합니다. 


어린 주인공 스카웃이 오빠인 젬과 방학마다 옆집으로 놀러오는 딜과 함께 겪은 경험담을 스카웃의 입장에서 풀어내고 있습니다. 주요 사건이라면 오랫동안 칩거를 하고 있는 부 래들리를 직접 보고 싶어 집에서 끌어내려고 시도하는 과정에서 일어나는 해프닝, 그리고 질낮은 이웰이라는 백인이 자기딸을 흑인이 겁탈하였다고 고발하여 재판을 받게 하고 끝내 죽임에 이르도록 하는 이야기 정도. 대부분이 10살정도 된 스카웃이 그 동네에 살고 있는 여러 등장인물들의 생활이야기가 담겨져 있습니다. 


그런데 저는 솔직히 그다지 감명을 받지 못했습니다. "강간과 인종차별이라는 무거운 이야기를 따뜻한 시선으로 그려내고 있다"라고 평을 받고 있고, 세밀한 묘사로 그 당시의 모습이 눈에 그려질 듯 잡하지는 듯 했지만, 인종차별이 별로 실감나지 않는 저에게 그냥 단조로운 일상적인 이야기에 가깝지 않았나 싶습니다. 


4000만부 이상 팔렸다는 이유는, 아마도 미국인들이 잊고 있었던, 노예 해방이 되었으나 엄연히 인종차별은 존재했던 옛 남부 이야기에 대한 향수 때문이 아니었을까 싶었습니다. 선생님을 비롯해 대부분의 "교양있는" 중산층이면서도 흑인들에 대한 노골적인 차별을 하고 있는 이율배반적인 상황속에서, 그 많은 사람들의 우려와 미움 속에서도 살인 누명을 쓴 흑인을 끝까지 변호한 스카웃의 아버지 애티커스가 사실상의 주인공입니다. 극히 보수적인 남부의 분위기 속에서 '숙녀'로 키워야 한다는 많은 압박속에서도 딸을 합리적으로 키우고자 했던 애티커스야 말로, 노예제도, 인종차별이라는 흑역사만 존재한 것은 아니라는 것을 내세우고 싶은, 자신들의 자존심을 지켜준 영웅이 아니었을까 싶네요.


뭐... 그래도... 읽었다는 게 다행이고... 아마도 속편도 읽어보게 되지 않을까... 싶네요.


민, 푸른하늘



Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02015. 1. 2. 02:25

크롬캐스트(Chromecast)는 TV의 HDMI 포트에 연결하여 사용하는 미디어 스트리밍 기기입니다. 간단하게 말해서 PC나 스마트폰, 태블릿 등의 화면을 TV로 보내서 볼 수 있는 장비라고 생각하면 됩니다.


제가 구글 크롬캐스트를 지난 7월에 구입했으니, 벌써 6개월 정도 사용했네요. 그 당시에는 지원되는 게 많지 않았습니다. 지금은 정확히 기억은 안나지만, 안드로이드 기기의 화면은 미러링이 가능했는데, 아이폰은 잘 안되었던 것 같고, 제한없이 사용할 수 있는 건 유튜브 외 몇가지 어플 정도... 였던 걸로 기억합니다. PC 화면은 크롬 브라우저 화면만 전송할 수 있었고요.


그러니까... PC에 저장해둔 사진이나, 비디오 등을 직접 TV로 보낼 수 있는 방법은 없었습니다. 구입당시에도 미러링 기능은 향후 지원한다고 되어 있었습니다. 그런데 오늘 가족들이 모여서 노트북에 저장된 사진을 보려고 여기저기 검색하다보니, 이제는 PC 화면 전송도 거의 문제가 없는 것 같네요.



크롬캐스트 설정


크롬캐스트를 사용하려면, 먼저 약간의 설정이 필요합니다. 


먼저 크롬캐스트를 TV의 HDMI 포트에 연결하고 전원을 연결해주면 됩니다. 전원은 USB 전원을 사용하므로, TV에서 HDMI와 USB를 모두 지원할 경우, 아래처럼 연결해 주면 간단합니다. USB가 없을 경우엔 크롬캐스트 구입시 포함된 외부전원코드를 사용하면 됩니다.



그 다음, 스마트기기에 크롬캐스트 앱을 설치해야 합니다. 설치하는 방법은 기기에 따라 다르겠지만, 안드로이드의 경우엔 구글 Play 스토어, iOS의 경우엔 앱스토어에서 다운 받으면 됩니다.


PC에서는 먼저 chrome browser를 설치한 후, 아래와 같이 Google Cast 라는 확장 프로그램을 설치하면 됩니다.



그 다음엔 크롬캐스트를 설정하는 절차가 필요하지만, 크롬캐스트 앱을 실행하고 시키는대로만 따라 하면 전혀 어렵지 않습니다. 자세한 내용은 구글링 해보시길....


안드로이드 화면 미러링


크롬캐스트를 통해 TV로 화면을 보내는 방법은 모바일 앱 또는 Web용 App에서 화면을 전송하는 방법과, 화면 전체를 미러링 하는 방법이 있습니다. 먼저 안드로이드 기기의 화면을 전체를 미러링하는 방법입니다. 


안드로이드에서 크롬캐스트를 통해 TV로 화면 전체를 보내려는 경우, 화면을 미러링하도록 명령을 내려야 합니다. 다만, 제작회사나 안드로이드 버전에 따라 약간씩 다르기 때문에 아래에 있는 여러가지 방법 중 어떤 것이 적합한지 알아보셔야 합니다.


첫번째, 설정 - 디스플레이 에 들어가면 맨 아래에 화면전송이 나타나는데요, 이걸 클릭하면 크롬캐스트 목록이 나타나고 이걸 클릭해주기만 하면 됩니다. (갤럭시 S3에서 확인)


두번째, 더 간단하게 설정하는 방법이 있습니다. 넥서스 7의 경우에는 아래와 캡처사진과 같이 화면을 끌어내리면 크롬캐스트 기기명이 보이는데, 이걸 클릭만 해주면 그때부터 안드로이드 화면이 바로 TV로 나오게 됩니다. 



또, 크롬캐스트 앱을 실행시킨 후 메뉴를 누르면 아래와 같이 화면 전송메뉴가 있어, 이를 누르면 화면이 전송됩니다.



이 기능을 사용하면 게임같은 걸 대형화면에서 즐길 수 있고... 특히 화면 조정이 필요없이 좌우로 기울여서 조정하는 게임이라면 실감나게 즐길 수 있습니다. 다만, 네트워크 상황 등에 따라 화면 지연이 발생할 수도 있습니다.


아이폰의 경우에도 크롬캐스트를 설치하면 맨 아래에 있는 방법으로 화면을 미러링 할 수 있을 듯 하지만, 제가 테스트를 해볼 수 없어 생략합니다. 저에게 있는 아이폰 계통 기기는 아이패드1 뿐이거든요. ㅎㅎ


앱 화면 전송


크롬캐스트를 지원하는 앱을 통해 앱의 화면을 TV로 보내는 방법입니다. (안드로이드 버전이 낮은 경우엔 이처럼 화면 전체를 미러링하는 방법이 없어 이 방법만 가능합니다.)


다음은 유튜브 화면인데, 오른쪽 위에 있는 아이콘을 눌러주면 유튜브 화면이 TV로 전송됩니다. (이 아이콘이 나타나지 않을 경우, 설치해둔 크롬캐스트앱을 실행하여, 크롬캐스트와 연결해주면 됩니다.) 다만, 스마트 기기에선 화면이 완전히 꺼져버리고, TV에서만 나오게 됩니다. 스마트 기기에서는 빨리보기/일시 정지 등 영상 조정만 가능합니다.



다음은 사진(photo) 어플을 시행한 모습입니다. 여기에서도 크롬캐스트 아이콘을 클릭해주면 화면이 TV로 전송됩니다.



그리고 다음은 기타 크롬캐스트를 지원하는 앱들입니다. 여기 들어가보시면 확인할 수 있습니다. 처음에는 몇가지 되지 않았는데, 지금은 꽤 많이 늘어났습니다.



이렇게 앱에서 크롬캐스트를 직접 지원하는 경우에도 원한다면 앞서 설명한 화면 미러링을 통해 TV로 송출할 수도 있습니다. 그렇지만 가급적 앱에서 직접 연결시키는 게 좋습니다. 서버->스마트기기->TV 로 연결되는 게 아니라, 서버에서 TV로 직접 연결되기 때문에 속도도 차이가 나고 해상도도 더 높기 때문입니다. 아울러, 스마트 기기에서는 화면이 정지되므로, 배터리가 덜 소모되는 장점이 있습니다.


즉, 아래 그림처럼, 처음에는 스마트기기에서 접속을 하지만, 일단 미디어를 선택하면 그 다음부터는 클라우드 서버로부터 직접 전송받는 방식입니다.



크롬브라우저 화면 전송


PC의 화면을 크롬캐스트(Chromecast)를 사용해서 TV로 보내려면, 반드시 크롬 브라우저가 필요합니다. 


크롬 브라우저를 설치한 후에는 크롬캐스트 확장프로그램을 설치해야 합니다. 설정-확장프로그램 으로 들어간 후, 맨 아래에 내려가 더 많은 확장프로그램 다운로드로 들어간 후 아래와 같이 검색하여 설치하시면 됩니다.



이 확장 프로그램을 설치하면 크롬브라우저 오른쪽 위에 아래와 같이 크롬캐스트 아이콘이 추가됩니다. 이 아이콘을 누르면, 현재 탭의 화면이 TV로 전송됩니다. 




이때, 크롬브라우저 내에서 유튜브와 같이 크롬캐스트를 직접 지원하는 경우에는 PC의 화면은 꺼져버리고 유튜브와 PC가 직접 연결이 됩니다. 


PC 화면 미러링


이제 마지막입니다. 원래 구글이 크롬캐스트를 발매할 때에는 PC화면 전체를 TV로 미러링하는 기능은 없었습니다. 그런데 최근에 가족이 모두 모여, 노트북에 들어 있는 사진을 TV로 가족이 함께 보는 방법을 고민하다가 최근에 이 기능이 활성화된 것을 알아냈습니다. 


아래와 같이 크롬브라우저에서 크롬캐스트 아이콘을 클릭한 뒤, 오른쪽 위에 있는 삼각형을 누른 후 "전체 화면 전송 (실험용)"을 누르면 됩니다. 그러면 컴퓨터 화면에 나오는 모든 화면이 TV로 전송되게 됩니다.



물론, 이 방법은 여러가지 문제가 있을 수도 있습니다. "(실험용)" 이랍니다. 그리고 전송속도가 약간 늦은 편이라서 화면이 약간 끊기는 듯 느껴집니다. 그리고 컴퓨터에서도 화면과 소리가 나오고, TV에서도 화면과 소리가 나오며, 약간의 시차까지 있어서 불편하기도 합니다. 


하지만, 이 방법을 사용하면 PC에 저장된 미디어를 거실에 있는 가족들과 함께 공유하는데는 아주 쓸만합니다. 몇 년전만해도, 그래픽카드에서 선을 뽑아 TV로 연결하거나, 별도의 전용기기를 구입했었는데, 이제는 작은 동글하나로 해결이되네요. ㅎㅎㅎ 


PC에 저장된 영화보기


마지막입니다. PC에 다운로드 받은 영화를 TV에서 보는 방법입니다. 물론 바로 위에서 설명한 미러링 방법을 사용해서도 영화를 볼 수 있지만, 화면이 약간 지연되고, 끊기는 등의 문제가 있어, 특히 속도가 빠른 영화는 마음 푹놓고 감상하기 힘듧니다. 그리고 중간에 잠깐 쉬었다 보고 싶거나 빨리 돌리거나... 등등의 조절이 필요한 경우, PC 앞까지 가야만 합니다.


이때, Zimly 라는 어플을 사용하면 훨씬 편하게 감상할 수 있습니다. 다만, 이 어플을 사용하려면, PC 와 TV 외에도 안드로이드 기기가 하나 더 있어야 합니다. 이때, PC는 서버가 되고, 안드로이드 기기는 콘트롤러가 된다고 생각하면 됩니다.


원래 글에는 Zimly라는 어플을 사용해서 편리했었는데, 이제는 홈페이지까지 사라졌네요. 우리나라 기업이 만들었던 것 같은데, 그래서 더욱 안타깝습니다. 그래서 대안으로 VideoStream이라는 크롬앱을 사용하는 방법을 알려드립니다.


먼저 아래와 같이 Chrome 웹 스토어에 들어가서 videostream이라고 검색을 해서  VS Launcher를 설치합니다.



그러면 크롬 브라우저 오른쪽 위에 다음과 같은 아이콘이 새로 설치됩니다.



이 아이콘을 누르면 아래와 같이 https://getvideostream.com/ 사이트로 이동됩니다.



이제 파란색 [Get Streaming]을 누르고 VideoStream 어플을 설치해줍니다.(자세한 사항은 생략합니다.)  바탕화면에 있는 아이콘이나 크롬브라우저 오른쪽 위에 있는 아이콘을 누르면 아래와 같은 화면이 나오게 됩니다. 이제 다운로드 받은 영화를 크롬캐스트를 사용해서 TV에서 볼 수 있게 되었습니다.



가운데 있는 파란색[Choose a Video] 버튼을 클릭하면 아래와 같은 화면이 나오는데, 여기에서 영화파일을 선택해 줍니다. (한글이 깨지네요. ㅠㅠ)



여기에서 원하는 파일을 선택하고 크롬캐스트를 연결하면 TV에서 영화가 나옵니다. 다만 이때 문제가 있습니다. VideoStream은 한글 자막파일에 많이 사용되는 .smi 파일을 지원해주지 않는다는 것입니다. 그래서 .smi 파일을 .srt 포맷으로 변경시켜주어야 합니다. 저는 아래에 있는 smi2srt.exe 를 사용해서 변환합니다. 이 파일을 .smi 파일이 있는 폴더에 넣어준 후 더블 클릭하면 자동으로 변환해 줍니다.


smi2srt.exe


그런데... 기본적으로 영화파일명과 자막파일명을 일치시키면 자동으로 자막을 사용해야 할 것 같은데, VideoStream은 그러지 않아서 별도로 읽어 들여야 합니다. (무슨 이런 개같은 프로그램이... ㅠㅠ) 아래에서 화살표에 있는 아이콘을 클릭하여...



아래와 같이 [Add External Subtitle File]을 눌러 .srt 파일을 선택하면 됩니다. 만약 글씨가 깨져 나오면 그 바로 위에 있는 인코딩을 바꿔줘야 하고요. 한글 자막은 대부분 Korean(EUC) 로 되어 있을텐데, 아니면 Unicode로 설정하면 문제가 없을 겁니다.


그리고... 구글플레이에서 VideoStream 이라고 검색해보면 안드로이드용 앱도 있는데, 이걸 사용하면 PC에 왔다갔다 하지 않아도 TV 앞에서 제어할 수 있습니다. 참고하세요.


이상입니다. 부디... 도움이 되시길...


민, 푸른하늘


아래는 예전에 쓴 글인데 혹시나해서 남겨둡니다.


먼저 PC 웹브라우저에서 Zim.ly에 접속합니다. 오른쪽 위에 있는 "Downloads"를 누르고 "Streamer for Windows"를 눌러 설치해줍니다. 맥용 프로그램도 있네요.



Zimly 의 설치가 끝나면, 아래와 같이 시스템 트레이로 들어가게 됩니다. 



이 아이콘을 클릭하면 먼저 아래와 같은 로그인 창이 뜹니다. PC와 다른 스마트 기기를 연결하기 위한 목적입니다. PIN 번호를 입력해서 연결할 수도 있고 페이스북을 통해 연결할 수도 있지만, 저는 Google+ 로 연결했습니다. Google에 로그인되어 있는 상태라면 아래와 같이 동의 버튼만 눌러주면 연결됩니다.



다음은 서버관리화면입니다. 처음에는 빈화면이 나올텐데, 오른쪽 아래에 있는 "+" 아이콘을 누르면 폴더추가 화면이 뜨고, 여기에서 영화가 들어있는 폴더를 선택하고 "추가"버튼을 눌러주면 됩니다. 이렇게만 해주면 서버의 설정은 완료됩니다.



그 다음 안드로이드 기기(또는 iOS 기기)를 설정합니다. 플레이스토어에서 Zimly를 검색해서 설치합니다. 그 뒤 Zimly를 실행하고, 서버와 연결해줍니다. 아래 제일 좌측이 연결화면인데, PC에서 로그인할 때와 동일한 방식을 사용하면 서로 연결이 됩니다.


연결이 완료된 후, 폴더를 찾아 들어가면, PC와 Storage가 나오는데, PC는 바로 위에서 공유한 폴더가 나타나고, Storage는 스마트기기내에 들어 있는 미디어를 찾아 실행 시킬 수 있습니다.



이제 원하는 파일을 실행시키면 해당 동영상을 스마트폰에서 볼 수 있습니다. 이 상태에서 크롬캐스트 아이콘을 클릭하면 TV에 화면이 전송되고요. (스마트기기의 화면은 꺼집니다.)


이상입니다. 부디... 도움이 되시길...


민, 푸른하늘

Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

  1. 크롬캐스트 이용자

    크롬캐스트 사용법에 관한 최고의 설명이었습니다.
    도움이 많이 됐습니다. 감사합니다.

    2015.04.04 04:47 [ ADDR : EDIT/ DEL : REPLY ]
  2. 김화영

    정말 잘 정리된 자료 너무 잘 보았습니다. 마지막 어플은 참 유용할듯 합니다.

    2015.05.04 21:33 [ ADDR : EDIT/ DEL : REPLY ]
  3. 잘읽었습니다.
    옥션에 주문해놨는데 기대됩니다.^^
    영화천국앱 영화도 끊어짐 볼수있겠지요?

    2015.05.17 09:06 [ ADDR : EDIT/ DEL : REPLY ]
  4. mozzi

    크롬캐스트가 이렇게 유용할 줄 몰랐네요. 이 설명 못봤더라면 한달안에 중고처분할 뻔 했어요ㅎㅎ
    마지막 앱은 크롬캐스트 뿐만 아니라 스마트폰으로 스트리밍하는거라 엄청 유용하게 쓸것같아요. 감사합니다!!

    2015.05.30 21:20 [ ADDR : EDIT/ DEL : REPLY ]
  5. 안개소리

    그동안 짐리 쓰다가, 잠깐 뒤로 돌려보고 싶을 때 불편해서 다른 방법 찾고 있었는데 마침 전체 화면 전송 안내가 있네요. 저한테는 짐리 정보보다 이게 더 유용한 정보였습니다. 감사합니다.
    개인적인 바람은 동영상 플레이어에서 직접 크롬캐스트로 보내는 기능이 있으면 좋을 것 같구요, 아니면 크롬의 전체화면 전송 기능이 속도가 빨라져도 될 것 같구요.

    2015.06.18 12:41 [ ADDR : EDIT/ DEL : REPLY ]
  6. 지나가다가..


    지니가다가... 몇 가지 정보 추가로 적어봅니다.

    동영상 플레이어에서 직접 크롬캐스트로 영상을 송출한다는 것은.. 특히.. 고화질의 경우는
    아직까지는 좀 힘들다고 할 수 있습니다.
    이 부분을 이해하기 위해서는 크롬캐스트 작동 원리를 알아야 하는데..

    예를 들어 PC 또는 스마트폰에서 보는 유투브 영상을 크롬캐스트를 통해 TV로 출력하는 것은...
    실시간으로 PC or 스마트폰의 화면을 크롬캐스트로 쏴주는 것이 아니라...
    이미 인터넷상에 존재하는 스트리밍 파일(유투브 영상의 원래 저장 주소)을 크롬캐스트가 받아와서 출력을 해주는 원리입니다.

    이게 왜 문제가 되는가 하면...
    물론.. PC 또는 스마트폰 화면도 TV 출력이 가능하기는 한데...
    그런것들을 지원하는 대부분의 프로그램은...

    현재 나의 PC 또는 스마트폰의 화면은 스트리밍 파일이 존재하지 않음으로..
    1. 나의 PC 또는 스마트폰 화면을 인터넷상의 임의의 장소에 계속 업로드 시키면서..
    스트리밍 원본 파일을 만들어 주고...
    2.크롬캐스트는 다시 인터넷상에 우리가 업로드가 하고 있는 스트리밍을 다시 다운 받아와야 합니다.

    이게 왜 문제가 되냐면...
    유투브의 경우에는 인터넷상에 이미 존재하는 스트리밍 영상의 주소로 단순히 다운 만 받으면 되는데...
    우리의 PC 또는 스마트폰 화면을 TV에 출력하는 경우에는 PC에서 실시간 업로드 및 동시에 크롬캐스트에서 다시 다운로드의 과정이 이루어져야 하기 때문에.. 급격히 속도가 저하됩니다...
    아시다시피... 기본적으로 크롬캐스트와 TV or 스마트폰은 같은 Wifi에 물려야 하는 제약도 존재하기 때문에... 속도 저하가 생각보다 큽니다.

    물론 인터넷 속도가 충분하다면 얼마든지 동기화가 가능합니다만...
    제가 현재까지 해본 바로는 완전 시간차 없이 보는 것은 불가한 상태이고...
    고화질의 경우에는 중간중간 버퍼링이 발생하게 됩니다...

    저 같은 경우에도 상세 작동 원리를 몰라서...
    가끔 스마트폰 게임이라던지... 화면이 답답하면 TV에 쏴서 해야지 했었는데...
    그런 정도로는 아직 불가한 상태더군요...
    물론 기타 TVing 같은 어플을 통해서 영화를 보거나 할때는... Youtube 작동과 같은 원리이기에 렉 없이 시청이 가능합니다만.... 혹시나 좀 헷갈려서 구매 후에 후회 하시는 분이 있으시지 않을까 하여 정보 공유드립니다..

    2015.08.21 00:33 [ ADDR : EDIT/ DEL : REPLY ]
  7. 추가로 다가...

    음.. 그리고 PC or 스마트폰 화면 실시간 미러링의 경우.. 한가지 문제가 존재하는데...
    인터넷 임의의 저장공간에 자기 화면을 실시간으로 업로드 하는 것과 같다고 위에서 말씀드렸는데..
    이는 반대로 말하면 누군가가 그 주소를 획득한다면 본인의 PC or 스마트폰 화면이 다른 사람에게도 실시간으로 전송될 가능성도 존재합니다...

    이런 특성이 안드로이드 계열 vs. 아이폰 계열에서 확실히 차이를 보이는데...
    기본적으로 아이폰 계열은 크롬캐스트 공식 어플에서는 전체화면에 대한 실시간 스트리밍을 지원하지 않습니다... 아이폰 계열은 오픈소스를 정책으로 택하지도 않거니와 굉장히 폐쇠적인 환경을 가지고 있는데.. 아무래도 답답함이 있긴 합니다만... 반대로 말하면 보안에 있어 위험이 될 만한 요소는 애시당초 차단을 하기 때문입니다... 안드로이드 계열은 오픈소스를 지향하기 때문에... 사용 편의성을 극대화하지만... 대신 보안에 대한 책임 또한 본인에게 맡겨놓는 분위기 이죠...

    어찌되었든...이런 내용도 조금은 알고 있는 상태에서 사용을 하시는 것이 좋을 것 같습니다.

    2015.08.21 00:41 [ ADDR : EDIT/ DEL : REPLY ]
  8. 신입회원

    정말로 감사합니다...뭐라고 드릴말씀이 없어요^

    2015.09.20 08:29 [ ADDR : EDIT/ DEL : REPLY ]
  9. 왕초보

    크롬카스트를 처음 사서 막막했는데 이렇게 자세하게 설명해주시니 눈이 확뜨입니다
    저같은 초보도 다 이해하도록 설명해주는 당신은 대단한 고수십니다. 감사합니다. ^^

    2016.02.14 00:36 [ ADDR : EDIT/ DEL : REPLY ]
  10. red811

    안녕하세요 ㅜㅜ저같은경우에는
    pc에서 스마트빔으로 영상쏠려고하는데
    이게 유선연결이 안돼서 ㅜㅜ
    팁뷰어로 봤는데 20분 돌고 튕기더라구요
    좋은방법없을까요?
    빔프로젝터는 안드로이드가 깔려있어서 폰으로 생각하시면돼요
    미러링 어플있음 좋을텐데 ㅠㅠ

    2018.03.29 19:09 [ ADDR : EDIT/ DEL : REPLY ]

기타/웹 2.02014. 7. 23. 10:26

다시 책한권을 사서 새로 공부하기 시작했습니다. 이번에는 PHP, MySQL, JavaScript, CSS, HTML5가 모두 들어 있는 책입니다. 물론 입문서겠죠. 


저는 웹기술이 본격적으로 도입될 즈음 프로그램에서 손을 떼고, 현재의 분야로 옮겼기 때문에 사실 웹쪽이 어떻게 발전되어 왔는지 거의 모르고 있었습니다. 그래서 제가 이전에 시험삼아 개발한 kmap_geocaching 사이트도 거의 Javascript로만 구현되어 있습니다. (물론 다른 부분들도 조금씩 포함되어 있기는 하지만요.)


그런데, 이 책을 사서 개요부분을 읽어보니 정말 순서가 잘못되었다는 걸 깨닫게 되었습니다. 서버쪽과 클라이언트쪽을 동시에 다루어야 하는데, 저는 클라이언트쪽만 공부한 셈이었죠. 



아무튼... 이 모든 기술을 좀 더 이해하기 위해서는 제 PC 쪽에 서버를 설치해 두는 게 좋겠다... 싶어서 이책 2장에 나온대로 Zend Server를 설치했습니다. 그 과정은 사실 어려울 건 없는데, 중간에 막히는 바람에 몇시간 고생을 한게 아까와서 좀 정리를 해두려고 합니다.


우선 Zend Server는 웹개발에 필수적인 서버를 구성하기 위한 WAMP(Windows, Apache, MySQL and PHP")의 일종입니다. Mac의 경우엔 MAMP, Linux의 경우엔 LAMP라고 한답니다. 이런 구성요소들을 각기 따로 설치할 경우, 환경을 맞춰주는 작업이 복잡할 수 밖에 없는데, 이것들을 한꺼번에 모아서 하나의 패키지인 것처럼 설치하는 겁니다.


어쨌든 설치방법...

1. Zend Website 에서 무료버전을 다운로드 받는다. 



2. 설치시작.... 설치방법은 http://hyeonstorage.tistory.com/56 참조 

제가 설치한 버전은 7.0.0 이지만, 설치방법은 거의 비슷합니다.


3. 에러 수정

설치가 완료되면, 기본 웹브라우저가 뜨고 http://localhost:10081/Zendserver 로 연결되고, 여기에서 추가적으로 몇가지를 설정해야 하는데, 그냥 아래와 같은 에러만 발생합니다. 아마도 Windows가 한글버전이기 때문이지 않을까 싶습니다만...



어쨌든 이 현상을 확인하기 위해 제가 Zend Server를 설치한 폴더에서 에러 로그 파일(C:\Program Files (x86)\Zend\Apache2\logs )을 확인해 보면...


[Tue Jul 22 17:09:33 2014] [error] Zend Enabler cannot load because of a problem in its configuration file: XML parse error on line 1 column 1 - invalid byte '?' at position 3 of a 3-byte sequence


이러한 에러가 발생했다고 나타납니다. 설정파일(XML)이 잘못되었다는 겁니다. 이 설정 파일은 C:\Program Files (x86)\Zend\ZendServer\etc 에 들어 있는 ZendEnablerConf.xml 파일입니다. 


표시된 것처럼 첫줄에 이상한 문자가 들어 발생하는 문제입니다.여기에서 첫줄을 아래와 같이 고쳐주면 됩니다. 단, 수정하려면 관리자 권한이 필요할 수 있습니다.

<?xml version="1.0" encoding="UTF-8" ?>

 

4. 재부팅

그런데 이 파일을 수정하고 http://localhost:10081 를 실행해봐도 동일한 Internal Server Error 가 발생합니다. 사실 그때문에 고생을 많이 했죠... 이미 잘못된 설정으로 Zend Server 가 실행중이기 때문입니다. 따라서 재부팅을 시켜주면 문제가 해결됩니다.


최종적으로 아래 화면이 뜨면 완료!



====

대충대충 썼네요. 참고하세요.


민, 푸른하늘

Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

  1. 장병진

    EditPlus에서 처음에 이상한 문자가 생기는 것은 아마도 EditPlus가 BOM(Byte Order Mark[1])을 잘 해석하지 못해서 일 것입니다.
    이런 문제 때문에 저는 Notepad++[2]를 사용합니다. 빠르고 문법에 따른 컬러코딩도 잘되고, 무엇보다 한글 Code Page를 기가 막히게 판단합니다. 저는 개발팀에 한국인이 있다고 확신합니다. 단점은 FTP로 서버의 파일을 편집하는 기능이 EditPlus에 비하면 불편합니다.

    [1] http://blog.wystan.net/2007/08/18/bom-byte-order-mark-problem
    [2] http://notepad-plus-plus.org/

    2014.07.31 11:16 [ ADDR : EDIT/ DEL : REPLY ]
    • 흠... 제가 잘 이해가 안됩니다만... 이건 EditPlus 문제가 아닌 건 확실합니다. 다른 분들도 모두 이런 증상을 호소하거든요. 아무튼 감사합니다. 배워야 할 게 너무 많다는 것만 뼈저리게 느끼고 있습니다.

      2014.08.04 19:21 신고 [ ADDR : EDIT/ DEL ]
  2. wamp

    안녕하세요

    wamp server 문의 좀 드리려구요~~

    서버에서 윈도우에 php로 데이터베이스는 mysql을 쓰고, apache를 세팅을

    한 후 wamp server를 설치 해서 실행만 하면, 이상하게도 28-365365.com

    사이트에 로그인이 안되요~~ ㅜㅜ


    (bet365사이트는 플래쉬로 제작된 것 입니다.) 다른 개발자들이 만든 환경에서는

    모두 정상적으로 bet365에서 운영하는 virtual sports에 있는 가상축구와 개경주 등

    경기 배당(팀이름) 및 경기결과 값 등을 자동으로 잘~~ 뽑아오고 있는데...

    저는 몇 일째 이 문제로 고생하고 있습니다.


    ~~ 질 문 ~~~

    1. bet365.com (한국 접속 도메인주소 28-365365.com)에서 virtual sports에서

    3분마다 진행되는 가상축구(Soccer)와 개경주(Goldenhill Park) 경기 팀이름

    / 배당(Decimal) 및 경기결과 값 등을 자동으로 뽑아 올 수 있 방법~~????

    2. php에 데이터베이스는 mysql을 쓰고, apache로 세팅을 한 후에 28-365365.com

    에 로그인이 잘 되는데, wamp server를 설치 해서 실행만 하면, 이상하게도

    28-365365.com 사이트에 로그인이 안되는 이유~~????


    혹시 wamp server 와 호환할 수 있는.... 다른 프로그램을 깔아야 하는건지????

    아니면 설정을 어떻게 잡아야 하는 건지????

    바쁘시겠지만, 아시면 알려주시길 바랍니다. 꼭~~ 부탁드릴께요~~~

    제 이메일은 : totosale89@naver.com 입니다.

    2015.06.29 15:16 [ ADDR : EDIT/ DEL : REPLY ]

기타/웹 2.02014. 6. 26. 16:24

이제 PHP 투토리얼 시리즈 마지막입니다. AJAX네요. 어차피 클라이언트와 데이터를 주고 받으려면 AJAX를 제일 많이 쓰지 않을까... 하는 생각이 듭니다. 써봐야 알겠지만요.


AJAX의 개념


  • Asynchronous Javascript and XML
  • 빠르고 동적인 웹페이지를 만드는 기술
  • 서버간에 작은 데이터만 교환하면서 웹페이지가 비동기적으로 갱신되도록. 즉, 화면의 일부만 갱신 가능
  • GoogleMaps, Gmail, Youtube 등이 모두 AJAX 활용
  • AJAX는 인터넷 표준에 기초함
    • XMLHttpRequest (데이터를 비동기적으로 서버와 주고 받음)
    • Javascript/DOM (정보의 표현)
    • CSS (데이터 스타일)
    • XML (데이터 전달 포맷)
<html>
<head>
<script>
function showHint(str) {        // key를 하나씩 누를때마다 실행됨
  if (str.length==0) { 
    document.getElementById("txtHint").innerHTML="";    //공백일 경우, 힌트도 공백으로
    return;
  }
  var xmlhttp=new XMLHttpRequest();
  xmlhttp.onreadystatechange=function() {        // 상태가 변할때 실행될 함수를 등록
    if (xmlhttp.readyState==4 && xmlhttp.status==200) {
      document.getElementById("txtHint").innerHTML=xmlhttp.responseText;
    }
  }
  xmlhttp.open("GET","gethint.php?q="+str,true);    // GET 모드로 호출
  xmlhttp.send();
}
</script>
</head>
<body>

<p><b>Start typing a name in the input field below:</b></p>
<form> 
First name: <input type="text" onkeyup="showHint(this.value)">
</form>
<p>Suggestions: <span id="txtHint"></span></p>

</body>
</html>


AJAX 와 MySQL


  • AJAX를 사용하여 데이터베이스와 대화식으로 통신
  • html 파일

<html>

<head>

<script>

function showUser(str) {        // user를 선택했을 때 실행되는 함수

  if (str=="") {

    document.getElementById("txtHint").innerHTML="";

    return;

  } 

  xmlhttp=new XMLHttpRequest();

  xmlhttp.onreadystatechange=function() {      // 상태변경시 실행되는 함수 등록

    if (xmlhttp.readyState==4 && xmlhttp.status==200) {

      document.getElementById("txtHint").innerHTML=xmlhttp.responseText;

    }

  }

  xmlhttp.open("GET","getuser.php?q="+str,true);  // GET 모드로 호출

  xmlhttp.send();

}

</script>

</head>

<body>


<form>

<select name="users" onchange="showUser(this.value)">      // 폼 요소 생성. 

<option value="">Select a person:</option>

<option value="1">Peter Griffin</option>

<option value="2">Lois Griffin</option>

<option value="3">Joseph Swanson</option>

<option value="4">Glenn Quagmire</option>

<option value="5">민 허</option>

</select>

</form>

<br>

<div id="txtHint"><b>Person info will be listed here.</b></div>    // 여기에 표시됨.


</body>

</html>

  • PHP 파일

<?php

$q = intval($_GET['q']);        // integer 로 받음.


$con = mysqli_connect('localhost','id','password','db_name');  // 데이터베이스 연결

if (!$con) {

  die('Could not connect: ' . mysqli_error($con));

}


mysqli_select_db($con,"Persons");        // 테이블 선택    

$sql="SELECT * FROM user WHERE id = '".$q."'";        // id 를 기준으로 선택 (1...5)

$result = mysqli_query($con,$sql);        // query 결과는 $result


echo "<table border='1'>

<tr>

<th>Firstname</th>

<th>Lastname</th>

<th>Age</th>

<th>Hometown</th>

<th>Job</th>

</tr>";


while($row = mysqli_fetch_array($result)) {        // $result 를 배열로 변환

  echo "<tr>";

  echo "<td>" . $row['FirstName'] . "</td>";

  echo "<td>" . $row['LastName'] . "</td>";

  echo "<td>" . $row['Age'] . "</td>";

  echo "<td>" . $row['Hometown'] . "</td>";

  echo "<td>" . $row['Job'] . "</td>";

  echo "</tr>";

}

echo "</table>";


mysqli_close($con);

?>


AJAX XML


  • form에서는 거의 동일함. PHP에서 XML을 처리하는 방법만 차이남
  • XML을 직접 처리하는 방법은 많이 까다로워서... 생략
  • 차라리 XML 그 자체를 반환한 후, 클라이언트 쪽에서 JQuery로 처리하는 게 나을 듯


AJAX Live Search


  • 실시간으로 XML에서 검색하여 존재하는 것을 모두 보여주는 방식
  • 키보드를 누를때마다 계속해서 검색 결과가 바뀜





















Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02014. 6. 26. 11:45

다섯번째는 XML. 


XML Expat Parser


  • XML Parser는 두가지 종류가 있음
    • Tree 기반 parser : XML 문서를 트리구조로 변환, 문서 전체를 분석하고, 트리의 각 요소에 접근. DOM(Document Object Model)
    • Event 기반 parser : XML 문서를 이벤트의 연속으로 봄. 특정 이벤트가 발생하면 그와 연결된 함수를 호출하는 방식. 문서의 구조보다 내용에 집중. 더 빠르다. XML 구조에 문제가 있어도 문제없음. 
  • Expat Parser는 Event 기반 parser임. PHP 웹 어플에 최적
  • Expat Parser는 PHP 에 내장되어 있음


XML DOM


<!--?xml version="1.0" encoding="UTF-8"?-->

<from>Jani</from>

  • 레벨 1 : XML document
  • 레벨 2 : Root element : <from>
  • 레벨 3 : text element : "Jani"


SimpleXML


  • PHP5에서 새롭게 등장
  • XML 요소의 이름과 text를 간단하게 추출
  • 코드를 간단하게 짤 수 있음
  • XML 문서를 객체로 변환함
    • 요소는 SimpleXMLElement 객체의 속성(attribute)로 변환됨. 어느 레벨에 여러개의 요소가 있을 경우 배열에 들어가게 됨
    • 속성은 associative 배열로 접근가능 (index가 attribute의 name)
    • 요소의 text는 문자열로 변환됨. 여러개의 text 노드가 있을 경우, 순서대로 배열됨
  • SimpleXML은 XML파일로부터 데이터를 읽거나 추출하거나, 텍스트 노드/속성을 편집할 때 빠르고 간단하게 수행가능
  • 복잡한 XML의 경우, Expat이나 DOM을 사용하는 것이 나음


















Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02014. 6. 24. 17:06

이제 4번째네요... PHP로 할 수 있는 게 정말 다양하다는 걸 다시한번 느꼈습니다. 그리고... 그냥 javascript면 대충 해결되겠지... 라고 생각했는데... 참으로 거시기하네요. 오히려 웹앱을 개발하려면 서버측 개발이 더 중요한데 말이죠.


MySQL  개요


  • MySQL은 웹에서 사용되는 DBMS. 서버에서 수행됨. 크기에 관계없이 사용가능. 
  • 빠르고, 신뢰성 높고, 사용하기 쉬움. 표준 SQL의 지원, 다양한 platform 지원, 무료
  • Oracle에서 개발 보급. 이름은 공동개발자의 딸의 이름(My)를 따서 지음
  • 특히 MySQL + PHP 를 하면 cross-platform 으로 매우 유용함
  • MySQL을 어떻게 사용하는가는 SQL을 얼마나 잘 할 수 있는가에 달려있음.


MySQL 서버에 접속


<?php

$con = mysqli_connect("example.com", "peter", "abc123", "my_db");

// host, username, password, db_name

if (mysqli_connect_errno()) {

echo "Failed to connect to MySQL. : " . mysqli_connect_errno();

}


....


mysqli_close($con);

?>



Create DB / Create Table


  • cafe24 호스팅의 경우, 새로운 DB를 생성할 수 없음. 기존의 DB를 사용해야 함. 
  • 기존 DB 명은 사용자id와 동일


....

$sql = "CREATE DATABASE my_db";

if(!mysqli_query($con, $sql) {

echo "Error creating DB : " . mysqli_error($con);

} else {

echo "Successful";

}


$sql ="CREATE TABLE Persons(

PID INT NOT NULL AUTO_INCREMENT,     //

PRIMARY KEY(PID),                                // PID를 primary key!

FirstName CHAR(30), 

LastName CHAR(30), 

Age INT)";


if(!mysqli_query($con, $sql) {

echo "Error creating Table : " . mysqli_error($con);

} else {

echo "Successful";

}



Insert a row


  • INSERT INTO table_name VALUES (value1, value2, value3,...)
  • INSERT INTO table_name (column1, column2, column3,...) VALUES (value1, value2, value3,...)

  • 데이터 입력을 받는 폼

<html>

<body>


<form action="insert_data.php" method="post">

Firstname: <input type="text" name="firstname"><br />

Lastname: <input type="text" name="lastname"><br />

Age: <input type="text" name="age"><br />

<input type="submit">

</form>


</body>

</html>


  • 실제로 Table에 입력해 주는 php

<?php

$con=mysqli_connect("localhost","id","pw","dbname");

// Check connection

if (mysqli_connect_errno()) {

  echo "Failed to connect to MySQL: " . mysqli_connect_error();

}


// 폼에서 입력된 항목을 SQL INJECTION 을 방지하기 위해 escape 처리

$firstname = mysqli_real_escape_string($con, $_POST['firstname']);

$lastname = mysqli_real_escape_string($con, $_POST['lastname']);

$age = mysqli_real_escape_string($con, $_POST['age']);


$sql="INSERT INTO Persons (FirstName, LastName, Age)

VALUES ('$firstname', '$lastname', '$age')";


if (!mysqli_query($con,$sql)) {

  die('Error: ' . mysqli_error($con));

}

echo "1 record added";


mysqli_close($con);

?>



Read Data from MySQL


  • mysqli_query()를 사용하여 SELECT 문을 사용하면 데이터를 읽을 수 있음
  • mysqli_fetch_array를 사용하면 한 record 씩 배열로 받아짐.
  • 그 결과를 html로 표현함.

<?php

$con=mysqli_connect("localhost","id","pw","db_name");

// Check connection

if (mysqli_connect_errno()) {

  echo "Failed to connect to MySQL: " . mysqli_connect_error();

}


$result = mysqli_query($con,"SELECT * FROM Persons");


echo "<table border='1'>

<tr>

<th>Firstname</th>

<th>Lastname</th>

</tr>";


while($row = mysqli_fetch_array($result)) {

  echo "<tr>";

  echo "<td>" . $row['FirstName'] . "</td>";

  echo "<td>" . $row['LastName'] . "</td>";

  echo "</tr>";

}


echo "</table>";


mysqli_close($con);

?>






















Posted by 푸른하늘 푸른하늘이

댓글을 달아 주세요

기타/웹 2.02014. 6. 23. 16:36

W3C PHP 강좌 제3장 입니다. 1장 기초2장 Form도 참고하세요.


다차원 배열


  • PHP의 배열(Array)는 key/value의 리스트
  • PHP의 다차원 배열은 여러개의 배열을 담은 배열(array containing one or more arrays)
  • 2차원 배열은 배열의 배열

$cars = array (
    array("Volvo",22,18),
    array("BMW",15,13),
    array("Saab",5,2),
    array("Land Rover",17,15)
);


  • echo $cars[0][0]." : in stock ".$cars[0][1]." : sold ".$cars[0][2].".<br />"; 와 같이 참조가능


날짜와 시간


  • date(format, timestamp) : timestamp는 옵션. default는 현재시간.
  • echo "Today is " . date("Y-m-d") . "<br />";     // 여기에서 Y, m, d, 1 (요일) 등 사용가능
  • &copy 2010-<?php date("Y") ?>                         // @2010-2014 로 표시됨
  • echo "The time is : " . date("h:i:s") . <br />";    // 여기에서 h, i(시간), s, a(오전 오후)  등 사용가능 
  • date_default_timezone_set()                             // 시간대 설정
  • mktime(hour, min, sec, month, day, year)         // 시간 생성
  • strtotime("10:30am April 15 1999"); strtotime("tomorrow")    // 인간이 사용하는 시간을 저장


Include


  • Include (혹은 require)는 지정한 텍스트/코드/등을 읽어들이는 문장으로, php, html 등을 반복적으로 사용할 때 유용함. 두 문장은 기능적으로 동일
    • include 의 경우, 에러가 발생하더라도 경고만 하고 계속진행
    • require의 경우, 에러가 발생하면 정지
  • include 'filename'; 또는 require 'filename'; 으로 사용
  • 공통 라이브러리로 사용하거나, 메뉴로 사용하거나, 변수 저장소로 사용하거나... 


File Handling


  • readfile() : 파일을 읽어서 output buffer로 보냄. (즉, 일반적으로는 화면에 그대로 표시됨)
  • fopen("filename", "mode");     // 모드는 r/w/a/x/r+/w+/a+/r+

<?php

$myfile = fopen("webdictionary.txt", "r") or die("Unable to open");

// echo fread($myfile, filesize("webdictionary.txt"));

while(!feof($myfile)) {

echo fgets($myfile) . "<br />";    // 한줄 읽기

}

fclose($myfile);

?>


  • File upload form
<html>
<body>

<form action="file_upload.php" method="post" enctype="multipart/form-data">
<label for="file">Filename :</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="Submit">
</form>

</body>
</html>


  • file_upload.php
  • 다만 여기에 파일의 최대크기, file type 등을 체크하는 기능이 필요
<?php
if ($_FILES["file"]["error"] > 0){
echo "Error : " . $_FILES["file"]["error"] . "<br />";

} else {

echo "Upload : " . $_FILES["file"]["name"] . "<br />";

echo "Type : " . $_FILES["file"]["type"] . "<br />";

echo "Size : " . ($_FILES["file"]["size"] / 1024) . " KB<br />"; 

echo "Stored in : "  . $_FILES["file"]["tmp_name"];

}

?>


Cookies


  • 쿠키는 사용자를 구분하는데 주로 사용된다. 쿠키는 서버에서 사용자 컴퓨터에 심는 작은 파일로서, 컴퓨터가 동일한 요청을 하면 쿠키도 함께 전송된다. PHP를 사용하면 쿠키를 생성할 수도, 값을 불러올 수도 있다.

<?php

$expire = time() + 60*60*24*30;
setcookie("user", "Min Heo", $expire);  // user 에 "Min Heo" 부여, 30일 후 해제

?>  // setcookie는 반드시 html 앞에 위치해야 한다. 


<html>


  • setcookie()는 자동으로 URLencode 됨. 원하지 않을때는 setrawcookie() 사용.
  • 쿠키를 읽을 때는 별도의 file open 작업이 필요없음. 

<?php

echo $_COOKIE["user"];    // "user"의 값

print_r ($_COOKIE);            // 모든 쿠키 값을 보는 방법

?>


Session


  • 세션... 한번의 접속?? 이때 세션에 따른 정보를 저장해 둘 수 있음

<?php

session_start();


if(isset($_SESSION['views'])) {

$_SESSION['views'] = $_SESSION['views'] +1;

} else {

$_SESSION['views'] = 1;

}


echo 'Pageviews = " . $_SESSION['views'];

?>


PHP Error


    • die() 로 처리
    • 별도의 에러 처리 루틴을 만듦
    • 에러 보고 


    PHP Filter


      • 의심스런 곳에서 입력된 데이터의 유효성 검증 및 필터링
      • PHP filter 는 데이터 필터링을 손쉽게 하기 위한 확장
      • 대부분의 웹앱은 외부 입력이 필요. 필터를 사용하면 항상 올바른 입력이 들어오도록
      • 모든 종류의 외부 데이터는 다 필터링을 해야 함
        • form 으로부터의 입력
        • 쿠키
        • 웹 서비스 데이터
        • 서버 변수
        • 데이터 쿼리 결과
      • Validating Filter
        • 사용자 입력의 검증
        • 정확한 포맷 확인 (이메일 또는 URL 등)
        • 성공시 기대한 타입을 반환, 실패시 FALSE 반환
      <?php
      if(!filter_has_var(INPUT_GET, "email")){   //GET 타입의 INPUT 변수인 "email"이 존재하는가?
      echo("Input type does not exist");
      } else {
      if(!filter_input(INPUT_GET, "email", FILTER_VALIDATION_EMAIL)) { 
      echo("Email is not valid");
      } else {
      echo("Email is valid");
      }
      }
      ?>
      • Sanitizing Filter
        • 문자열에서 특정 문자를 허용/불가
        • No data의 포맷 룰
        • 항상 문자열을 반환함
      <?php
      if(!filter_has_var(INPUT_POST, "url")) {
      echo ("Input type does not exist");
      } else {
      $url = filter_input(INPUT_POST, "url", FILTER_SANITIZE_URL);
      }
      ?>


      Posted by 푸른하늘 푸른하늘이

      댓글을 달아 주세요

      기타/웹 2.02014. 6. 22. 23:49

      웹페이지를 제작하기 위해서는 크게 두가지 작업이 필요합니다. 하나는 서버측 프로그래밍이고, 다른 하나는 클라이언트측 프로그래밍입니다.


      원칙적으로 서버측에서는 데이터 그 자체를 다루고, 클리이언트 측에서는 그 데이터를 어떻게 표현하는가를 다루므로, 서버측이 더 중요하다고 볼 수 있습니다.


      서버측 프로그램은 여러가지 언어로 개발될 수 있지만, 가장 널리 사용되는 것이 PHP (PHP HyperText Preprocessor)입니다. 이전에는 기본적인 사항을 다루었고, 이번엔 두번째로 Form을 처리하는 방법입니다.


      PHP - A Simple HTML Form

      다음 예제는 두개의 input 필드와 submit 버튼이 있는 폼


      <html>

      <body>


      <form action="welcome.php" method="post">

      Name: <input type="text" name="name"><br>

      E-mail: <input type="text" name="email"><br>

      <input type="submit">

      </form>


      </body>

      </html>


      사용자가 input 필드를 채우고 submit 버튼을 누르면, form 데이터가 action에서 지정한 welcome.php 로 전달됨. 이 폼은 POST 으로 전송됨.

      아래는 welcome.php 의 내용임


      <html>

      <body>


      Welcome <?php echo $_POST["name"]; ?><br>

      Your email address is: <?php echo $_POST["email"]; ?>


      </body>

      </html>


      ====

      HTTP GET을 사용해도 동일한 처리가 가능함


      <html>

      <body>


      <form action="welcome_get.php" method="get">

      Name: <input type="text" name="name"><br>

      E-mail: <input type="text" name="email"><br>

      <input type="submit">

      </form>


      </body>

      </html>


      아래는 이에 대응되는 welcome.php 의 내용


      <html>

      <body>


      Welcome <?php echo $_GET["name"]; ?><br>

      Your email address is: <?php echo $_GET["email"]; ?>


      </body>

      </html>


      ***** 위의 내용에서는 없지만, 보안을 위하여 반드시 Form validation 이 필요함. 

      GET vs. POST

      GET과 POST는 모두 배열( 예: array( key => value, key2 => value2, key3 => value3, ...)) 를 생성함. 이 배열에는 key/value 쌍이 저장되어 있음. 여기에서 key는 폼의 control 이름. values는 사용자가 입력한 데이터. 


      GET과 POST는 $_GET, $_POST를 사용하여 처리됨. $_GET과 $_POST는 super 전역변수(변수범위에 관계없이 어디에서나 접근 가능) 


      $_GET은 URL 파라미터를 통해 현재 script에 전달된 변수의 배열

      $_POST는 HTTP POST 메소드를 통해 현재 script에 전달된 변수의 배열


      GET 메소드를 통해 폼에 전달된 정보는 누구나 볼수 있음(변수와 값이 URL에 표시됨). 보낼 수 있는 정보의 양도 약 2000 문자로 제한됨. 하지만, 변수가 모두 보이므로 북마크가 가능함. GET은 민감하지 않은 자료를 보낼 때 사용가능


      POST 메소드로 전달된 정보는 아무에게도 안보임. (키/값 이 모두 HTTP request의 몸체속에 내장됨.) 보낼 수 있는 정보의 양도 제한이 없음. 


      아울러 파일을 서버에 올릴 때 multi-part binary input을 지원하는 등 고급 기능을 지원함. 


      그러나, 북마크는 불가능함. 대부분의 개발자들은 POST를 더 좋아하는 편


      PHP Form Validation

      해커와  스패머를 막기 위해서는 적절한 처리가 필요.


      폼의 형태

      <h2>PHP Form Validation Example</h2>

      <form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>"> 

         Name: <input type="text" name="name">

         <br><br>

         E-mail: <input type="text" name="email">

         <br><br>

         Website: <input type="text" name="website">

         <br><br>

         Comment: <textarea name="comment" rows="5" cols="40"></textarea>

         <br><br>

         Gender:

         <input type="radio" name="gender" value="female">Female

         <input type="radio" name="gender" value="male">Male

         <br><br>

         <input type="submit" name="submit" value="Submit"> 

      </form>


      <form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">

      • From이 제출되면 POST 메소드로 전송됨
      • $_SERVER["PHP_SELF"] 는 현재 수행되는 스크립트의 파일명 을 돌려주는 super 전역변수.
      • 따라서 form 데이터를 자기 자신에 돌려줌. 이렇게 하면 에러메시지를 현재 페이지에서 볼 수 있음
      • htmlspecialchars()는 special character를 HTML 엔터티로 변환. 즉, <, > 등을 &lt, &gt 등으로 변환. 이렇게 해야만, 해커들이 폼에 HTML이나 Javascript를 삽입함으로써 코드를 도용하는 것(Cross-site Scripting Attacks)을 막을 수 있음

      PHP Form 의 보안문제

      • $_SERVER["PHP_SELF"] 변수는 해커의 표적이 될 수 있음.
        • /를 넣고, XSS(Cross site scripting) 명령을 삽입시킬 수 있음
        • test_form.php 내에 <form method="post" action="<?php echo $_SERVER["PHP_ERVER"];?>"> 라고 정의 되어 있다고 가정하면,  일반적으로는 <form method="post" action="test_from.php">로 해석되므로 문제가 없음
        • 그런데 주소에 다음처럼 넣었다고 하면...
        • http://www.example.com/test_from.php/%22%3E%3Cscript%3Ealert('hacked')%3C/script%3E
        • <form method="post" action="test_form.php"/><scprit>alert('hacked')</script> 처럼 해킹되어버림.
      • 먼저 모든 변수를 htmlspecialchars()을 사용해 걸러내면 막을 수 있음
        • <form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_ERVER"]);?>">
        • 그러면 <form method="post: action="test_form.php/&quot;&gt;&lt;.... 으로 해석되므로 문제가 없음

        PHP를 이용한 Form 데이터 검증

        • 가장 먼저 모든 변수를 htmlspecialchars()로 처리한 뒤 사용
        • PHP trim()을 사용하여, 사용자 입력자료에서 공백, 탭, 등을 제거 
        • PHP stripslashes()를 사용하여 '\'를 제거
        • 이 세가지 기능을 처리하는 함수를 작성하여 사용

        <?php

        $name = $email = $website = $comment = $gender = "";


        if ($SERVER["REQUEST_METHOD"] == "POST"){

        $name = test_input($POST["name"]);

        $email = test_input($POST["email"]);

        ....

        }


        function test_input($data){

          $data = trim($data);

          $data = stripslashes($data);

          $data = htmlspecialchars($data);

          return $data;

        }

        ?>


        Required Field

        • if (empty($POST["name"])) 로 테스트하여 처리


        <?php

        $nameErr = $emailErr = $websiteErr = $commentErr = $genderErr = "";

        $name = $email = $website = $comment = $gender = "";


        if ($SERVER["REQUEST_METHOD"] == "POST"){

        if (empty($POST["name"])) {

        $nameErr = "Name is required";

        } else {

             $name = test_input($POST["name"]);

        }

        ....

        }

        ?>


        • 그리고 Form에서 에러메시지를 받아서 표시하도록 함.


        <form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>"> 

           Name: <input type="text" name="name">

           <span class="error">* <?php echo $nameErr;?></span>

           <br><br>

           E-mail: <input type="text" name="email">

           <span class="error">* <?php echo $emailErr;?></span>

           <br><br>

            ....

        </form>


        • 그러나, 이와같은 Form의 항목 점검은 클라이언트 쪽에서 javascript로 처리하는 게 나을 것 같음

        Name 처리

        • 모두 영문자 또는 공백의 경우

        $name = test_input($POST["name"]);

        if(!preg_match("/^[a-zA-Z ]*$/", $name) {

        $nameErr ="Only letters and white spaces allowed";

        }

        • Email 의 경우 : if (!preg_match("/([\w\-]+\@[\w\-]+\.[\w\-]+)/",$email))
        • URL의 경우 if (!preg_match("/\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i",$website)): 


          Posted by 푸른하늘 푸른하늘이

          댓글을 달아 주세요

          기타/웹 2.02014. 6. 22. 23:49

          저는 요즘 자바스크립트 열공중입니다. 그런데, 자바스크립트를 공부하려니, 점점 공부할게 늘어납니다. 자바스크립트는 클라이언트용 스크립트입니다. 즉, 웹브라우저와 같은 환경에서 서버로부터 받은 정보를 처리하는 용도입니다. 


          그런데, 서버에서도 여러가지 작업이 필요합니다. 이를 위해서 필요한 게 서버측 스크립트인 PHP입니다.  파일을 올리고 DB를 조작하는 등 서버와 통신 등을 담당합니다.


          이글은 http://www.w3schools.com/php/에 있는 PHP 5 투토리얼을 제 마음대로 간략하게 정리한 겁니다. 참고하세요.


          PHP 는 서버 스크립트용 언어로, 동적/대화식 웹페이지를 빠르게 구축할 수 있는 강력한 도구이다. PHP는 널리 사용되며, 무료이고, 마이크로소프트의 ASP와 같은 유사한 도구를 효율적으로 대체할 수 있다.


          첫번째 예제: 

          <!DOCTYPE html>
          <html>
          <body>

          <?php
          echo "My first PHP script!";
          ?>


          </body>
          </html>


          PHP란 무엇인가?

          • PHP는 "PHP Hypertext Preprocessor"의 약어임
          • PHP는 광범위하게 사용되는 오픈소스 스크립트 언어
          • PHP 스크립트는 서버에서 실행됨
          • PHP는 무료임.

          PHP 파일은 어떤 것이 있나?

          • PHP files can contain text, HTML, CSS, JavaScript, and PHP code PHP code are executed on the server, and the result is returned to the browser as plain HTML PHP files have extension ".php"
          • PHP 파일에는 텍스트, HTML, CSS, Javascript, PHP 코드가 들어갈 수 있다.
          • PHP는 서버에서 실행되며, 그 결과는 브라우저에게 일반 HTML 형식으로 반환됨.
          • PHP 파일의 확장자는 .php

          PHP로 할 수 있는 것

          • PHP can generate dynamic page content PHP can create, open, read, write, and close files on the server PHP can collect form data PHP can send and receive cookies PHP can add, delete, modify data in your database PHP can restrict users to access some pages on your website PHP can encrypt data
          • PHP는 동적인 페이지를 생성할 수 있음
          • PHP는 서버에 파일을 생성하고, 열기/읽기/쓰기/닫기 등이 가능함
          • PHP는 폼 data를 수집할 수 있음
          • PHP는 쿠키를 전송/수신할 수 있음
          • PHP는 데이터베이스에서 데이터를 추가/삭제/수정할 수 있음
          • PHP는 웹사이트중 일부를 사용자가 접근하지 못하도록 막을 수 있음
          • PHP는 데이터를 암호화할 수 있음

          PHP의 결과가 HTML만 나오는 건 아님. 영상, PDF, 플래시 등도 가능하다. XHTML, XML 등의 텍스트도 가능


          PHP를 사용하는 이유

          • PHP는 다양한 플랫폼(윈도, Linux, Unix, Mac OS X 등)을 지원함
          • 현재 사용되는 거의 모든 서버(Apache, IIS, 등)와 사용가능
          • 다양한 데이터베이스 지원
          • 무료. www.php.net 에서 다운로드 받으면 됨.
          • 배우기 쉽고, 서버에서 효율적으로 운영됨

          PHP 문법

          • PHP는 문서 어디나 있어도 됨. <?php 로 시작하고 ?>로 끝남
          • 기본 확장자는 .php
          • PHP 파일에는 일반적으로 HTML 태그와 PHP 스크립트가 들어있음

          <!DOCTYPE html>
          <html>
          <body>

          <h1>My first PHP page</h1>

          <?php
          echo "Hello World!";
          ?>


          </body>
          </html>


          참고로 php 구문은 세미콜론으로 끝남. 

          코멘트

          3가지 종류가 있음

          • 라인 코멘트 : //, #
          • 블록 코멘트 : /*   */

          대소문자 구별

          • 사용자 정의 함수, 클래스, 키워드(if, else, while, echo, 등)은 대소문자 구별 없음
          • 단, 모든 변수는 대소문자를 구별함

          PHP 변수


          • 변수명은 $로 시작하고 그 뒤에 변수명이 따라옴
          • 변수명은 반드시 문자 혹은 밑줄로 시작해야 함
          • 변수 이름은 숫자로 시작할 수 없음
          • 변수 이름에는 영문자, 숫자, 밑줄만 사용가능(A-z, 0-9, and _ ) 
          • 변수명은 대소문자를 구별함

          변수선언

          • PHP에는 별도의 변수 선언이 없음. 값을 할당하는 순간 생성됨
          • 변수타입이 정해져 있지 않음
          • 변수타입은 필요에 따라 자동으로 변환됨


          <?php
          $txt="Hello world!";
          $x=5;
          $y=10.5;
          ?>


          변수 범위(Scope)

          • 변수는 어디에서나 선언할 수 있음. 
          • 함수 바깥쪽에서 선언한 변수는 전역범위(global scope)를 가지며, 함수 바깥쪽에서만 사용가능 
          • 함수 내부에서 선언한 변수는 지역범위(local scope)를 가지며, 해당함수 안쪽에서만 사용가능

          Global 키워드

          • global 이라는 키워드를 사용하면 global 변수를 함수 내부에서 사용할 수 있음.
          • 함수 내부에서 변수명 앞에 global이라고 쓰면 됨.
          • 글로벌 변수는 $GLOBAL[index]에 보관되므로(여기에서 index는 변수명), 이를 통해 직접 접근할 수도 있음

          Static 키워드

          • 로컬 변수는 함수가 종료가 되면 사라지지만, static 변수는 그대로 살아 있음. 변수 앞에 stattic 키워드를 붙이면 됨
          <?php
          $x=5;
          $y=10;

          function myTest()
          {
          global $x,$y;
          $y=$x+$y;

          // $GLOBALS['y']=$GLOBALS['x']+$GLOBALS['y']; 도 가능함
          }


          myTest();
          echo $y; // outputs 15
          ?>


          echo 와 print

          • 출력하기 위한 함수.
          • echo : 여러개의 string을 한꺼번에 출력 가능
          • print : 한번에 한개만 가능. 항상 1을 반환함.
          • echo "문자열" 도 가능하고, echo("문자열") 도 가능함. print 도 비슷

          <?php
          $txt1="Learn PHP";
          $txt2="W3Schools.com";
          $cars=array("Volvo","BMW","Toyota");

          echo $txt1;
          echo "<br>";
          echo "Study PHP at $txt2";
          echo "My car is a {$cars[0]}";
          ?>



          데이터 타입

          • String, Integer, Floating point numbers, Boolean, Array, Object, NULL. 등이 있음.
          • string
            • 큰따옴표, 작은 따옴표 모두 허용. 
          • Integer
            • 10진수, 16진수 (0x로 시작), 8진수 (0으로 시작) 가 지원됨.
            • var_dump()함수를 사용하면 데이터 타입과 값이 반환됨.
          • Floating point numbers
            • 일반형(소수점) 및 지수형(2.4e4 등) 지원함
          • Bloolean
            • true, false
          • Array
            • 하나의 변수에 여러개의 값을 저장
            • index는 0부터 시작. 아래에서는 $cars(1)=="BMW".
            • $cars=array("Volvo","BMW","Toyota");
          • Object
            • 데이터와 처리방법(메소드)이 저장되어 있는 데이터 타입
            • 객체는 반드시 명시적으로 정의해야 함
            • 먼저 class 키워드를 사용하여 class를 정의해야 함.
            • this->$color 와 같은 방식으로 프로퍼터 참조.
          • NULL
            • 값이 없음을 알려주는 타입. 이 타입의 값은 NULL 하나뿐임. 
            • 변수가 값이 있는지 없는지 알아낼 수 있음. "" 과 NULL은 다름
            • 변수에 NULL을 저장하면 변수의 값을 지울 수 있음

          PHP String 함수

          • strlen()
          • strpos(A, a) - 문자열 A에 a가 있는지 검색. 성공하면 첫번째 매칭 위치 반환. 아니면 false 반환

          PHP 상수

          • 프로그램 시행중 값을 변경시킬 수 없는 식별자(이름)
          • 변수와는 달리 $ 표시가 없음. 범위(scope)는 자동적으로 global임
          • 상수는 define()을 사용하여 정의. 세번째 인수는 대소문자 구분여부를 설정

          <?php
          define("GREETING", "Welcome to W3Schools.com!", true); //case-insensitive
          echo GREETING;
          ?>


          PHP 연산자

          • 산술연산자 : +, -, *, /, %
          • 할당연산자 : =, +=, -=, *=, /=, %=
          • 문자열연산자 : . (문자열 연결) ...
          • 증가연산자, 감소연산자 : ++, --. 전치 후치 모두 가능

          <?php
          $a = "Hello";
          $b = $a . " world!";
          echo $b; // outputs Hello world! 
          ?>

          PHP 비교연산자

          • 동등, 일치 : ==, === : 일치는 데이터 타입도 같아야 함.
          • 같지  않음 : <>, !=    : 이 두가지는 동일
          • 크다/작다  : >, <, <=, >=

          <?php

          $x = 100;

          $y = "100";


          var_dump($x==$y);   // boolean(true)

          var_dump($x===$y);   // boolean(false)


          ?>

          PHP 논리연산자

          • and, &&,          or, ||,      xor,    !

          PHP 배열 연산자

          • + : 두 배열을 합침.  (단, 중복된 key를 덮어쓰지는 않음)
          • 비교연산자 : ==, ===, <>, !=, !==     : ===의 경우, key/values 일치, 순서일치, 타입일치 모두 성립해야 함

          PHP 조건문

          • if()  {....}
          • if() elseif() elseif() else

          <?php
          $t=date("H");
          if ($t<"10")
            {
            echo "Have a good morning!";
            }
          elseif ($t<"20")
            {
            echo "Have a good day!";
            }
          else
            {
            echo "Have a good night!";
            }
          ?>


          PHP switch 문

          • c와 동일함

          PHP 반복문

          • while (condition is true) { execute this code }
          • do { execute this code) while (condition is true)
          • for (initialize; test; increment) {execute}
          • foreach ($array as $value) {execute}

          <?php 
          $colors = array("red","green","blue","yellow"); 
          foreach ($colors as $value)
            {
            echo "$value <br>";
            }
          ?>


          PHP 함수

          • 함수 선언 : function functioname(arg, arg, ..) { }
            • 함수명은 대소문자를 구분하지 않음
          • default arguments  -> function(arg="10") { }  와 같이 인수에 값을 지정해 두면, 인수 없이 호출 가능
          • return 수식; 방식으로 반환값을 지정

          <?php
          function setHeight($minheight=50)
          {
          echo "The height is : $minheight <br>";
          }

          setHeight(350);
          setHeight(); // will use the default value of 50
          ?>


          PHP 배열

          • 배열은 여러개의 값을 한꺼번에 담을 수 있는 특수한 변수
          • 배열 생성 : array(); 세가지 종류가 있음
            • indexed array : index가 숫자임
            • Associative array : named key로 참조
            • Multidimensional array : 여러개의 배열을 담은 배열
          • Indexed array : 일반적 배열, 숫자가 인덱스. 
            • $cars=array("Volvo","BMW","Toyota");  - index가 자동으로 부여됨
            • $cars[0] 등으로 참조가능. 
          • Array의 크기(요소의 갯수)는 count($cars) 로 알 수 있음

          <?php
          $cars=array("Volvo","BMW","Toyota");
          $arrlength=count($cars);

          for($x=0; $x<$arrlength; $x++)
            {
            echo $cars[$x];
            echo "<br>";
            }

          // foreach로 구현하려면

          // foreach($cars as $x)

          //   {

          //      echo $x . "<br>";

          //   }
          ?>

          • Associative array : 이름이 키. 자바스크립트의 객체와 비슷.
            • $age=array("Peter"=>"35","Ben"=>"37","Joe"=>"43");
            • 또는  $age['Peter']="35";    $age['Ben']="37";     $age['Joe']="43"; 
            • foreach 를 사용하여 순환함.

          <?php
          $age=array("Peter"=>"35","Ben"=>"37","Joe"=>"43");

          foreach($age as $x=>$x_value)
            {
            echo "Key=" . $x . ", Value=" . $x_value;
            echo "<br>";
            }
          ?>

          • Multidimensional array : 원소가 배열인 배열

          PHP 배열 소팅

          • sort() : 오름차순
          • rsort() : 내림차순
          • asort() : Associative 배열에 대해, value 를 기준으로 오름차순
          • ksort() : Associative 배열에 대해, key 를 기준으로 오름차순
          • arsort() : Associative 배열에 대해, value 를 기준으로 내림차순
          • krsort() : Associative 배열에 대해, key 를 기준으로 내림차순

          PHP 전역변수 - SuperGlobals

          • 미리 정의되어 있는 전역변수. 어디에서나 접근가능. 
          • $GLOBALS $_SERVER $_REQUEST $_POST $_GET $_FILES $_ENV $_COOKIE $_SESSION 등이 있음.

          PHP $GLOBAL

          • PHP의 전역변수를 어디에서든 접근할 수 있게 해주는 Super Global 변수
          • 모든 전역변수는 $GLOBALS[index]에 저장됨. 
            • 전역변수 $gx  는 $GLOBALS['gx'] 로 접근가능.

          PHP $_SERVER

          • 헤더, 경로, 스크립트 파일의 위치 등의 정보를 담고 있는 전역변수
          • $_SERVER['PHP_SELF']  현재 수행중인 스크립트 파일명 
          • $_SERVER['SERVER_ADDR'] 호스트 서버의 IP 주소
          • $_SERVER['REQUEST_METHOD'] 해당 페이지를 호출하는 데 사용된 호출방법 (POST 등)
          • $_SERVER['QUERY_STRING'] query string으로 호출되었을 경우, 그 쿼리문
          • $_SERVER['REMOTE_ADDR'] 뷰어의 IP 주소
          • $_SERVER['SCRIPT_URI'] 현재 페이지의 URI

          PHP $_REQUEST

          PHP $_REQUEST 는 HTML 폼을 제출한 후, 데이터를 수집하는데 사용됨.


          아래의 예는 input 필드와 submit 버튼이 있는 폼임. 사용자가 submit 버튼을 제출하면, Form 의 데이터가 <form> 태그의 action 속성에 지정된 파일에 전달됨. 이 예제에서는 자기 자신을 지정하였음 <?php echo $_SERVER['PHP_SELF']; ?> 폼데이터를 다른 PHP 파일로 처리하게 하려면 여기에 파일명을 지정하면 됨. 그 다음 input 필드의 값은 super 전역변수인 $_REQUEST 를 사용하여 수집함.


          <html>
          <body>

          <form method="post" action="<?php echo $_SERVER['PHP_SELF'];?>">

          // 실행시킬 파일명으로 자기 자신을 지정함
          Name: <input type="text" name="fname">
          <input type="submit">
          </form>

          <?php 
          $name = $_REQUEST['fname'];  // 제출된 form에서 fname 필드 값을 읽어옴
          echo $name; 
          ?>

          </body>
          </html>


          PHP $_POST

          PHP $_POST는 method="post"를 사용하여 HTML 폼을 제출한 후, 데이터를 수집하는데 널리 사용됨

          아래의 예는 input 필드와 submit 버튼이 있는 폼임. 사용자가 submit 버튼을 제출하면, Form 의 데이터가 <form> 태그의 action 속성에 지정된 파일에 전달됨. 이 예제에서는 폼데이터를 처리하기 위해 자기 자신을 지정하고 있음. 폼데이터를 다른 PHP 파일로 처리하게 하려면, 파일명을 바꾸면 됨. input 필드의 값을 수집하려면 super 전역변수인 $_POST 를 사용하면 됨.


            <html>

            <body>


            <form method="post" action="<?php echo $_SERVER['PHP_SELF'];?>">

            Name: <input type="text" name="fname">

            <input type="submit">
            </form>


            <?php
            $name = $_POST['fname'];

            echo $name;

            ?>

            </body>

            </html>

            PHP $_GET

            PHP $_GET으로도 method="get"을 사용하여 HTML 폼을 제출한 후 데이터를 수집하는데 사용할 수있음. 

            아울러 URL에서 전송된 데이터를 수집할 수 있음. 

            다음과 같은 페이지가 있다고 가정.

            <html>
            <body>

            <a href="test_get.php?subject=PHP&web=W3schools.com">Test $GET</a>

            </body>
            </html>


            사용자가 이 페이지에서 "TEST $GET" 링크를 누르면, "subject"와 "web" 파라미터가 "test_get.php"에 보내짐. 

            "test_get.php" 파일에서는 $_GET 을 사용하여 그 값에 접근할 수 있음. 

            아래는 "test_get.php"의 소스임


            <html>
            <body>

            <?php 
            echo "Study " . $_GET['subject'] . " at " . $_GET['web'];
            ?>

            </body>
            </html>



            Posted by 푸른하늘 푸른하늘이
            TAG php

            댓글을 달아 주세요

            기타/웹 2.02014. 6. 15. 23:58

            제가 체험단 이벤트로 스마트폰으로 조종하는 RC카 HAMMER를 받아서 처음 우리 딸래미한테 보여주자, 우리 딸래미는, "와 정말 멋지다!!" "그래? 왜?" "내가 제일 가지고 싶은 차걸랑" ... 이런 반응을 보였습니다. @_@ (머... 우리 딸래미가 좀 독특합니다. 사실 저보다 HAMMER를 더 좋아하거든요. ㅎㅎ)


            아무튼 구글에서 "Hammer car"라고 검색을 봤습니다.  아래와 같은 사진들이 나타나더군요. 그런데 원래의 차 이름은 Hammer가 아닌 Hummer. 1980년대초 미군에서 사용된 Humvee의 상용버전으로, GM에서 2009년까지 생산하던 럭셔리 SUV라고 나옵니다. 홈페이지는 여기입니다. 위키페이지는 여기. 너무 덩치가 크다보니, 경제위기 상황하에서 단종된 모양입니다. 그런데, 왜 Hummer가 Hammer로 검색해도 나올까... 싶었는데, Rhino Buggies Hammer라고 Hummer H1 짝퉁이 있어서 그런게 아닌가... 싶네요.


            아무튼 멋지긴 멋집니다. 아마도 크기가 상당할 것 같은데, 한번 몰아보고 싶은 생각이 들기는 합니다만, 너무 커서 연비가 낮은 것은 물론 주차하기도 힘들 지경이라니 아무래도 힘들지 않을까 싶네요. ㅎ




            아래는 제가 촬영한 RC카 Hammer 사진들입니다. 엊그제 송도 인천경제자유구역으로 지오캐싱을 나갈 때 시험삼아 가지고 나갔다가 촬영한 겁니다. 바퀴만 빼면 상당히 비슷하다는 걸 아실 수 있을 겁니다.



            요런 각도로 촬영해도 참 이쁘네요. 좌측에 있는 앰브란스는 지오캐시 속에 들어 있던 기념품입니다. 크기는 약 3cm 정도. 아주 귀엽습니다. ㅎㅎ




            요건 들고 촬영해 본 것입니다. 여기는 wonkoo1님이 설치하신 지오캐시 #38. Garden 입니다.



            스마트 RC카 HAMMER 처럼 엄청나게 큰 바퀴를 달도록 개조한 차를 몬스터 트럭(Monster Truck)이라고 합니다. 이런 식으로 개조해서 경주도 하고 그러는 모양이더군요. 저도 한번 내셔널 지오그래픽인가 한번 본 것 같고요.



            어쨌든 이 녀석 덕분에 RC카가 뭔지 알고 싶어 검색해보니 RC카 입문을 위한 초보 가이드 (아빠들을 위한 가이드)라는 글을 만나게 되었습니다. 덕분에 아주 조금이나마 알게되었네요. 우선 RC가 Remote Control 이 아니라 Radio Control 의 약자라고 하는 것부터... 저는 당연히 Remote라고 생각했는데 말이죠. ㅎㅎㅎ


            RC카를 크게 구분하면 전동 RC카와 엔진 RC카로 나눌 수 있는데, 당연히 스마트 RC카 HAMMER는 전동 RC카. 전동 RC카는 엔진 출력이 낮고 배터리 용량으로 한계가 있기는 하지만, 엔진 소음이 없어서 집안이나 지하주차장, 공원, 운동장에 나가도 조용하게 즐길 수 있어, 초보자용으로 적합하다고 합니다.


            그리고 조립상태에 따라서, 구입한 후 바로 사용할 수 있는 것(RTR : Ready to Run)과 조립하면 바로 사용할 수 있는 것(ARR : Almost Ready to Run) 그리고 차체를 제외한 모든 부품은 별매로 구입하여 완성시켜야 하는 미조립차 (BYO : Build Your Own)로 나눌 수 있는데, 당연히 초보자라면 RTR이 최선이고, 당연히 HAMMER도 RTR입니다. 배터리마저도 충전되어 있는 상태이기 때문에(에너루프 계통의 배터리를 사용하는데, 충전시키고 1년이 경과해도 10%정도만 방전된답니다.) 바로 굴려볼 수 있습니다.


            그 다음으로 세단이나 스포츠카 같이 바퀴가 작고 쇼바가 낮은 온로드(On-Road)용과 차체가 높고 바퀴가 크며 쇼바 역시 탄력성이 좋아 울퉁불퉁한 곳을 다니기에 좋게 설계되어 되어 있는 오프로드(Off-Road)용이 있는데, 당연히 제 HAMMER는 오프로드용이고 특히 몬스터형. 이것도 바퀴간 거리가 넓어서 초보자용으로 적합. ㅎㅎ


            차량의 크기로는 스탠다드(1/7 - 1/10 정도), 이보다 작은 마이크로, 미니 등이 있는데, 몬스터 트럭의 경우엔 1/7 - 1/8 정도가 많답니다. 흠... Toy's myth에서 제작한 HAMMER는 21cm x 19.5cm 높이는 13cm 정도이고, Hummer의 길이는 H2 모델 기준으로 520 cm 정도 되므로, 1/25 정도 되나요? RC카 자체는 크기가 딱 적당하다는 느낌인데, Hummer 자체가 큰건지는 모르겠네요. 1/10 정도라면 50cm가 되어야 하는데... 가지고 다니기엔 좀 버거울 것 같다는 생각도 들고요.


            아무튼 결론적으로 제 스마트 RC카 HAMMER는 스마트폰으로 조종할 수 있는 초보자용 RC카 라고 생각하면 되겠네요.


            ===

            그런데 이글을 읽다보니... "드리프트카는 말 그대로 드리프트가 주목적인 차량으로 타이어와 휠, 쇼바 등이 드리프트에 적합하게 만들어져야 한다. 또한 조종능력이 좋아야 제대로 된 드리프트를 즐길 수 있다." 라는 글이 있네요. 오프로드용 RC카라면 타이어를 바꿔서 시도해볼 수 있다... 흠... HAMMER로 드리프트를 할 수 있다면 꽤 멋질 것 같다는 생각이 드네요. 아마 저는 힘들겠죠? ㅎㅎ


            아래는 환상적인 드리프트 실력을 보여주는.... 1:00 부터 보면 됩니다. RC도 RC지만, 아마도 상당한 실력이 있어야 할 것 같다는 생각이 듭니다.



            아래는 SMART Wi-Fi RC HAMMER 를 조종하는 방법을 보여주는 영상입니다. 여기에도 1:00 부터 보시면 (드리프트라고 부르기는 민망하지만) 나름 비슷하게 조종할 수 있나 봅니다. 나중에 저도 한번 시도를 해봐야겠네요.




            아래는 제가 오늘 아파트 한바퀴 돌아본 기록입니다. 땅바닥에서 촬영해서 독특합니다. 중간에 화면이 깨지는 것은 아마도 Wi-Fi 연결상의 오류가 아닌가 싶네요.



            아무튼... 요녀석... 가지고 놀면 놀 수록 재미있습니다. 이러다가 푹빠질까봐 그게 걱정이네요. ㅎㅎ


            민, 푸른하늘


            Posted by 푸른하늘 푸른하늘이

            댓글을 달아 주세요

            1. GSU

              재미있네요ㅎㅎ 알려주신 G9 사러 가야겠어요ㅋㅋ

              2014.06.19 00:39 [ ADDR : EDIT/ DEL : REPLY ]
            2. elessar

              좋은 사용기 잘 읽었습니다.
              감사합니다.

              2014.06.23 13:52 [ ADDR : EDIT/ DEL : REPLY ]
            3. 왕자의게임

              급뽐 오네요. 지금 사러 갑니다 ㅌㅌㅌ

              2014.06.23 14:35 [ ADDR : EDIT/ DEL : REPLY ]
            4. 킹왕짱

              지난 번 리뷰에서는 실내여서 그랬는지 화면이 많이 안 좋았는데 이번에는 외부라 그런지 괜찮네요 중간중간 화면이 깨지는 것 말고는 실감 나네요! 사용기가 자세하고 재밌어서 제품을 안 사도 산 것 같은 느낌입니다 ㅎㅎ 항상 재미있고 유용한 글 감사합니다~~

              2014.06.23 20:08 [ ADDR : EDIT/ DEL : REPLY ]
            5. 우왕..

              리볼트 경기도 가능하겠네요..

              2014.08.23 01:54 [ ADDR : EDIT/ DEL : REPLY ]

            기타/웹 2.02014. 6. 14. 16:31



            드디어 스마트 RC 카 해머(Hammer)를 받았습니다. 테스트용으로요. 좌측 위 사진이 바로 제가 해머 체험단 이벤트에 응모해서 받은 해머(Hammer)입니다. 평소에 RC카를 잘 알지도 못하는 제가 체험단으로 선정된 것은 아마도 제가 제일 처음으로 댓글을 남기면서, 이랬으면 좋겠다, 저랬으면 좋겠다.. 제안을 했던 덕분이 아닌가 합니다. ㅎㅎ


            사실 그냥 단순한 RC 카라면 관심을 두지 않았을 것 같습니다. 그런데 이 녀석은 Wi-Fi를 통해 구동이 되고, 특히 스마트폰으로 조종이 되며, RC 카의 카메라에서 촬영된 영상이 그대로 스마트폰으로 전달되어 저장되기 때문에 많이 끌렸습니다. 게다가 (현재로서는 부족하지만) 사물인터넷(IoT)의 플랫폼을 지향하고 있다고 하니까 관심을 가질 수 밖에 없었습니다. 


            아래는 HAMMER를 개발한 토이스미스(Toy's Myth)에 있는 HAMMER 소개자료 중 일부입니다. 사양만 봐도 꽤 끌리죠? ㅎ



            일단 박스개봉 사진부텀. 박스는 꽤 깔끔합니다. 제 눈에는요. 하지만 미술하는 우리 딸래미 의견은 좀 다르더군요.  "스타트업들이 디자인에 신경을 덜 쓰는 경향이 있는데, 이는 정말 큰 실수" 의견. ㅎㅎ





            박스 해체 시작. 



            아... 꺼내놓고 나니 정말 이쁩니다. ㅎㅎ





            이건 장식용 스티커 입니다. 데칼이라고 합니다. 윗 사진은 순정상태인데, 이것들을 사용해서 원하는대로 꾸밀 수 있습니다. 좀더 실력이 있다면 자기가 좋아하는 도안으로 디자인을 해서 도색을 할 수도 있습니다만, 저에게는 꿈같은 일이고... ㅎㅎ



            아래는 기타 들어있는 부속품들입니다. 매뉴얼, 데칼, 그리고 배터리 그리고 충전기가 있습니다.



            ====

            모두 조립한 상태로 배송되기 때문에 따로 조립할 것은 없는데, 배터리는 따로 넣어줘야 합니다. 아래 사진처럼 뒤집어 놓고, 좌측위에 있는 나사하나만 풀면 되고요,



            배터리를 연결해주면 끝.



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

            이 스마트 RC HAMMER는 스마트폰으로 조종합니다. 따라서 앱 설치가 필수입니다. 아이폰과 안드로이드 모두 지원하는데, 앱스토어나 구글플레이에서 RC HAMMER 로 검색하면 찾을 수 있습니다. 머... 앱설치는 다 아실테니까 생략.


            그럼 이제 스마트폰과 HAMMER를 연결할 차례입니다. HAMMER는 기본적으로 Wi-Fi를 통해 스마트폰과 연결됩니다. 


            먼저 HAMMER를 뒤집어서 스위치를 켜줍니다. 그러면 전조등 부분의 LED에 불이 들어오고 잠시후에 후면등도 들어옵니다. 이렇게 되면 HAMMER 쪽은 준비가 완료된 겁니다.



            그 다음 Wi-Fi 를 연결합니다. 우선 스마트폰에서 Wi-Fi 설정에 들어가면 다음과 같이 TS_M_***** 으로 시작하는 WI_Fi 가 나타나면 이를 선택하면 됩니다. 초기 비밀번호는 12345678. 가능하면 빨리 바꿔주는 게 좋겠죠. (처음에는 갤럭시 3에서 연결이 안되더군요. 나중에 보니... 인터넷이 안되면 자동으로 다른 무선 AP로 바꿔주도록 설정이 되어있어서 입니다. Wi-Fi 고급설정에서 네트워크 자동전환을 꺼주니 문제 없이 연결되었습니다.)



            Wi-Fi 설정이 완료된 후 앱을 실행하면 다음과 같은 모습이 됩니다. 여기에서 "드라이브"를 누르고...



            그 다음 오른쪽 구석에 있는 Engine Start 버튼을 누르면 시작됩니다.



            아래는 실행화면 몇개를 촬영한 겁니다. 앱은 넥서스7에 설치했으며, 촬영은 갤럭시3로 했습니다. (물론 갤럭시3에도 설치가 됩니다.) 이 상태에서 해머를 조종할 수 있습니다. 방향전환, 가속/감속 등... 그리고 카메라 촬영 비디오 저장 등도 모두 화면에서 설정할 수 있습니다.






            시험삼아 운전해보니 우리 강아지가 제일 관심을 보이네요. 자기 친구라고 생각하는 모양입니다. ㅎㅎㅎ


            ====

            아래는 Hammer로 촬영한 사진들입니다. 실내 촬영이라 화질이 낮은지는 잘 모르겠습니다만... 어차피 전문 카메라는 아니니까....




            마지막으로 아래는 비디오를 저장해서 유튜브에 올린겁니다. 우리집 강아지가 흥분해서 짖는 모습이 보일텐데 소리는 하나도 없습니다. 원래 마이크가 없기 때문입니다. 그리고... 제가 아직 조종이 서툴다보니 앞뒤로 왔다 갔다뿐이 안되네요. 죄송합니다. 사실은 낮에 아파트를 한바퀴 돌았었는데, 비디오가 항상 자동으로 저장된다고 생각해서 그냥 조종만했더니 낮에 촬영한 건 하나도 안남았습니다. 나중에 좀더 연습한 뒤 올리겠습니다.



            ====

            이상입니다. Wi-Fi 스마트 RC카 HAMMER의 처음 사용기이다보니 좀 자세하게 썼습니다. 혹시 지루하셨더라도 이해해 주시길. 


            나름대로 느낀점도 쓸까... 했지만, 제가 다른 RC카를 조종해본 경험도 없다보니 비교하기도 그렇고... 아직 조종에 익숙하지도 않다보니 경험이라고 썼다간 야단만 들을 것 같아 그냥 생략하려고 합니다. 나중에 좀더 경험이 쌓이면 한마디 하게 될지도...


            그런데 사실 제가 정말 원했던 기능은 조금 달랐습니다. WiFi로 조종이 된다길래, 당연히 인터넷을 통해서 조종이 된다고 생각했고, 그럼 밖에서도 웹브라우저나 스마트폰으로 조종이 가능하겠다고 생각했었습니다. 예를들어 집을 비웠는데 강아지가 뭘하고 있는지가 궁금하다면 스위치를 켜고 여기저기 페트롤하는 기능같은 게 있으면 좋겠다... 는 거죠. 좀 더 나아가서는 집안 평면도를 입력해서 자동 운전시키는 기능까지도 가능할 것 같고요.


            아니면... RC카를 조종하는 게 아니라... 공원같은 데를 나가서 산책하고 있으면 RC카가 알아서 뒤를 졸졸 쫒아오게 만들면 어떨까... 하는 것도 생각해 봤습니다. 아마 하드웨어적으로는 가능할 것 같은데... 좀 더 다른 걸 많이 고민해야겠죠. 그래도 이런 기능이 있다면 정말로 많은 사람들... 저처럼 RC카에는 그다지 관심없는 사람들도 많이 관심을 가지지 않을까... 하는 생각을 해봤습니다. 


            개발하는 데 많은 어려움이 있었다고 들었는데... 이제 시작이니까... 앞으로 더 좋은 기능 탑재하고 훨훨날았으면 좋겠네요.


            민, 푸른하늘


            Posted by 푸른하늘 푸른하늘이

            댓글을 달아 주세요

            1. 하얀곰

              미국애들 개조한 차량 같네요. ㅋ 작은 차체에 큰 바퀴. 애들 참 좋아하게 생겼습니다.

              2014.06.15 11:46 [ ADDR : EDIT/ DEL : REPLY ]
            2. 와정말 별게 다있다 싶네요 울 애기 찍어도 좋겠네요 호기심어린 눈으로 쫓아 올걸 생각하니 왠지 재미있어지네요 ㅎㅎ
              온라인에서도 파는 거죠?

              2014.06.18 14:05 [ ADDR : EDIT/ DEL : REPLY ]
            3. 킹왕짱

              세상의 변화가 정말 빠르네요. 상상으로만 가능하던 것들이 이렇게 빨리 만들어지다니... 무섭기도 하고 재밌기도 하고 그러네요

              아들이 저게 뭐냐고 계속 물어보네요 ;;; 빨리 구매해서 같이 가지고 놀아봐야겠어요

              좋은 제품 소개해주셔서 감사합니다

              2014.06.19 13:31 [ ADDR : EDIT/ DEL : REPLY ]
            4. elessar

              멋진 사용기입니다.
              강아지 반응이 재미있네요.
              동작 완구 외에도 애완동물과 놀아주면서 애완동물 시각의 높이에서 바라볼 수 있다는 점은 장점인 것 같습니다.

              2014.06.19 15:00 [ ADDR : EDIT/ DEL : REPLY ]
            5. 와~ 멋진 제품이 등장했네요! (+_+) 몬스터 트럭말고 스포츠카나 버기카 등 다양한 모델과 사이즈의 제품으로 출시되면 인기가 상당할 것 같습니다 어린애도 아닌데 너무 기대가 되네요 ㅎㅎㅎ

              2014.06.23 00:45 [ ADDR : EDIT/ DEL : REPLY ]
            6. 이상원

              죄송한데 rc카 조종하는 어플은 다운받으신건가여 ?

              아님 직접 제작하신건가요 ?

              혹시 다운받으신거나 퍼오신거면 출처좀 알수 있을까여?

              2014.08.21 10:40 [ ADDR : EDIT/ DEL : REPLY ]
              • 해머를 조정하는 어플은 앱스토어 같은 곳에서 받으시면 됩니다. 다만, 이 어플은 해머만 조정할 수 있습니다. 다른 RC카는 해당되지 않습니다.

                2014.08.25 23:18 신고 [ ADDR : EDIT/ DEL ]
            7. 속력은 어떻게 되는 건가요?
              제가 만족하는 속력은 시속 30km/h~40km/h라서요^^

              2014.11.12 22:28 [ ADDR : EDIT/ DEL : REPLY ]
            8. 안녕하세요 우연히 검색을 통해 오게되었습니다 자노라는 마이크로 드론이 있는데 이게 님이 마지막에 희망사항중 주인을 따라 다니는 기능이 있더라구요 요즘 참 좋아젔다는 생각이 드네요 자노 드론 검색한번해보세요 ^^

              2014.12.22 08:43 [ ADDR : EDIT/ DEL : REPLY ]
            9. 민수

              안녕하세요..저도 최근에 이제품 샀는데요.. 좌우 방향전환시에 방향이 바뀌고도 모터가 고속회전하는게 정상인가요? 이거원 소음도 크고 .. ㅠㅠ

              2015.01.05 21:58 [ ADDR : EDIT/ DEL : REPLY ]
            10. 민석

              해머는 어디서 샀나요???

              2016.08.30 15:17 [ ADDR : EDIT/ DEL : REPLY ]