commit 493ff79fa012a72c2a1333c454818533eeb16138
Author: みぞ@CrazyBeatCoder <mizo0203@mizo0203.com>
Date:   Sat Aug 18 02:43:07 2018 +0900

    Change application name from TwitterTimelineTalker to TimelineTalker.

diff --git a/.idea/artifacts/TimelineTalker_jar.xml b/.idea/artifacts/TimelineTalker_jar.xml
new file mode 100644
index 0000000..28e1340
--- /dev/null
+++ b/.idea/artifacts/TimelineTalker_jar.xml
@@ -0,0 +1,10 @@
+<component name="ArtifactManager">
+  <artifact type="jar" name="TimelineTalker:jar">
+    <output-path>$PROJECT_DIR$/out/artifacts/TimelineTalker_jar</output-path>
+    <root id="archive" name="TimelineTalker.jar">
+      <element id="module-output" name="TimelineTalker"/>
+      <element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/twitter4j/twitter4j-core/4.0.6/twitter4j-core-4.0.6.jar" path-in-jar="/" />
+      <element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/twitter4j/twitter4j-stream/4.0.6/twitter4j-stream-4.0.6.jar" path-in-jar="/" />
+    </root>
+  </artifact>
+</component>
\ No newline at end of file
diff --git a/.idea/artifacts/TwitterTimelineTalker_jar.xml b/.idea/artifacts/TwitterTimelineTalker_jar.xml
deleted file mode 100644
index a088a71..0000000
--- a/.idea/artifacts/TwitterTimelineTalker_jar.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<component name="ArtifactManager">
-  <artifact type="jar" name="TwitterTimelineTalker:jar">
-    <output-path>$PROJECT_DIR$/out/artifacts/TwitterTimelineTalker_jar</output-path>
-    <root id="archive" name="TwitterTimelineTalker.jar">
-      <element id="module-output" name="TwitterTimelineTalker" />
-      <element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/twitter4j/twitter4j-core/4.0.6/twitter4j-core-4.0.6.jar" path-in-jar="/" />
-      <element id="extracted-dir" path="$MAVEN_REPOSITORY$/org/twitter4j/twitter4j-stream/4.0.6/twitter4j-stream-4.0.6.jar" path-in-jar="/" />
-    </root>
-  </artifact>
-</component>
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 6c0d958..87a23b6 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -6,11 +6,11 @@
         <sourceOutputDir name="target/generated-sources/annotations" />
         <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
         <outputRelativeToContentRoot value="true" />
-        <module name="TwitterTimelineTalker" />
+        <module name="TimelineTalker"/>
       </profile>
     </annotationProcessing>
     <bytecodeTargetLevel>
-      <module name="TwitterTimelineTalker" target="1.7" />
+      <module name="TimelineTalker" target="1.7"/>
     </bytecodeTargetLevel>
   </component>
 </project>
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index c40df5a..859a6fb 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,7 +2,7 @@
 <project version="4">
   <component name="ProjectModuleManager">
     <modules>
-      <module fileurl="file://$PROJECT_DIR$/TwitterTimelineTalker.iml" filepath="$PROJECT_DIR$/TwitterTimelineTalker.iml" />
+      <module fileurl="file://$PROJECT_DIR$/TimelineTalker.iml" filepath="$PROJECT_DIR$/TimelineTalker.iml"/>
     </modules>
   </component>
 </project>
\ No newline at end of file
diff --git a/TimelineTalker.iml b/TimelineTalker.iml
new file mode 100644
index 0000000..bceb6db
--- /dev/null
+++ b/TimelineTalker.iml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
+    <output url="file://$MODULE_DIR$/target/classes" />
+    <output-test url="file://$MODULE_DIR$/target/test-classes" />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+      <excludeFolder url="file://$MODULE_DIR$/target" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="Maven: org.twitter4j:twitter4j-core:4.0.6" level="project" />
+    <orderEntry type="library" name="Maven: org.twitter4j:twitter4j-stream:4.0.6" level="project" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/TwitterTimelineTalker.iml b/TwitterTimelineTalker.iml
deleted file mode 100644
index bceb6db..0000000
--- a/TwitterTimelineTalker.iml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
-  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
-    <output url="file://$MODULE_DIR$/target/classes" />
-    <output-test url="file://$MODULE_DIR$/target/test-classes" />
-    <content url="file://$MODULE_DIR$">
-      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
-      <excludeFolder url="file://$MODULE_DIR$/target" />
-    </content>
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="library" name="Maven: org.twitter4j:twitter4j-core:4.0.6" level="project" />
-    <orderEntry type="library" name="Maven: org.twitter4j:twitter4j-stream:4.0.6" level="project" />
-  </component>
-</module>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index b4ba65d..839bed9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
 	<modelVersion>4.0.0</modelVersion>
 
 	<groupId>com.mizo0203</groupId>
-	<artifactId>TwitterTimelineTalker</artifactId>
+	<artifactId>TimelineTalker</artifactId>
 	<version>0.0.1-SNAPSHOT</version>
 	<packaging>jar</packaging>
 
diff --git a/src/META-INF/MANIFEST.MF b/src/META-INF/MANIFEST.MF
index 3429757..3f5f332 100644
--- a/src/META-INF/MANIFEST.MF
+++ b/src/META-INF/MANIFEST.MF
@@ -1,3 +1,3 @@
 Manifest-Version: 1.0
-Main-Class: com.mizo0203.twitter.timeline.talker.Application
+Main-Class: com.mizo0203.timeline.talker.Application
 
diff --git a/src/com/mizo0203/timeline/talker/Application.java b/src/com/mizo0203/timeline/talker/Application.java
new file mode 100644
index 0000000..5258e30
--- /dev/null
+++ b/src/com/mizo0203/timeline/talker/Application.java
@@ -0,0 +1,79 @@
+package com.mizo0203.timeline.talker;
+
+import twitter4j.conf.Configuration;
+import twitter4j.conf.ConfigurationBuilder;
+
+/**
+ * Java アプリケーション起動時に実行されるクラス
+ * 
+ * @author みぞ@CrazyBeatCoder
+ */
+public class Application {
+
+  public static void main(String[] args) {
+    TimelineTalker timelineTalker;
+    Talker talker;
+
+    try {
+      talker = new Talker();
+      timelineTalker =
+              new TimelineTalker(new Arguments(args).twitterConfiguration, talker);
+    } catch (IllegalArgumentException | IllegalStateException e) {
+      System.err.println(e.getMessage());
+      return;
+    }
+
+    timelineTalker.start();
+    talker.talkAsync("アプリケーションを起動しました", Talker.YukkuriVoice.REIMU);
+  }
+
+  /**
+   * Java アプリケーション起動時に指定する引数のデータクラス
+   * 
+   * @author みぞ@CrazyBeatCoder
+   */
+  private static class Arguments {
+
+    private final Configuration twitterConfiguration;
+
+    private Arguments(String[] args) throws IllegalArgumentException {
+      if (args.length < Argument.values().length) {
+        StringBuilder exceptionMessage = new StringBuilder();
+        exceptionMessage.append(Argument.values().length + " つの引数を指定してください。\n");
+        for (Argument arg : Argument.values()) {
+          exceptionMessage.append((arg.ordinal() + 1) + " つ目: " + arg.detail + "\n");
+        }
+        throw new IllegalArgumentException(exceptionMessage.toString());
+      }
+
+      String consumer_key = args[Argument.CONSUMER_KEY.ordinal()];
+      String consumer_secret = args[Argument.CONSUMER_SECRET.ordinal()];
+      String access_token = args[Argument.ACCESS_TOKEN.ordinal()];
+      String access_token_secret = args[Argument.ACCESS_TOKEN_SECRET.ordinal()];
+
+      twitterConfiguration = new ConfigurationBuilder().setOAuthConsumerKey(consumer_key)
+          .setOAuthConsumerSecret(consumer_secret).setOAuthAccessToken(access_token)
+          .setOAuthAccessTokenSecret(access_token_secret).build();
+    }
+
+  }
+
+  /**
+   * Java アプリケーション起動時に指定する引数の定義
+   * 
+   * @author みぞ@CrazyBeatCoder
+   */
+  private enum Argument {
+    CONSUMER_KEY("Twitter Application's Consumer Key (API Key)"), //
+    CONSUMER_SECRET("Twitter Application's Consumer Secret (API Secret)"), //
+    ACCESS_TOKEN("Twitter Account's Access Token"), //
+    ACCESS_TOKEN_SECRET("Twitter Account's Access Token Secret"), //
+    ;
+
+    private final String detail;
+
+    private Argument(String detail) {
+      this.detail = detail;
+    }
+  }
+}
diff --git a/src/com/mizo0203/timeline/talker/RuntimeUtil.java b/src/com/mizo0203/timeline/talker/RuntimeUtil.java
new file mode 100644
index 0000000..a528d7a
--- /dev/null
+++ b/src/com/mizo0203/timeline/talker/RuntimeUtil.java
@@ -0,0 +1,17 @@
+package com.mizo0203.timeline.talker;
+
+import java.io.IOException;
+
+public class RuntimeUtil {
+
+  public static void execute(String[] cmdarray) {
+    try {
+      Process process = Runtime.getRuntime().exec(cmdarray);
+      process.waitFor();
+      process.destroy();
+    } catch (IOException | InterruptedException e) {
+      e.printStackTrace();
+    }
+  }
+
+}
diff --git a/src/com/mizo0203/timeline/talker/Talker.java b/src/com/mizo0203/timeline/talker/Talker.java
new file mode 100644
index 0000000..c464c6b
--- /dev/null
+++ b/src/com/mizo0203/timeline/talker/Talker.java
@@ -0,0 +1,67 @@
+package com.mizo0203.timeline.talker;
+
+import java.io.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class Talker {
+
+  private static final String AQUESTALK_PI_PATH = "./aquestalkpi/AquesTalkPi";
+
+  private final ExecutorService mSingleThreadExecutor = Executors.newSingleThreadExecutor();
+
+  public Talker() throws IllegalStateException, SecurityException {
+    File file = new File(AQUESTALK_PI_PATH);
+    if (!file.isFile()) {
+      throw new IllegalStateException(file.getPath() + " に AquesTalk Pi がありません。\n"
+          + "https://www.a-quest.com/products/aquestalkpi.html\n" + "からダウンロードしてください。");
+    }
+    if (!file.canExecute()) {
+      throw new IllegalStateException(file.getPath() + " に実行権限がありません。");
+    }
+  }
+
+  public void talkAsync(final String text, final YukkuriVoice voice) {
+    mSingleThreadExecutor.submit(new Runnable() {
+
+      @Override
+      public void run() {
+        try {
+          File file = new File("text.txt");
+          PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));
+          pw.println(text);
+          pw.flush();
+          pw.close();
+          RuntimeUtil.execute(new String[] {AQUESTALK_PI_PATH, "-v", voice.value, "-f", "text.txt",
+              "-o", "out.wav"});
+          RuntimeUtil.execute(new String[] {"sh", "-c", "aplay < out.wav"}); // 起動コマンドを指定する
+          Thread.sleep(2000);
+        } catch (IOException | InterruptedException e) {
+          e.printStackTrace();
+        }
+      }
+
+    });
+  }
+
+  public static enum YukkuriVoice {
+
+    /**
+     * ゆっくりボイス - 霊夢
+     */
+    REIMU("f1"), //
+
+    /**
+     * ゆっくりボイス - 魔理沙
+     */
+    MARISA("f2"), //
+    ;
+
+    private final String value;
+
+    private YukkuriVoice(String value) {
+      this.value = value;
+    }
+  }
+
+}
diff --git a/src/com/mizo0203/timeline/talker/TimelineTalker.java b/src/com/mizo0203/timeline/talker/TimelineTalker.java
new file mode 100644
index 0000000..7df6c64
--- /dev/null
+++ b/src/com/mizo0203/timeline/talker/TimelineTalker.java
@@ -0,0 +1,88 @@
+package com.mizo0203.timeline.talker;
+
+import twitter4j.*;
+import twitter4j.conf.Configuration;
+
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class TimelineTalker {
+
+  /**
+   * ISO 639 言語コード - 日本語 (ja)
+   */
+  public static final String LANG_JA = Locale.JAPAN.getLanguage();
+
+  private Talker.YukkuriVoice mYukkuriVoice = Talker.YukkuriVoice.REIMU;
+  private final TwitterStream mTwitterStream;
+  private final Talker mTalker;
+
+  public TimelineTalker(Configuration configuration, Talker talker) {
+    mTwitterStream = new TwitterStreamFactory(configuration).getInstance();
+    mTwitterStream.addListener(new OnStatusEvent());
+    mTalker = talker;
+  }
+
+  public void start() {
+    // OnStatusEvent に Twitter タイムラインが通知される
+    mTwitterStream.user();
+  }
+
+  private static String getUserNameWithoutContext(String name) {
+    Pattern p = Pattern.compile("([^@＠]+).+");
+    Matcher m = p.matcher(name);
+    return m.replaceFirst("$1");
+  }
+
+  private class OnStatusEvent implements StatusListener {
+
+    public void onStatus(final Status status) {
+      if (!LANG_JA.equalsIgnoreCase(status.getLang())) {
+        return;
+      }
+
+      final StringBuffer buffer = new StringBuffer();
+
+      if (status.isRetweet()) {
+        Status retweetedStatus = status.getRetweetedStatus();
+        buffer.append(getUserNameWithoutContext(status.getUser().getName()) + "さんがリツイート。");
+        buffer.append(getUserNameWithoutContext(retweetedStatus.getUser().getName()) + "さんから、");
+        buffer.append(retweetedStatus.getText());
+      } else {
+        buffer.append(getUserNameWithoutContext(status.getUser().getName()) + "さんから、");
+        buffer.append(status.getText());
+      }
+
+      mTalker.talkAsync(UrlUtil.convURLEmpty(buffer).replaceAll("\n", "。"), mYukkuriVoice);
+
+      // 読み上げは、霊夢と魔理沙が交互に行なう
+      if (mYukkuriVoice == Talker.YukkuriVoice.REIMU) {
+        mYukkuriVoice = Talker.YukkuriVoice.MARISA;
+      } else {
+        mYukkuriVoice = Talker.YukkuriVoice.REIMU;
+      }
+
+    }
+
+    public void onDeletionNotice(StatusDeletionNotice sdn) {
+      System.err.println("onDeletionNotice.");
+    }
+
+    public void onTrackLimitationNotice(int i) {
+      System.err.println("onTrackLimitationNotice.(" + i + ")");
+    }
+
+    public void onScrubGeo(long lat, long lng) {
+      System.err.println("onScrubGeo.(" + lat + ", " + lng + ")");
+    }
+
+    public void onException(Exception excptn) {
+      System.err.println("onException.");
+    }
+
+    @Override
+    public void onStallWarning(StallWarning arg0) {}
+  }
+
+}
diff --git a/src/com/mizo0203/timeline/talker/UrlUtil.java b/src/com/mizo0203/timeline/talker/UrlUtil.java
new file mode 100644
index 0000000..d082595
--- /dev/null
+++ b/src/com/mizo0203/timeline/talker/UrlUtil.java
@@ -0,0 +1,24 @@
+package com.mizo0203.timeline.talker;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * http://chat-messenger.net/blog-entry-40.html
+ */
+public class UrlUtil {
+  /** URLを抽出するための正規表現パターン */
+  private static final Pattern convURLLinkPtn = Pattern.compile(
+      "(http://|https://){1}[\\w\\.\\-/:\\#\\?\\=\\&\\;\\%\\~\\+]+", Pattern.CASE_INSENSITIVE);
+
+  /**
+   * 指定された文字列内のURLを、正規表現を使用し、 空文字列に変換する。
+   * 
+   * @param str 指定の文字列。
+   * @return リンクに変換された文字列。
+   */
+  public static String convURLEmpty(CharSequence str) {
+    Matcher matcher = convURLLinkPtn.matcher(str);
+    return matcher.replaceAll("");
+  }
+}
diff --git a/src/com/mizo0203/twitter/timeline/talker/Application.java b/src/com/mizo0203/twitter/timeline/talker/Application.java
deleted file mode 100644
index 79f51a3..0000000
--- a/src/com/mizo0203/twitter/timeline/talker/Application.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package com.mizo0203.twitter.timeline.talker;
-
-import twitter4j.conf.Configuration;
-import twitter4j.conf.ConfigurationBuilder;
-
-/**
- * Java アプリケーション起動時に実行されるクラス
- * 
- * @author みぞ@CrazyBeatCoder
- */
-public class Application {
-
-  public static void main(String[] args) {
-    TwitterTimelineTalker twitterTimelineTalker;
-    Talker talker;
-
-    try {
-      talker = new Talker();
-      twitterTimelineTalker =
-          new TwitterTimelineTalker(new Arguments(args).twitterConfiguration, talker);
-    } catch (IllegalArgumentException | IllegalStateException e) {
-      System.err.println(e.getMessage());
-      return;
-    }
-
-    twitterTimelineTalker.start();
-    talker.talkAsync("アプリケーションを起動しました", Talker.YukkuriVoice.REIMU);
-  }
-
-  /**
-   * Java アプリケーション起動時に指定する引数のデータクラス
-   * 
-   * @author みぞ@CrazyBeatCoder
-   */
-  private static class Arguments {
-
-    private final Configuration twitterConfiguration;
-
-    private Arguments(String[] args) throws IllegalArgumentException {
-      if (args.length < Argument.values().length) {
-        StringBuilder exceptionMessage = new StringBuilder();
-        exceptionMessage.append(Argument.values().length + " つの引数を指定してください。\n");
-        for (Argument arg : Argument.values()) {
-          exceptionMessage.append((arg.ordinal() + 1) + " つ目: " + arg.detail + "\n");
-        }
-        throw new IllegalArgumentException(exceptionMessage.toString());
-      }
-
-      String consumer_key = args[Argument.CONSUMER_KEY.ordinal()];
-      String consumer_secret = args[Argument.CONSUMER_SECRET.ordinal()];
-      String access_token = args[Argument.ACCESS_TOKEN.ordinal()];
-      String access_token_secret = args[Argument.ACCESS_TOKEN_SECRET.ordinal()];
-
-      twitterConfiguration = new ConfigurationBuilder().setOAuthConsumerKey(consumer_key)
-          .setOAuthConsumerSecret(consumer_secret).setOAuthAccessToken(access_token)
-          .setOAuthAccessTokenSecret(access_token_secret).build();
-    }
-
-  }
-
-  /**
-   * Java アプリケーション起動時に指定する引数の定義
-   * 
-   * @author みぞ@CrazyBeatCoder
-   */
-  private enum Argument {
-    CONSUMER_KEY("Twitter Application's Consumer Key (API Key)"), //
-    CONSUMER_SECRET("Twitter Application's Consumer Secret (API Secret)"), //
-    ACCESS_TOKEN("Twitter Account's Access Token"), //
-    ACCESS_TOKEN_SECRET("Twitter Account's Access Token Secret"), //
-    ;
-
-    private final String detail;
-
-    private Argument(String detail) {
-      this.detail = detail;
-    }
-  }
-}
diff --git a/src/com/mizo0203/twitter/timeline/talker/RuntimeUtil.java b/src/com/mizo0203/twitter/timeline/talker/RuntimeUtil.java
deleted file mode 100644
index c0c225b..0000000
--- a/src/com/mizo0203/twitter/timeline/talker/RuntimeUtil.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.mizo0203.twitter.timeline.talker;
-
-import java.io.IOException;
-
-public class RuntimeUtil {
-
-  public static void execute(String[] cmdarray) {
-    try {
-      Process process = Runtime.getRuntime().exec(cmdarray);
-      process.waitFor();
-      process.destroy();
-    } catch (IOException | InterruptedException e) {
-      e.printStackTrace();
-    }
-  }
-
-}
diff --git a/src/com/mizo0203/twitter/timeline/talker/Talker.java b/src/com/mizo0203/twitter/timeline/talker/Talker.java
deleted file mode 100644
index e27775c..0000000
--- a/src/com/mizo0203/twitter/timeline/talker/Talker.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.mizo0203.twitter.timeline.talker;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-public class Talker {
-
-  private static final String AQUESTALK_PI_PATH = "./aquestalkpi/AquesTalkPi";
-
-  private final ExecutorService mSingleThreadExecutor = Executors.newSingleThreadExecutor();
-
-  public Talker() throws IllegalStateException, SecurityException {
-    File file = new File(AQUESTALK_PI_PATH);
-    if (!file.isFile()) {
-      throw new IllegalStateException(file.getPath() + " に AquesTalk Pi がありません。\n"
-          + "https://www.a-quest.com/products/aquestalkpi.html\n" + "からダウンロードしてください。");
-    }
-    if (!file.canExecute()) {
-      throw new IllegalStateException(file.getPath() + " に実行権限がありません。");
-    }
-  }
-
-  public void talkAsync(final String text, final YukkuriVoice voice) {
-    mSingleThreadExecutor.submit(new Runnable() {
-
-      @Override
-      public void run() {
-        try {
-          File file = new File("text.txt");
-          PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));
-          pw.println(text);
-          pw.flush();
-          pw.close();
-          RuntimeUtil.execute(new String[] {AQUESTALK_PI_PATH, "-v", voice.value, "-f", "text.txt",
-              "-o", "out.wav"});
-          RuntimeUtil.execute(new String[] {"sh", "-c", "aplay < out.wav"}); // 起動コマンドを指定する
-          Thread.sleep(2000);
-        } catch (IOException | InterruptedException e) {
-          e.printStackTrace();
-        }
-      }
-
-    });
-  }
-
-  public static enum YukkuriVoice {
-
-    /**
-     * ゆっくりボイス - 霊夢
-     */
-    REIMU("f1"), //
-
-    /**
-     * ゆっくりボイス - 魔理沙
-     */
-    MARISA("f2"), //
-    ;
-
-    private final String value;
-
-    private YukkuriVoice(String value) {
-      this.value = value;
-    }
-  }
-
-}
diff --git a/src/com/mizo0203/twitter/timeline/talker/TwitterTimelineTalker.java b/src/com/mizo0203/twitter/timeline/talker/TwitterTimelineTalker.java
deleted file mode 100644
index cb4d47f..0000000
--- a/src/com/mizo0203/twitter/timeline/talker/TwitterTimelineTalker.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package com.mizo0203.twitter.timeline.talker;
-
-import java.util.Locale;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import twitter4j.StallWarning;
-import twitter4j.Status;
-import twitter4j.StatusDeletionNotice;
-import twitter4j.StatusListener;
-import twitter4j.TwitterStream;
-import twitter4j.TwitterStreamFactory;
-import twitter4j.conf.Configuration;
-
-public class TwitterTimelineTalker {
-
-  /**
-   * ISO 639 言語コード - 日本語 (ja)
-   */
-  public static final String LANG_JA = Locale.JAPAN.getLanguage();
-
-  private Talker.YukkuriVoice mYukkuriVoice = Talker.YukkuriVoice.REIMU;
-  private final TwitterStream mTwitterStream;
-  private final Talker mTalker;
-
-  public TwitterTimelineTalker(Configuration configuration, Talker talker) {
-    mTwitterStream = new TwitterStreamFactory(configuration).getInstance();
-    mTwitterStream.addListener(new OnStatusEvent());
-    mTalker = talker;
-  }
-
-  public void start() {
-    // OnStatusEvent に Twitter タイムラインが通知される
-    mTwitterStream.user();
-  }
-
-  private static String getUserNameWithoutContext(String name) {
-    Pattern p = Pattern.compile("([^@＠]+).+");
-    Matcher m = p.matcher(name);
-    return m.replaceFirst("$1");
-  }
-
-  private class OnStatusEvent implements StatusListener {
-
-    public void onStatus(final Status status) {
-      if (!LANG_JA.equalsIgnoreCase(status.getLang())) {
-        return;
-      }
-
-      final StringBuffer buffer = new StringBuffer();
-
-      if (status.isRetweet()) {
-        Status retweetedStatus = status.getRetweetedStatus();
-        buffer.append(getUserNameWithoutContext(status.getUser().getName()) + "さんがリツイート。");
-        buffer.append(getUserNameWithoutContext(retweetedStatus.getUser().getName()) + "さんから、");
-        buffer.append(retweetedStatus.getText());
-      } else {
-        buffer.append(getUserNameWithoutContext(status.getUser().getName()) + "さんから、");
-        buffer.append(status.getText());
-      }
-
-      mTalker.talkAsync(UrlUtil.convURLEmpty(buffer).replaceAll("\n", "。"), mYukkuriVoice);
-
-      // 読み上げは、霊夢と魔理沙が交互に行なう
-      if (mYukkuriVoice == Talker.YukkuriVoice.REIMU) {
-        mYukkuriVoice = Talker.YukkuriVoice.MARISA;
-      } else {
-        mYukkuriVoice = Talker.YukkuriVoice.REIMU;
-      }
-
-    }
-
-    public void onDeletionNotice(StatusDeletionNotice sdn) {
-      System.err.println("onDeletionNotice.");
-    }
-
-    public void onTrackLimitationNotice(int i) {
-      System.err.println("onTrackLimitationNotice.(" + i + ")");
-    }
-
-    public void onScrubGeo(long lat, long lng) {
-      System.err.println("onScrubGeo.(" + lat + ", " + lng + ")");
-    }
-
-    public void onException(Exception excptn) {
-      System.err.println("onException.");
-    }
-
-    @Override
-    public void onStallWarning(StallWarning arg0) {}
-  }
-
-}
diff --git a/src/com/mizo0203/twitter/timeline/talker/UrlUtil.java b/src/com/mizo0203/twitter/timeline/talker/UrlUtil.java
deleted file mode 100644
index 264cd49..0000000
--- a/src/com/mizo0203/twitter/timeline/talker/UrlUtil.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.mizo0203.twitter.timeline.talker;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * http://chat-messenger.net/blog-entry-40.html
- */
-public class UrlUtil {
-  /** URLを抽出するための正規表現パターン */
-  private static final Pattern convURLLinkPtn = Pattern.compile(
-      "(http://|https://){1}[\\w\\.\\-/:\\#\\?\\=\\&\\;\\%\\~\\+]+", Pattern.CASE_INSENSITIVE);
-
-  /**
-   * 指定された文字列内のURLを、正規表現を使用し、 空文字列に変換する。
-   * 
-   * @param str 指定の文字列。
-   * @return リンクに変換された文字列。
-   */
-  public static String convURLEmpty(CharSequence str) {
-    Matcher matcher = convURLLinkPtn.matcher(str);
-    return matcher.replaceAll("");
-  }
-}
