IBM®
메인 컨텐츠로 가기
    Korea [국가변경]    이용약관
 
 
   
        제품    서비스 & 솔루션    고객지원 & 다운로드    회원 서비스    
메인 컨텐츠로 가기

한국 developerWorks  >  웹 개발  >

구글 코드 야구 핵: 구글 가젯으로 타율 표시하기

구글 가젯, 구글 스프레드시트 API, 구글 차트 API로 야구 핵을 만들어보자

developerWorks
문서 옵션

JavaScript가 필요한 문서 옵션은 디스플레이되지 않습니다.

영어원문

영어원문


제안 및 의견
피드백

난이도 : 중급

Paul D. Reiners, 소프트웨어 개발자, IBM
John S. Mysak, 소프트웨어 개발자, IBM
Paul DiCarlo, 소프트웨어 개발자, IBM

옮긴이: 박재호 이해영 dwkorea@kr.ibm.com

2008 년 10 월 28 일

이 기사에서는 몇 가지 구글 코드 API를 사용하여 야구 핵을 만들어 봅니다. 구체적으로는 메이저리그 야구 타율을 표시하는 구글 가젯을 만듭니다. 이 과정에서 구글 가젯, 구글 스프레드시트 API, 구글 차트 API를 익힙니다. 기사를 모두 이해하고 나면, 이런 API로 제작이 가능한 응용 프로그램 종류, 자신만의 응용 프로그램을 만드는 방법, 좀 더 상세한 정보를 얻는 방법을 익힐 것입니다. 이 기사는 구글 코드 야구 핵 연재 중 첫 번째 기사입니다.

소개

이 기사에서는 재미난 야구 핵을 구현하면서 세 가지 구글 코드 API를 사용하는 방법을 살펴본다. 기사가 따르는 형식과 기사에서 소개하는 예제 코드는 Joseph Adler가 집필한 멋진 책인 Baseball Hacks(참고자료 참조)를 참조했다. 여기서 사용하는 세 가지 구글 코드 API는 구글 차트 API, 구글 스프레드시트 API, 구글 가젯 API다. API 자체를 상세히 설명하지는 못하지만, 독자들의 흥미를 북돋우기에는 충분하리라 생각한다. 좀 더 자세한 내용이 궁금하다면 구글 문서와 튜토리얼을 참조하기 바란다. 이 기사를 작성한 목표는 자신이 가장 좋아하는 메이저리그 야구 팀의 최신 타율을 표시하는 구글 가젯을 만드는 데 있다. 세 단계를 거쳐 이 목표를 달성한다.

첫째, 야구 팀 웹 사이트에서 야구 통계를 내려받아 CSV 파일로 저장한다. 둘째, 구글 스프레드시트 API를 사용하여 통계 자료를 구글 스프레드시트로 업로드한다. 셋째, 구글 스프레드시트에서 통계 자료를 읽어 구글 차트 API를 사용해 막대 그래프로 표시하는 구글 가젯을 구현한다.




위로


웹에서 통계 자료 가져오기

가장 먼저, 웹에서 통계 자료를 내려받는다. 여기서 사용하는 코드는 Baseball Hacks에서 소개하는 "Hack #25: Spider Baseball Sites for Data"에서 가져왔다. 책에서 코드를 상세히 설명하므로 여기서 중복하지 않겠다. 이 단계에 해당하는 원시 코드는 get_all_teams_hitting.pl이라는 펄 프로그램과 GetStats.pm이라는 펄 모듈이다(원시 코드는 아래 다운로드 절에서 내려받는다). 단, 몇 가지 언급하고 넘어갈 사항이 있다.

첫째, 경기 결과(즉 득점 상황)를 제공하는 RSS 피드나 Atom 피드는 아주 많은 반면, 선수별 최신 통계를 제공하는 RSS 피드나 Atom 피드는 없는 듯이 보였다. 웹 피드가 존재한다면 웹 피드에서 통계 자료를 가져오는 방법이 맞다. 여기서는 어쩔 수 없이 HTML 페이지에서 자료를 긁어오는 방법을 택했다. 깔끔함이나 안정성과는 거리가 먼 방법이다. HTML이 갑자기 변하면 코드가 동작하지 않기 때문이다. 둘째, 웹 사이트에서 정보를 긁어오려면 먼저 사이트 소유자에게 동의를 구해야 한다. 항상 사이트 이용 약관(Terms of Use)을 꼼꼼히 확인한다. 셋째, 사이트에서 정보를 긁어와도 괜찮다면 정도를 지나치지 않도록 조심한다. 페이지를 연속적으로 읽을 때는 몇 초 정도 간격을 둔다. 예의도 예의지만, 자칫하면 사이트 접근 권한을 잃어버린다(실제로 코드를 테스트하는 과정에서 연속으로 페이지를 가져오다가 문제가 발생했다).




위로


구글 스프레드시트로 통계 자료 업로드하기

앞서 HTML 페이지에서 통계 자료를 추출한 후 팀마다 하나씩 CVS 파일로 저장했다. 이제 구글 스프레드시트로 자료를 업로드할 차례다. 나중에 구현할 구글 가젯은 구글 스프레드시트에서 통계 자료를 가져온다. 구글 스프레드시트 API를 사용하면 행이나 셀 단위로 내용을 추가, 수정, 삭제할 수 있다. 구글 스프레드시트 API가 지원하는 언어는 자바(Java™), .NET, PHP, 파이썬이다. 이 기사에서는 우리 필자들이 애용하는 파이썬을 사용했다.

파이썬 코드가 담긴 Listing 1은 CSV 파일을 하나씩 확인하면서 통계를 실제 스프레드시트로 업로드하는 코드를 호출한다(실제로 업로드를 수행하는 코드는 Listing 2에서 소개한다). 여기서 사용하는 또 다른 자료인 MLBTeams.csv는 팀 이름 목록을 포함하는 파일이다.


Listing 1. upload_all_teams_hitting.py 코드 일부
				
mlb_teams = open('../../data/MLBTeams.csv')
try:
      lines = mlb_teams.readlines( );
finally:
      mlb_teams.close( )             
  
# 헤더를 건너뛴다.
for line in lines[1:]:
    line = line.rstrip();
    if line != '':
        parts = line.split(",")  
        curr_wksht_id = parts[1].rstrip()
        teamAbbrev = parts[0].rstrip()
        print "Updating: " + teamAbbrev
        infile = "../../tempData/" + teamAbbrev + "Hitting.txt"
                
        uploader = Uploader(user, pw, infile)
        if curr_key != '':
            uploader.set_spreadsheet(curr_key)
        if curr_wksht_id != '':
            uploader.set_worksheet(curr_wksht_id)
        uploader.prompt_delete_old_rows_and_add_new_rows()

프로그램에서 구글 스프레드시트와 통신하는 방법은 두 가지다. 하나는 행 단위 피드이고, 다른 하나는 셀 단위 피드다. 우리 응용 프로그램에서는, 대개 경우 이전 행을 지우고 새 행을 생성하므로 행 단위 피드를 주로 사용한다.

우리가 사용하는 gdata.spreadsheet 메서드와 필드는 다음과 같다.

  • SpreadsheetsListFeed: 행 단위로 스프레드시트를 조작한다.
  • SpreadsheetsList: 스프레드시트 내 한 행을 가리킨다.
  • SpreadsheetsCellsFeed: 셀 단위로 스프레드시트를 조작한다.
    • row_count.text: 현재 작업 시트에 있는 행 수를 가리킨다.
  • service.SpreadsheetsService: 스프레드시트에 접근하는 클라이언트 API 객체다.
    • email: Gmail 계정
    • password: Gmail 암호
    • source: API를 사용하는 응용 프로그램 이름
    • ProgrammaticLogin(): 구글 계정으로 로그인한다.
    • GetCellsFeed(key, wksht_id): 스프레드시트 ID와 작업 시트 ID를 받아 스프레드시트의 셀 피드(SpreadsheetsCellsFeed)를 반환한다.
    • GetListFeed(key, wksht_id): 스프레드시트 ID와 작업 시트 ID를 받아 스프레드시트의 행 피드(SpreadsheetsListFeed)를 반환한다.
    • InsertRow(row_data, key, wksht_id): 스프레드시트에 새 행을 추가한다.
    • DeleteRow(entry): 스프레드시트에서 행(SpreadsheetsList)을 제거한다.

Listing 2는 타율 통계 자료를 구글 스프레드시트로 업로드하는 코드를 포함한다. 우선, (_delete_and_add_rows에서 보듯이) 현재 작업 시트에서 모든 행을 제거한다. 그런 다음, (_fill_in_rows에서 보듯이) .csv 파일에서 통계 자료를 가져와 새 행으로 추가한다.


Listing 2. upload_stats.py 코드 일부
				
import gdata.spreadsheet.service

class Uploader(CRUD):
    """
    Deletes old contents of a Google Worksheet and adds new contents from a .csv
    file.
    """

    def __init__(self, email, password, infile):
        "Uploader 속성을 초기화한다."
        self.gd_client = gdata.spreadsheet.service.SpreadsheetsService()
        self.gd_client.email = email
        self.gd_client.password = password
        self.gd_client.source = 'Upload Batting Stats'
        self.gd_client.ProgrammaticLogin()
        self.curr_key = ''
        self.curr_wksht_id = ''
        self.list_feed = None
        self.infile = infile
    
    def prompt_delete_old_rows_and_add_new_rows(self):
        """
        옛날 행을 삭제하고 새 행을 추가한다. 아직 설정되어 있지 않다면
        스프레드시트와 작업 시트 ID를 사용자에게 물어본다.
        """
        if not self.curr_key:
            self._PromptForSpreadsheet()
        if not self.curr_wksht_id:
            self._PromptForWorksheet()

        self._delete_and_add_rows()

    def _delete_and_add_rows(self):
        """
        먼저 (헤더 행을 제외한) 모든 행을 스프레드시트에서 삭제한 다음에
        행 추가를 위한 메서드를 호출한다.
        """
        cells_feed = self.gd_client.GetCellsFeed(self.curr_key, self.curr_wksht_id)
        row_count = int(cells_feed.row_count.text)
        while (row_count > 1):
            self._list_delete_action(0)
            cells_feed = self.gd_client.GetCellsFeed(self.curr_key, self.curr_wksht_id)
            row_count = int(cells_feed.row_count.text)
      
        self._fill_in_rows()
  
    def _list_delete_action(self, index):
        "매개변수 index가 가리키는 행을 삭제한다."
        self.list_feed = self.gd_client.GetListFeed(self.curr_key, self.curr_wksht_id)
        self.gd_client.DeleteRow(self.list_feed.entry[index])
        print 'Deleted!'
  
    def _fill_in_rows(self):
        "새로운 자료로 새로운 행을 만든다."
        infile = open(self.infile)
        header_line = infile.readline().strip()
        headers = header_line.split(',')
        col_count = len(headers)
        while infile:
            line = infile.readline().strip()
            if len(line) > 0:
                row_data = {}
                parts = line.split(',')
                for col in range(col_count):
                    row_data[headers[col].lower()] = parts[col].strip()
                try:
                    self._list_insert_action(row_data)
                except (gdata.service.RequestError, SyntaxError):
                    print 'Error inserting row:', row_data
                    print 'Will skip that row.'
            else:
                break;
    
    def _list_insert_action(self, row_data):
        "자료로 새 행을 추가한다."
        entry = self.gd_client.InsertRow(row_data,
            self.curr_key, self.curr_wksht_id)
        if isinstance(entry, gdata.spreadsheet.SpreadsheetsList):
            print 'Inserted!'

다음 절에서는 이 통계 자료를 구글 막대 그래프로 표시한다.




위로


구글 차트 API로 구글 막대 그래프 생성하기

구글 차트 API는 사용하기 쉽다. 특정한 google.com URL을 사용하면 된다. URL에 필요한 인수를 지정하면 구글 차트 API가 차트를 반환한다.

예제를 살펴보자. 그림 1은 우리가 그리려는 타율 막대 그래프다. 그래프는 타율 평균(AVG), 출루율(OBP), 장타율(SLG)을 보여준다.


그림 1. 구글 막대 그래프 예제
구글 막대 그래프 예제

Listing 3은 그림 1을 생성한 URL이다. URL을 간단히 훑어본 후 구성 요소를 자세히 설명하겠다.


Listing 3. 구글 차트 API를 사용하는 예제 URL
                
var chartURL = "http://chart.apis.google.com/chart?cht=bvg&" +
    "chd=t:0.284,0.299,0.271|0.328,0.37,0.298|0.355,0.494,0.4&chs=298x180&" +
    "chco=c6d9fd,4d89f9,8a31fb&chdl=AVG|OBP|SLG&chds=0,0.700&" + 
    "chtt=Minnesota%20Twins+Batting&chxt=y,x&" +
    "chxl=0:|0.000|0.100|0.200|0.300|0.400|0.500|0.600|0.700|" + 
    "1:|D+Young|J+Morneau|C+Gomez&chbh=15"

URL에서 각 인수가 의미하는 바는 다음과 같다.

  • cht: 차트 유형을 지정한다. bvg는 막대(bar) 그래프를 그룹(group) 지어 수직(vertical)으로 표시하라는 뜻이다.
  • chd: 차트로 표시할 자료다.
  • chs: 차트 크기를 픽셀 단위로 지정한다.
  • chco: 막대 색상을 지정한다.
  • chdl: 차트 자료에 붙일 레이블을 지정한다.
  • chds: 차트 배율을 지정한다.
  • chtt: 차트 제목을 지정한다.
  • chxt: 각 축의 방향을 지정한다.
  • chxl: 차트 레이블을 지정한다.
  • chbh: 막대 높이를 지정한다. 기본적으로 막대는 수평이다. 우리는 수직 막대 그래프를 그리므로 막대 너비에 해당하는 값이다.




위로


구글 가젯 만들기

마지막으로 구글 가젯을 만들 차례다. 구글 가젯은 iGoogle 페이지와 같은 웹 페이지 내부에 위치하는 위젯이다. XML, HTML, 자바스크립트 조합으로 이루어진다.

우리가 만든 구글 가젯은 그림 2와 같은 막대 그래프를 포함한다.


그림 2. 타율 구글 가젯
타율 구글 가젯

위에서 보듯이 구글 가젯은 사용자가 환경 설정을 변경할 수 있다. 우리가 만든 가젯은 팀을 선택하는 옵션과 표시할 선수 수 옵션을 제공한다.


그림 3. 환경 설정을 표시한 가젯
환경 설정을 표시한 가젯

Listing 4는 우리가 만든 가젯 코드다. 코드는 기본적으로 세 가지 작업을 수행한다.

  1. 구글 스프레드시트에서 타율 자료를 가져온다.
  2. 구글 차트 URL을 생성한다.
  3. 가젯 내 HTML에 차트를 추가한다.
JSON(JavaScript Object Notation) 피드로 스프레드시트에 있는 통계 자료를 가져오는데, 이 JSON 피드가 구글 스프레드시트 API를 사용한다. 이 JSON 피드는 listStats 콜백 함수로 넘겨지고, 이 함수에서 스프레드시트 자료를 분석한다.



Listing 4. mlb-batting-stats.xml 코드 일부
                
<Module>
 <ModulePrefs 
  title="MLB Batting Stats"
  screenshot="http://mrsabermetrics.sourceforge.net/images/MLBBattingScreenShot.PNG"
  description="Displays up-to-date MLB batting stats."
  height="200"
  width="675"
  thumbnail="http://mrsabermetrics.sourceforge.net/images/Babe_Ruth.jpg"
  title_url="http://mrsabermetrics.sourceforge.net/"
  scrolling="true"
 >
 </ModulePrefs>
 <UserPref name="num_players" display_name="How many players to show?" 
           datatype="enum" default_value="9" required="true">
  <EnumValue value="2" display_value="2"/>
  <EnumValue value="3" display_value="3"/>
  <EnumValue value="4" display_value="4"/>
    .
    .
    .
  <EnumValue value="15" display_value="15"/>
 </UserPref>
 <UserPref name="team" 
     display_name="Team"
     datatype="enum"
     required="true"
 >
  <EnumValue value="ARI" display_value="Arizona Diamondbacks"/>
  <EnumValue value="ATL" display_value="Atlanta Braves"/>
  <EnumValue value="BAL" display_value="Baltimore Orioles"/>
    .
    .
    .
  <EnumValue value="MON" display_value="Washington Nationals"/>
 </UserPref>
 <Content type="html">
<![CDATA[
<div id="statsdiv"></div>
<script>
    function listStats(root) {
        var feed = root.feed;
        var entries = feed.entry || [];
        var html = [''];
        var avgs = [];
        var obps = [];
        var slgs = [];
        var names = [];
            
        // 구글 차트를 위한 URL 생성
        var cht = 'bvg';
        html.push(
            '<img src="http://chart.apis.google.com/chart?cht=' + cht + '&chd=t:');
        for (var i = 0; i < feed.entry.length; ++i) {
            var entry = feed.entry[i];
            var title = entry.title.$t;
            names.push(title);
            var content = entry.content.$t;
            var parts = content.split(',');

            var avg = extractStat(parts[0]);
            avgs.push(avg);
            var obp = extractStat(parts[1]);
            obps.push(obp);
            var slg = extractStat(parts[2]);
            slgs.push(slg);
        }
        
        var numPlayersPref = getStringPref("num_players");

        // Show highest AB players
        var numPlayers = parseInt(numPlayersPref);
        if (numPlayers > names.length) {
            numPlayers = names.length;
        }
        
        for (var i = 0; i < numPlayers; ++i) {
            html.push(avgs[i]);
            if (i < numPlayers - 1) {
                html.push(",");
            }
        }
        html.push("|");
        
        for (var i = 0; i < numPlayers; ++i) {
            html.push(obps[i]);
            if (i < numPlayers - 1) {
                html.push(",");
            }
        }
        html.push("|");
        
        for (var i = 0; i < numPlayers; ++i) {
            html.push(slgs[i]);
            if (i < numPlayers - 1) {
                html.push(",");
            }
        }
        var width = 1000;
        if (numPlayers <= 9) {
            var width = 58 * numPlayers + 124;
        }
        var chs = width + 'x180';
        var chds = '0,0.700';
        html.push(
            "&chs=" + chs + 
                "&chco=c6d9fd,4d89f9,8a31fb&chdl=AVG|OBP|SLG&chds=" + chds);

        var teamAbbrevToName = new Object();
        for (var i = 0; i < teamInfoArray.length; i += 3) {
            teamAbbrevToName[teamInfoArray[i]] = teamInfoArray[i + 2];
        }  
        var teamName = teamAbbrevToName[getStringPref("team")]; 
        var chxt = 'y,x';
        html.push('&chtt=' + teamName + '+Batting&chxt=' + chxt + 
            '&chxl=0:|0.000|0.100|0.200|0.300|0.400|0.500|0.600|0.700|1:');
        
        for (var i = 0; i < numPlayers; ++i) {
            var parts = names[i].split(' ');
            name = parts.join("+");
            html.push('|' + name)
        }
        
        html.push('&chbh=15"/>');
        
        var generatedHTML = html.join("");
    
        // 가젯에 들어있는 HTML에 차트를 추가한다.
        document.getElementById("statsdiv").innerHTML = generatedHTML;
    }
    
    function extractStat(nameAndStat) {
        var parts = nameAndStat.split(":");
        var stat = parts[1];
        var fStat = parseFloat(stat);
        
        return fStat;
    }
  
    function getStringPref(prefName) {
        var prefs = new _IG_Prefs();
        var stringPref = prefs.getString(prefName);

        return stringPref;
    }
  
    var teamInfoArray = 
        new Array('MIN', 'od6', "Minnesota Twins", 'ANA', 'od7', "Los Angeles Angels", 
                  'ARI', 'od4', "Arizona Diamondbacks", 'ATL', 'od5', "Atlanta Braves", 
                  'BAL', 'oda', "Baltimore Orioles", 'BOS', 'odb', "Boston Red Sox", 
                    .
                    .
                    .
                  'TEX', 'ocm', "Texas Rangers", 'TOR', 'ocn', "Toronto Blue Jays");  
</script>
  
<script language="javascript">
    var teamToWkshtID = new Object(  );
    for (var i = 0; i < teamInfoArray.length; i += 3) {
        teamToWkshtID[teamInfoArray[i]] = teamInfoArray[i + 1];
    }  
    var wkshtID = teamToWkshtID[getStringPref("team")];
    
    // 구글 스프레드시트에서 타율을 가져온다.
    // 스프레드시트 API를 사용해 JSON 피드를 인출한다.
    var parmsrc = 
        "http://spreadsheets.google.com/feeds/list/" + 
            "o15075496074116042190.8006901556347913051/" + wkshtID + 
            "/public/basic?alt=json-in-script&callback=listStats"; 
    scriptNode = document.createElement('script');
    scriptNode.src = parmsrc;
    scriptNode.type = 'text/javascript';
    document.getElementsByTagName('head')[0].appendChild(scriptNode);
</script>
]]>

 </Content>
</Module>
        




위로


기타 고려 사항

우리가 만든 가젯은 개선할 여지가 있다. 몇 가지만 언급하자면 다음과 같다.

  • 막대에 정확한 값을 표현하면 좋겠다. 예를 들어, 마우스를 막대 위로 가져가면 (툴팁처럼) 정확한 값이 표시되면 좋겠다.
  • 팀 단위로 AVG/OBP/SLG 통계를 비교하는 기능이 있으면 좋겠다.
  • 가젯 코드를 보면 팀 목록을 배열로 관리하는데, 코드 자체에서 분리해 별도 텍스트 파일로 다른 곳에서 관리하면 좋겠다. 다른 한편으로 생각하면, (비록 "Devil Rays"가 "Rays"로 이름을 줄인 적이 있지만) 자주 바뀔 목록은 아니므로 코드에 그대로 두어도 심각한 문제는 아니라 생각한다.

스프레드시트라는 중간 과정을 거치지 않고 가젯 코드에서 웹 사이트 정보를 바로 가져와 통계를 내는 편이 낫다고 생각하는 독자도 있겠다. 스프레드시트를 중간 단계로 사용한 이유는 몇 가지가 있다. 첫째, 야구 통계는 하루에 한 번씩만 변하며 모든 사용자에게 똑같은 정보를 제공한다. 그러므로 불필요하게 야구 사이트에 부하를 걸 이유가 없다. 둘째, 이 기사는 다양한 구글 코드 API를 보여주려는 의도가 있다. 중간 단계에 사용한 스프레드시트는 구글 스프레드시트 API를 보여주는 좋은 예제가 되었다.

구글 가젯으로 구현할 수 있는 야구 가젯 종류는 아주 많다. Fantasy Baseball[옮긴이 주: 실제 스포츠 게임 통계와 결과를 토대로 하는 온라인 게임이다. 야구에만 국한하지 않고 다양한 Fantasy 스포츠 게임이 존재한다.] 팀을 관리한다면 온갖 가젯으로 상황판을 만들어도 재미있겠다.

현재 구글 가젯 외에도 다양한 위젯이 많이 나와 있다. 맥 OS X 대시보드 위젯도 인기 있는 위젯 중 하나다.




위로


결론

이 기사에서는 구글 가젯 API, 구글 스프레드시트 API, 구글 차트 API를 사용하여 간단한 웹 응용 프로그램을 만들어 보았다. 기사에서 제시한 코드 예제를 충분히 익힌다면 구글 코드 API를 사용하여 자신만의 응용 프로그램을 시작하기에 무리가 없으리라 믿는다. 좀 더 자세한 내용이 궁금하다면 참고자료 절을 살펴본다. 또한 Joseph Alder가 집필한 멋진 책인 Baseball Hacks도 읽어보라고 권한다. 야구를 별로 좋아하지 않는 독자라도 흥미로워 할 책이다.



다운로드 하십시오

Note

  1. 이 글에서 만든 구글 가젯


참고자료

교육
  • Baseball Hacks(Copyright 2006 O'Reilly Media, Inc., 0-596-00942-9): Joshep Alder가 집필한 책으로, 이 기사도 이 책에서 아이디어를 얻었다.

  • Moneyball: The Art of Winning an Unfair Game(Copyright 2004 W. W. Norton & Company, 978-0393324815): Michael M. Lewis가 집필한 책이다. 야구에서 통계를 객관적으로 사용하는 방법을 소개한다. 야구를 별로 좋아하지 않는 독자라도 흥미로워 할 책이다.[옮긴이 주: 머니볼(한스미디어, 2006년 출간)이라는 제목으로 한국어판이 나와 있다.]

  • 다음 사이트는 개발 키트와 자세한 정보를 제공한다.
  • 온라인 기술 서점: 다양한 기술 서적과 기술 자료를 제공한다.


토론


필자소개

Paul Reiners

Paul Reiners는 Catfish Hunter, Rollie Fingers, Vida Blue 등의 야구 선수들이 한창 활동하던 시절에 Oakland Athletics 팬이었다. 그는 Automatous Monk, Twisted Life, Leipzig 같은 오픈 소스 프로그램을 개발한 개발자다. UIUC(University of Illinois at Urbana-Champaign)에서 응용 수학(계산 이론) 석사 학위를 받았다. 현재 미네소타 주에 살며, 여가 시간에는 전기 베이스 기타를 연습하거나 TopCoder 대회에 참여한다.


John Mysak

John은 전직 포수로, 구글을 주 검색 엔진으로 오래동안 사용했다. John은 PowerWorship을 개발한 개발자이자 세상에서 가장 영리한 비글(개)의 주인이다.


Paul DiCarlo

Paul DiCarlo는 New York Yankees에서 투구하던 시절의 Catfish Hunter를 훨씬 좋아한다. 그는 현재 미네소타 주에 살면서 현악기 우쿨렐레를 배우려고 노력 중이다.




기사에 대한 평가


보다 나은 서비스를 제공하기 위함이오니 잠시 짬을 내어 이 양식을 제출하여 주십시오.



 


 


 


이 문서 북마킹 하기

mar.gar.in mar.gar.in naver naver eolin eolin del.icio.us del.icio.us





위로


Java and all Java-based trademarks and logos are trademarks of Sun Microsystems, Inc. in the United States, other countries, or both. 기타 회사, 제품, 및 서비스명은 다른 상표나 서비스 마크일 수 있습니다.

developerWorks 콘텐트를 다른 사이트에 전재하기:
developerWorks 콘텐트에 대한 저작권은 IBM에 있습니다. IBM의 서면 허가나 원본 저자의 허락이 없이는 전재를 금합니다. 저희 콘텐트를 전재하시려면 IBM developerWorks 담당자 에게 문의하십시오.
    IBM 소개 개인정보 보호정책 문의