워드캠프 참가 후기 및 XE에 대한 생각

3 Comments

오늘 코엑스에서 했던 워드캠프 서울2010 에 참가했었습니다.

참가 신청은 온오프믹스에서 이루어졌는데요 유료 행사임에도 불구하고 많은 사람들이 참가해서 워드프레스에 대한 사람들의 관심이 뜨거웠음을 알 수 있었습니다.

오늘 워드캠프는 처음열리는 워드캠프 답게 설치부터 설정 그리고 사례등의 소개가 이어졌습니다. 지난 몇일 동안 워드캠프를 사용하면서 또 일부 소스를 보고 오늘 설명을 들으면서 느낀점이 하나있어서 이렇게 글을 쓰게 되었네요.

워드프레스는 분명히 좋은 블로깅 툴이고 CMS 로서도 훌륭합니다만 이미 국내에서 봤던 XE(예전 명칭 제로보드) 도 훌륭합니다. 글쓸때의 에디터 창은 확실히 워드프레스보다 좋은 점이 많구요. 제가 부탁받아서 제작했던 홈페이지에 써봤던 경험상으로는 다국어 지원이나 HTML 편집 에디터에 강점을 가지고 있었습니다.

하지만 현재 상황으로 보면 앞으로 XE 보다는 워드프레스가 각광받을듯 싶습니다. 워드프레스의 테마나 플러그인의 다양성이 결국 그 중심에 있다고 봅니다. XE 가 국내에 기반이 있다보니 워드프레스보다 플러그인이나 테마가 부족한듯 하며,이건 우리나라의 인터넷 생태계 문제라고 봅니다. php 같은 스크립트 언어를 뒤떨어지는 기술 혹은 안좋게 생각하고 회사들에서 사용하지 않으니 스크립트언어를 하는 개발자는 점점줄어들고 XE 가 아무리 NHN의 지원을 받는다고 해도 플러그인을 개발해줄 외부 개발자가 많이 없을테니 말이죠. 외국에서는 개발언어 조사를 하면 JAVA 못지 않게 PHP 비중도 상당히 크니까 그만큼 플러그인도 나오는게 아닐까요? XE 는 작년쯤 플러그인이나 테마에 대해 경진대회 까지 열었지만 결과는 모르겠네요.

이번 워드캠프 참가를 계기로 워드프레스에 대해 좀더 많이 알게 되었고, 가능성도 보는 계기가 되었던것 같습니다

마지막으로 XE 라는 좋은 엔진이 묻히는것 같아서 아쉽고 XE 가 빨리 외국에서도 많이 사용되었으면 합니다.

병무청 그리고 예비군의 개인정보 삽질정책

No Comments

최근 예비군 훈련때문에 예비군 홈페이지에 들어갔다가 어이가 없어서 글을 적게 되었습니다.

요즘 예비군 훈련받으러 가면 이메일 주소와 핸드폰 번호등을 입력해달라고 하는 경우가 많습니다.
훈련 내용이나 장소등을 핸드폰과 이메일로 예비군 동대에서 알려주는거죠
또한 유사시 비상연락망으로 사용하게 되구요

그런데 오늘 예비군 홈페이지 갔다가 공지사항에 아래와 같은 이벤트를 하고 있는걸 보았습니다.
이메일로 병력동원이나 훈련 상황을 받아볼수 있게 신청하라 머 이런거죠
저는 실거주지와 주민등록상 거주지가 다르기 때문에 신청해야 겠다고 생각하고 신청을 했습니다
cfile2.uf.1747C9184BFB3C5C2D25E7 병무청 그리고 예비군의 개인정보 삽질정책
문제는 여기서 발생하는데요.
신청하기 버튼을 눌러서 들어가면 이름과 주민등록 번호를 입력하게 되어있습니다.
그러면 언제인가 입력했었던듯한 이메일주소와 핸드폰 번호가 나오게 됩니다
근데 이 이메일주소와 핸드폰 번호가 무려 2년전의 정보라는겁니다
(전 이미 안쓴지 오래되 기억도 안나는 핸드폰 번호가 있더군요)
예비군 홈페이지에서 조회할때는 분명히 최근에 갱신된 정보인데
병무청에서는 2년도 더 지난 다른 정보를 가지고 있었다는거죠.
설마해서 병무청에 가입하고 새로운 개인정보를 입력했는데도 마찬가지입니다.
이메일 병력동원신청에 사용하는 데이터는 병무청 인터넷회원 가입과 전혀 별개인거죠!
주민등록번호를 입력해 실명인증까지 했는데두요

만약 유사시 병무청에서 가지고 있는정보로 병력동원을 하려고 했다면
연락되지 않는 사람이 부지기수일듯 합니다.

도대체 왜 예비군, 병무청, 병무청 이메일주소신청에서는 같은 예비군에 대해 다른 정보를 가지고 있을까요?
군번이 엄연히 존재하기에 해당 정보로 인적자원의 정보를 한군데에서 통합관리하는게 맞을텐데요

전국의 대다수 남성의 데이터를 가지고 있는 군에서 이렇게 정보관리를 못해서야
대통령이 북한에 응분의 대가를 치르게 하고싶어해도 못하겠네요.

덧. 예전에 사단장이 새로 바뀌었을때가 생각나네요.
바뀌자마자 첫날 철책선 안쪽에서 이상한 불빛이 감지되어 사단CCC는 난리가 나서 저를 새벽에 깨우기에 바로 CCC에 가봤더니
사단장과 당직근무자만 덜렁있고 나머지 간부들은 한참 지난후에야 도착했었죠. 심지어 전화통화가 안되기도 했구요
다행히 이상한 동물의 눈빛이었습니다만 실제 상황이었다면 아찔한거죠
그 이후 사단장은 매달 간부들을 새벽에도 낯에도 비상소집하고 연락처 정보도 갱신했더랍니다.
당해봐야 알게되는게 진리일까요? 예측가능한 상황은 미리 대비해야 할텐데요.

구글 코드잼 2010 ThemaPark 문제 풀이

No Comments

작년에는 처음 접하는거고 그냥 풀면 되는줄 알고 참가해서 liquidbird 님 도움으로 겨우 Qualification Round 만 통과했었는데

(사실 통과한것도 아니다; 이미 라지셋으로 문제풀이하신분꺼로 계속 해보고 성공하고나서 올렸으니)

올해는 제대로 한번 해보자고 벼르고 있었는데 역시나 헛짓하다가 준비는 못하고
토요일날 점심에 팀원분 결혼식갔다가, 여자친구랑 서울역사박물관가서 서울의 예전 골목길 사진도 보고,
경희궁갔다가 저녁에 집에와서 부랴부랴 풀게 되었다. 원래는 세종문화회관도 가려고 했는데 안가서 다행
세종문화회관까지 같으면 아마 구글코드잼 그냥 안풀었을지도 모르겠다 -_-a
Qualification Round 에는 총 3개의 문제가 주어지는데 각각 스몰셋과 라지셋의 데이터가 주어진다.
이 중 한문제 이상 스몰셋과 라지셋을 모두 풀어야 통과되고 Round 1 에 진출할수 있는 자격을 얻게 되어진다.
우선 처음에 시도한건 1번째 문제였으나 영어를 제대로 하지 못해 헛짓하느라 시간 다보내고 스몰셋이 실패하길래
다른사람들의 스몰셋 성공률이 높은편인 3번째 문제에 도전했다.(다행히도 통과되었다)
3번째 문제는 ThemaPark 문제로 대략적인 문제는 다음과 같다.
(원본 문제 링크 http://code.google.com/codejam/contest/dashboard?c=433101#s=p2)

롤러코스터가 있는데 같이온 사람들은 서로 같이 타려고 하는 경향이 강하다는게 문제의 발단이다.
3명이서 같이 왔으면 앞 롤러코스터에 2자리가 남아있더라도 바로 안타고 그 다음껄 탄다는거다 
그렇다고 센스있게 뒤에 1명 혹은 2명이

기다리고

기다리고 있다고 먼저 태우지는 않는다 ㅎㅎ
이런식으로 사람을 태울때 하루에 얼마나 벌수 있나? 이걸 계산하는게 문제다.(한사람당 1유로)
아 그리고 이사람들은 롤러코스터 운행 끝날때 까지 죽어라고 다시 탄다고 한다. =_= 난 한번도 못타는데;

예를 들자면 [1명, 4명, 2명, 1명] 이렇게 줄을 서서 기다린다고 하고
롤러코스터 정원은 6명이라고 하면 
1회 : 1명 + 4명
2회 : 2명 + 1명 + 1명 
3회 : 4명 + 2명
4회 : 1명 + 1명 + 4명
이런식으로 운행하게 된다. 

(+) 참고로 정원이 100명이라고 해도 1,4, 2, 1 이렇게 밖에 못탄다는거 명심!
사람은 결국 그놈이 그놈이라서 더이상 탈사람이 없으니 =_=/

문제에서 변하는 값은 

롤러코스터 정원 : k

롤러코스터 하루 운행 횟수 : R
사람들 묶음 : gi
사람들 묶음 수 : N
이제 본격적으로 문제를 풀어보자
롤러코스터 운행에 따라서 사람들은 롤러코스터 운행이 종료될때까지 반복하게 된다. 
간단하게 보자면 같이온사람의 숫자를 배열로 만들고 롤러코스터 정원이 넘지 않도록 배열의 앞부분부터 빼서 태우면 된다.
그리고 한번 탄 그룹은 배열의 마지막에 넣고 이런식으로 롤러코스터 하루 운행횟수 만큼 반복하면 된다.
이런방식으로 풀게되면 스몰셋은 간단히 통과하지만 라지셋 데이터는 제한시간 8분 안에 답이 안나온다(슈퍼컴퓨터라면 모르겠지만)
이유는 라지셋 데이터의 경우 변수 범위가 아래와 같이 엄청 크기 때문이다.
1 ≤ R ≤ 100000000
1 ≤ k ≤ 1000000000
1 ≤ N ≤ 1000
1 ≤ gi ≤ 10000000
우선 롤러코스터 정원이 장난 아니고; 롤러코스터의 하루 운행횟수도 엄청나다.
그룹이 하나뿐이어서 더하는거 없이 그냥 R 번 반복하는 반복을 돈다고 해도 시간이 많이 걸리더라
(난 솔직히 컴퓨터가 엄청 빨리 해낼줄 알았는데 실망이다.)
라지셋을 풀기 위해서 변수 범위가 제일 작은게 N, 사람들 묶음의 수인데 이걸 활용하면 된다.
예제의 그룹 움직임을 잘살펴보면
[1,4] -> [2, 1, 1] -> [4, 2] -> [1, 1, 4] -> [2, 1, 1] -> [4, 2] -> [1, 1, 4]  이런식이다.
먼가 보이지 않나? 
첫번째를 제외한 [2, 1, 1] -> [4, 2] -> [1, 1, 4] 이 부분이 계속해서 반복하게 되는것이다.
이걸 잘 이용해서 반복되는 부분을 계속해서 R 까지 반복문 도는게 아니라 그냥 곱해 버리는거다.
예제로 보자면 R=4, k=6 이고 gi=[1,4,2,1]  일때
gi 를 반복하는 녀석이 나올때까지 k 를 넘지 않도록 조합하는거다.
그러면 새로운 unique_gi = [[1,4] , [2, 1, 1] , [4, 2] , [1, 1, 4]] 이렇게 된다.
그리고 반복하는 녀석의 시작 인덱스는 1 이고 , 반복길이는 3
여기서 sum 은 python 에서 해당 배열내부의 값을 모두 더해주는 함수이다.
하루 탑승 총인원수 
= 패턴에 포함되지 않는 경우 인원수 총합 + (패턴반복수*패턴의
인원수총합

인원수총합) + 불완전 패턴의 인원수총합

= sum(패턴에 포함되지 않는 조합) + (반복하는 패턴이 완벽히 나오는 횟수 * 반복하는 패턴의 인원수 총합) + sum(unique_gi[반복시작인덱스]) + ….  + sum(unique_gi[불완전 패턴의 인덱스])
= 5 + (1 * 16) + 0

이렇게 된다. 아이고 말로 설명하려니 어렵다. python 을 모르는 경우에 대해서도 설명하려니 배열쪽이 복잡하다;
핵심은 반복되는 패턴을 찾고 그 패턴의 총합을 곱하기 하여 반복문을 없애는게 되겠습니다.
python 코드를 첨부하니 자세한 사항은 소스를 보시면 되겠습니다.

[#M_python 소스보기|소스접기|

#!/usr/bin/python
class ThemePark:
  def __init__(self):
    self.outfile = open('third_other.out','w')
    self.infile = open('C-large.in','r')
    print "start"
   
  def __del__(self):
    self.outfile.close()
    self.infile.close()
    print "end"
   
  def set_first_line_read(self, line):
    split_str = line.split(" ")
    self.day_run = int(split_str[0])
    self.people_limit = int(split_str[1])
    self.max_group_index = int(split_str[2])
   
  def set_second_line_read(self, line):
    list = line.split(” “)
    self.group_list = map(lambda x:int(x), list)
   
  def set_group_iter(self):
    people = 0
    group_index = 0
    first_group_index = 0
    tmp_list = []
    while True:
      tmp_list.append(group_index)
      people += self.group_list[group_index]
      next_group_index = self.get_next_group_index(group_index)
      if (first_group_index == next_group_index) or (people + self.group_list[next_group_index] > self.people_limit):
        if self.group_unique.count(tmp_list) != 0:
          self.unique_start_index = self.group_unique.index(tmp_list)
          self.unique_length = len(self.group_unique) – self.unique_start_index
          break
        self.group_unique.append(tmp_list)
        self.group_unique_sum.append(people)
        tmp_list = []
        people = 0
        first_group_index = next_group_index
      group_index = next_group_index
   
  def process_init(self):
    self.group_unique = []
    self.group_unique_sum = []
    self.unique_start_index = -1
    self.unique_length = -1
       
  def process(self):
    self.process_init()
    test_time = 1
    for time, line in enumerate(self.infile):
      if time == 0:
        continue
      if time%2 == 1:
        self.set_first_line_read(line.strip())
        continue
      self.set_second_line_read(line.strip())
      self.set_group_iter()
      ”"”
      print self.group_unique
      print self.group_unique_sum
      print self.unique_start_index
      print self.unique_length
      ”"”
      self.print_result(test_time, self.get_money())
      self.process_init()
      test_time += 1
         
  def get_money(self):
    if self.unique_length == 1:
      return self.day_run * sum(self.group_unique_sum)
    non_unique_list = self.group_unique_sum[:self.unique_start_index]
    money = sum(non_unique_list)
    x_times = (self.day_run – len(non_unique_list)) / self.unique_length
    money += x_times * sum(self.group_unique_sum[self.unique_start_index:self.unique_start_index+self.unique_length])
    x_mod = (self.day_run – len(non_unique_list)) % self.unique_length
    money += sum(self.group_unique_sum[self.unique_start_index:self.unique_start_index + x_mod])
    return money
   
  def get_next_group_index(self, current_group_index):
    if current_group_index + 1 >= self.max_group_index:
      return 0
    return current_group_index + 1
   
  def print_result(self, time, money):
    result_str = “Case #%(time)s: %(money)s\n” % {‘time’:time, ‘money’:money}
    self.outfile.write(result_str)
a = ThemePark()
a.process()

_M#]

혹은 구글코드잼에서 제공하는 풀이가 있으니 확인해보세요 [http://code.google.com/codejam/contest/dashboard?c=433101#s=a&a=2]

Older Entries