2012년 2월 8일 수요일

onTouch() cannot differ views for multitouch

For few days, i was trying to apply multitouch on my application(game). My application uses multiple views and I want that the user can touch each view at the same time.
my code for single touch was...

onTouch(Veiw v, MotionEvent event){
    if(v==button1){
        ....
    } else if(v==button2){
        ......
    }

}

this style worked for single touch perfectly. So I could never doubt this won't differ the view I touched secondly(and more). But this method couldn't.

I'm not very well skilled programmer so not sure about there would be my fault. but for the if anybody has the same problem, just use "onTouchEvent(MotionEvent event)" and classify view by the position.

2012년 1월 30일 월요일

Accident on The Music Trend

There was hu~ge accident on one of main South Korean TV channel SBS 2 days ago. The Music Trend was on air like any other Sunday afternoon. But the problem was,,, while there was a performance of popular idol group T-ara, one of the 18-year-old member Hwayoung's cloth has been slipped and it was broadcasted live..
The song was "Lovey Dovey" and in the song T-ara dances shuffling(according to their management agency Core Contents Medias). Because she dances so tough, the accident happened according to the press.

It seems to be very painful for her because her pictures are spread on the Internet specially many masculine gag sites(ridiculous edited pics). South Korea has insane network bandwidth so anyone can download it in minutes.

In my memory, it's the first time that South Korean main TV station broadcasts female's nipple on air. "화영 인기가요" translated to "Hwayoung The Music Trend" is still the top search word on Korean leading portal site Naver.

begin

Today I'm very surprised that 100 guys have visited my blog.
This blog now has nothing but from today, I'll write many dedicated things about South Korea and my programming life.

I really appreciate your visiting.


p.s. - If you were a native English speaker and found some wired expression from my blog, please tell me for my English study. I'll be really happy :)

2011년 9월 29일 목요일

replyingtv - index.py

이 프로그램의 메인인 모듈인 index.py를 살펴보겠습니다.

# -*- coding: utf-8 -*-
'''
Created on 2011. 9. 14.

@author: Taejun Park

'''

from datetime import datetime, timedelta
import os
import logging

from google.appengine.api import memcache
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.db import djangoforms

#I made
import model
import getPrograms

#not yet attached
from django.utils import simplejson as json
 

def userLogging(self):
    """
    Args:
    self: page handler
    Returns:
    Logout(in) URL as a string, 'Login(out)'
    """
    if users.get_current_user():                                                        
        return users.create_logout_url(self.request.uri), 'Logout'
    else:
        return users.create_login_url(self.request.uri), 'Login'
    

def dateChanged(now):
    """
    Args:
    now : Datetime class
    Returns:
    True if changed, False if not    
    it checks wheather correct date was saved in the memcache/Parameter
    after it works, can use correct date guide
    """       
    
    today = now.date()
    
    programGuideDate = memcache.get("programGuideDate")
    
    #if memcache is empty
    if programGuideDate is None:
        parameter = model.Parameter.get_by_key_name(key_names='day')
        
        if parameter is None:   #if it is the first run
            model.Parameter(key_name='day', date=today ).put()
            if not memcache.add("programGuideDate", today): #save into memcache
                logging.error("Memcache set failed")
            return True
    
        programGuideDate = parameter.date
        
        if not memcache.add("programGuideDate", programGuideDate):  
            logging.error("Memcache set failed")
            
          
    if today > programGuideDate:    #if date changed
        #if now is after 4AM or more than 2days after
        if now.hour > 4 or today-programGuideDate > timedelta(1): 
            model.Parameter(key_name='day', date=today).put()
            if not memcache.add("programGuideDate", today):
                logging.error("Memcache set failed")
            return True
    #if not new day or tomorrow before 4am
    return False


def getBroadcastingProgramNow(broadcastingChannel):
    """
    Arg:
    broadcastingChannel : only KBS1 or KBS2 is supported now
    Return:
    ProgramGuide instance
    in this method, programLists: [program title+datetime] lists
    program = title+datetime+channel
    """    
    now = datetime.now()
    if dateChanged(now):  #if date changed, delete yesterday's program guide db with the same channel
        db.delete(model.ProgramGuide.gql("WHERE channel = :1", broadcastingChannel))
        
        #getPrograms returns [programtitle,datetime] as a list
        programLists = getPrograms.getPrograms(broadcastingChannel) #programs is list
        
        #parse programLists. the program name was got from KBS hompage so the encoding is euckr
        for program in programLists:
            model.ProgramGuide(key_name=program[0].decode('euckr', 'ignore'), programTime=program[1], channel=broadcastingChannel).put()
        
        #get if from db to match the type the same
        programs = model.ProgramGuide.gql("WHERE channel = :1 ORDER BY programTime ASC", broadcastingChannel)
        
        if not memcache.add(broadcastingChannel, programs):
            logging.error("Memcache set failed")
            
    else:   #check if the time pasts
        programs = memcache.get(broadcastingChannel)
        
        if programs is None:    #if memcache is empty, get it from db, add it to the memcache
            programs = model.ProgramGuide.gql("WHERE channel = :1 ORDER BY programTime ASC", broadcastingChannel)
            if not memcache.add(broadcastingChannel, programs):
                logging.error("Memcache set failed")
    
    #for ordered for clause. for more information, visit:
    #http://code.google.com/intl/ko-KR/appengine/docs/python/datastore/queries.html#Query_Cursors
    start_cursor = memcache.get("program_start_cursor")
    end_cursor = memcache.get("program_end_cursor")
    if start_cursor:
        programs.with_cursor(start_cursor = start_cursor)
    if end_cursor:
        programs.with_cursor(end_cursor = end_cursor)
    
    for program in programs:
        if program.programTime > now :  #if there's no program matches, it means there's no program now so return "화면조정"
            if not memcache.add("program_start_cursor", start_cursor):
                logging.error("Memcache set failed")    
            return program
    return None


class RecentCommentsPage(webapp.RequestHandler):
    """this class get 30 comments from db and match it for comments.html
    """
    def get(self):
        url, url_linktext = userLogging(self)
        comments = model.Comment.all().order('-written_datetime').fetch(30)
                    
        username = users.get_current_user()
                
        template_values={
                         'username':username,
                         'url':url,
                         'url_linktext':url_linktext,
                         'comments':comments,
                         }
        path=os.path.join(os.path.dirname(__file__), 'comments.html')
        self.response.out.write(template.render(path, template_values))
        
class MainPage(webapp.RequestHandler):
    """get which channel user want.
    then get what program is running now. get comments for the program
    send them to index.html
    """
    def get(self):
        #because there are not enough webpages, this program can only run over the KBSs.
        if self.request.path == '/2tv':
            channel = 'KBS2'
        else:
            channel = 'KBS1'    
        
        #get what program is running. probramNow programGuide Instance   
        programNow=getBroadcastingProgramNow(channel)
        
        if programNow is not None:        
            programInstance = model.Program.get_or_insert(key_name=programNow.key().name(), channel=channel)
            comments = model.Comment.gql("WHERE program = :program ORDER BY written_datetime DESC", program=programInstance).fetch(5)
            program = programNow.key().name()
        else:
            comments = None        
            program = None
        
        #make user signing up url
        url, url_linktext = userLogging(self)
        
        #HTML forms for POST
        form = ApplyingForm()
        
        username = users.get_current_user()

        template_values={
                         'channel':channel,
                         'head_title': '프로그램 목록',
                         'page_title': 'TV 프로그램 댓글',
                         'program': program,
                         'username': username,                                                
                         'url':url,
                         'url_linktext':url_linktext,   
                         'form': form,
                         'comments': comments                           
                         }
        path=os.path.join(os.path.dirname(__file__), 'index.html')
        self.response.out.write(template.render(path, template_values))
        
    #see http://code.google.com/intl/ko-KR/appengine/articles/djangoforms.html
    def post(self):
        #get POST requests
        data = ApplyingForm(data=self.request.POST)
        
        if data.is_valid():
            entity=data.save(commit=False)

            #get commenter: now this program saves email address of current user
            entity.commenter = users.get_current_user().email()
            
            entity.written_datetime =datetime.now()
            
            entity.written_via = 'replyingTV'  #later would be another platform
            
            #get program name from the web page, and get the model reference matches
            #first from the memcache, sencond from the db
            programNow = self.request.get('program')
            programInstance = memcache.get(programNow)
            if not programInstance:
                programInstance = model.Program.get_by_key_name(programNow)
            entity.program = programInstance
            
            try:         
                entity.put()    #save
            
            except :
                print "don't type that long, plz less than 500 bytes"
            finally:
            #redirect it to 2tv if it was from 2tv
                if self.request.get('channel') == 'KBS2':
                    self.redirect('/2tv', permenent=True)           
            
                self.redirect('')
            
        else:
            #redirect it to 2tv if it was from 2tv
            if self.request.get('channel') == 'KBS2':
                self.redirect('/2tv', permenent=True)           
        
            self.redirect('')
class ApplyingForm(djangoforms.ModelForm):
    """this class makes form for the Comment model
    see http://code.google.com/intl/ko-KR/appengine/articles/djangoforms.html
    """
    class Meta:
        model = model.Comment
        exclude=['commenter', 'written_datetime', 'program', 'written_via']
    
class TextPage(webapp.RequestHandler):
    """link to the replyingtv-program guide page
    """
    def get(self):
        self.redirect("http://tj850413.blogspot.com/", permanent=True)
        
def main():
    application = webapp.WSGIApplication([
                                          ('/about', TextPage),
                                          ('/2tv', MainPage),
                                          ('/comment', RecentCommentsPage),
                                          ('/.*', MainPage),
                                          ], debug=True)
    run_wsgi_app(application)
    
    
if __name__ == '__main__':
    main()

시간에 쫓겨 만들다보니 생각하던 것 보단 지저분한 코드가 나왔는데요, 하나하나 살펴보겠습니다.

def userLogging(self) - 앱엔진에서 제공하는 구글 id 로그인 모듈입니다. self클래스를 받아 로그인url과 문자열 login/logout을 리턴합니다. url은 나중에 index.html에서 로그인 url로써 쓰이고, 문자열login/logout은 역시 index.html에서 링크를 나타낼 때 쓰일 문자열입니다.

def dateChanged(now) - datetime인 now를 입력받아 편성표의 날짜가 바뀌었으면 True, 아니면 False를 리턴합니다.

def getBroadcastingProgramNow(broadcastingChannel) - broadCastingChannel을 입력받아 현재 채널의 방송중인 프로그램을 찾아  ProgramGuide 인스턴스를 리턴해줍니다.

class RecentCommentsPage(webapp.RequestHandler) - /comment 페이지의get메시지를 처리해줍니다. 코멘트를 위한 gql query를 보낸 후 최근의 30개만 보여줍니다.


class MainPage(webapp.RequestHandler) - 루트 페이지로 들어오는 get 및 post를 처리해줍니다. get 함수에선 Program 인스턴스를 등록해줍니다. post함수에선 html을 통해 들어온 새로운 comment를 등록해줍니다.


class ApplyingForm(djangoforms.ModelForm) - 장고의 모델폼을 상속하여, 폼을 등록하는데 사용하는 클래스입니다.


class TextPage(webapp.RequestHandler) - 이 블로그로 redirect해주는 클래스입니다.


def main() - WSGIApplication으로 각각의 페이지들을 유도해줍니다.

replyingtv - html파일들

replyingtv의 index.html입니다.
css등은 적용되지 않았고, template를 적용시키는 내용 외엔 복잡한 태그는 쓰이지 않았습니다.

<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-16" />	
		<title>{{ head_title }} - 현재 사용자: {{ username }}</title>
	</head>
	<body>
		{{ program }} 이 현재 방영되고 있습니다 | {{ channel }}
		<h1>{{ page_title }}</h1>
		<ul>{% for comment in comments %}
			<li>{{ comment.commenter }}
				{{ comment.written_datetime }} written via: {{ comment.written_via }}
				{{ comment.text }}
				<p/>
			</li>
			{% endfor %}
		</ul>
		{% if username and program %}
			<table border="1" align="center">
				<tr>
					<td width="100" align="center">사용자:</td> 
					<td>{{ username }}</td>
				</tr>
				<tr >
					<form method="post" action="." >
						{{ form.as_table }}
						<input type="hidden" name="program" value="{{ program }}">
					</form>
				</tr>
				<tr>
				</tr>
			</table>
		{% else %}{% if not program %}
			<p>현재 방송중인 프로그램을 얻을 수 없습니다</p>
		{% else %}		 
			<p>로그인 하세요</p>
		{% endif %}{% endif %}
		<a href="{{ url }}">{{ url_linktext }}</a> | 
		<a href="/comment">최근 댓글 페이지</a>
		<h2><a href="http://tj850413.blogspot.com/"> 이 사이트에 대하여</a></h2>
		
	</body>
</html>

앞부분에선 for문으로 comments를 통해 얻어온 내용들을 뿌려주며
아래쪽에선 user가 로그인해있고 program이 None이 아니면 comment입력 form을 형성해줍니다.
앱엔진에서 지원해주는 구글 로그인 url을 넣어주어 로그인했을 시엔 logout 링크가, 반대일때는 login이 뜨도록 하였습니다.
그 아래엔 최근 댓글들을 보여주는 링크가 있고
그 다음으론 이 블로그로 통하는 링크를 넣어주어습니다.

다음은 comments.html입니다.
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />	
		<title>최근 댓글 페이지 {{ username }}</title>
	</head>
	<body>
		<h1>최근에 등록 된 댓글 30개</h1>
			<ul>{% for comment in comments %}
			<li>{{ comment.text }} | 
				{{ comment.commenter }}
				{{ comment.program.key.name }}	
				{{ comment.written_datetime }} written via: {{ comment.written_via }}
				<p/>
			</li>

				{% endfor %}
			</ul>
		<a href="{{ url }}">{{ url_linktext }}</a> | 
		<a href="/">main page</a>
		
	</body>
</html>

여기에선 comment를 뿌려주는 일 외엔 별다른 설명할 부분이 없는 것 같습니다.

2011년 9월 30일 10시 40분 에러발생으로

갑자기 replyingtv가 에러가 발생해서 홈페이지를 이쪽으로 돌려놨습니다ㅠ
이번에도 로컬호스트에선 돌아가는데 앱엔진쪽엔 문제가 있네요... 고치고 있으니 나중에 다시 들려주세요ㅠㅠㅠ

http://replyingtv.appspot.com/2tv
를 들리시면 현재 상태를 아실 수 있습니다

2011년 9월 28일 수요일

replyingtv - model.py

replyingtv의 소스코드 중 모델 선언부분인 model.py를 살펴보겠습니다.

# -*- coding: utf-8 -*-

'''
Created on 2011. 9. 8.

@author: Park
'''

from google.appengine.ext import db 


class Program(db.Model):
    """this class saves the program titles, channel and the date which
    the program instance made
    """
    channel = db.StringProperty()
    date = db.DateTimeProperty(auto_now_add=True)

class Comment(db.Model):
    """this class saves comments
    program references the Program class.
    written_via is for the multi-platform extension.(ex i-phone, LGtv etc 
    """
    #if there would be another platform, 'commenter' should be changed as string or etc for many format
    commenter = db.EmailProperty()
    written_datetime = db.DateTimeProperty()
    program = db.ReferenceProperty(Program)
    written_via = db.StringProperty()
    text = db.StringProperty()

class Parameter(db.Model):
    """this class is for saving some parameters which need to run
    the whole program.
    2011.09.29: now only has date.
    """
    date = db.DateProperty()
    
class ProgramGuide(db.Model):
    """it saves the channel guide today. channel and program time, and
    the title as a key_name. 
    """
    programTime = db.DateTimeProperty()
    channel = db.StringProperty(multiline=True)   #ex) kbs1, kbs2 ...


별다른 어려운 부분은 없지만, Parameter 클래스는 변수 몇가지를 저장하기 위해 모델을 만들어 쓰게 돼서, 다른 방법이 없을까 하는 생각도 들었습니다만 뾰족한 방법을 모르겠네요
function foo()
{
}