You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by cm...@apache.org on 2013/05/05 05:40:06 UTC
svn commit: r1479234 [8/15] - in /lucene/dev/branches/lucene4956:
dev-tools/idea/.idea/ dev-tools/idea/lucene/analysis/arirang/
lucene/analysis/ lucene/analysis/arirang/ lucene/analysis/arirang/src/
lucene/analysis/arirang/src/java/ lucene/analysis/ari...
Added: lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/SyllableUtil.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/SyllableUtil.java?rev=1479234&view=auto
==============================================================================
--- lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/SyllableUtil.java (added)
+++ lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/SyllableUtil.java Sun May 5 03:39:51 2013
@@ -0,0 +1,136 @@
+package org.apache.lucene.analysis.kr.utils;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.lucene.analysis.kr.morph.MorphException;
+
+public class SyllableUtil {
+
+ public static int IDX_JOSA1 = 0; // ì¡°ì¬ì 첫ìì ë¡ ì¬ì©ëë ìì 48ê°
+ public static int IDX_JOSA2 = 1; // ì¡°ì¬ì ë ë²ì§¸ ì´ìì ìì ë¡ ì¬ì©ëë ìì 58ê°
+ public static int IDX_EOMI1 = 2; // ì´ë¯¸ì 첫ìì ë¡ ì¬ì©ëë ìì 72ê°
+ public static int IDX_EOMI2 = 3; // ì´ë¯¸ì ë ë²ì§¸ ì´ìì ìì ë¡ ì¬ì©ëë ìì 105ê°
+ public static int IDX_YONG1 = 4; // 1ìì ì©ì¸ì ì¬ì©ëë ìì 362ê°
+ public static int IDX_YONG2 = 5; // 2ìì ì©ì¸ì ë§ì§ë§ ìì ë¡ ì¬ì©ëë ìì 316ê°
+ public static int IDX_YONG3 = 6; // 3ìì ì´ì ì©ì¸ì ë§ì§ë§ ìì ë¡ ì¬ì©ëë ìì 195ê°
+ public static int IDX_CHEON1 = 7; // 1ìì ì²´ì¸ì ì¬ì©ëë ìì 680ê°
+ public static int IDX_CHEON2 = 8; // 2ìì ì²´ì¸ì ë§ì§ë§ ìì ë¡ ì¬ì©ëë ìì 916ê°
+ public static int IDX_CHEON3 = 9; // 3ìì ì²´ì¸ì ë§ì§ë§ ìì ë¡ ì¬ì©ëë ìì 800ê°
+ public static int IDX_CHEON4 = 10; // 4ìì ì²´ì¸ì ë§ì§ë§ ìì ë¡ ì¬ì©ëë ìì 610ê°
+ public static int IDX_CHEON5 = 11; // 5ìì ì´ì ì²´ì¸ì ë§ì§ë§ ìì ë¡ ì¬ì©ëë ìì 330ê°
+ public static int IDX_BUSA1 = 12; // 1ìì ë¶ì¬ì ë§ì§ë§ ìì ë¡ ì¬ì©ëë ìì 191ê°
+ public static int IDX_BUSA2 = 13; // 2ìì ë¶ì¬ì ë§ì§ë§ ìì ë¡ ì¬ì©ëë ìì 519ê°
+ public static int IDX_BUSA3 = 14; // 3ìì ë¶ì¬ì ë§ì§ë§ ìì ë¡ ì¬ì©ëë ìì 139ê°
+ public static int IDX_BUSA4 = 15; // 4ìì ë¶ì¬ì ë§ì§ë§ ìì ë¡ ì¬ì©ëë ìì 366ê°
+ public static int IDX_BUSA5 = 16; // 5ìì ë¶ì¬ì ë§ì§ë§ ìì ë¡ ì¬ì©ëë ìì 79ê°
+ public static int IDX_PRONOUN = 17; // ëëª
ì¬ì ë§ì§ë§ ìì ë¡ ì¬ì©ëë ìì 77ê°
+ public static int IDX_EXCLAM = 18; // ê´íì¬ì ê°íì¬ì ë§ì§ë§ ìì ë¡ ì¬ì©ëë ìì 241ê°
+
+ public static int IDX_YNPNA = 19; // (ì©ì¸+'-ã´')ì ìíì¬ ìì±ëë ìì 129ê°
+ public static int IDX_YNPLA = 20; // (ì©ì¸+'-ã¹')ì ìí´ ìì±ëë ìì 129ê°
+ public static int IDX_YNPMA = 21; // (ì©ì¸+'-ã
')ì ìí´ ìì±ëë ìì 129ê°
+ public static int IDX_YNPBA = 22; // (ì©ì¸+'-ã
')ì ìí´ ìì±ëë ìì 129ê°
+ public static int IDX_YNPAH = 23; // 모ìì¼ë¡ ëëë ìì 129ê°ì¤ 'ã
/ã
/ã
/ã
/ã
'ë¡ ëëë ê²ì´ ì ì´ë§ ì´ë¯¸ '-ì-'ê³¼ ê²°í©í ë ìì±ëë ìì
+ public static int IDX_YNPOU = 24; // 모ì 'ã
/ã
'ë¡ ëëë ìì ì´ 'ì/ì´'ë¡ ììëë ì´ë¯¸ë ì ì´ë§ ì´ë¯¸ '-ì-'ê³¼ ê²°í©í ë ìì±ëë ìì
+ public static int IDX_YNPEI = 25; // 모ì 'ã
£'ë¡ ëëë ì©ì¸ì´ 'ì/ì´'ë¡ ììëë ì´ë¯¸ë ì ì´ë§ ì´ë¯¸ '-ì-'ê³¼ ê²°í©í ë ìì±ëë ìì
+ public static int IDX_YNPOI = 26; // 모ì 'ã
'ë¡ ëëë ì©ì¸ì´ 'ì/ì´'ë¡ ììëë ì´ë¯¸ë ì ì´ë§ ì´ë¯¸ '-ì-'ê³¼ ê²°í©í ë ìì±ëë ìì
+ public static int IDX_YNPLN = 27; // ë°ì¹¨ 'ã¹'ë¡ ëëë ì©ì¸ì´ ì´ë¯¸ '-ã´'ê³¼ ê²°í©í ë ìì±ëë ìì
+ public static int IDX_IRRLO = 28; // 'ë¬' ë¶ê·ì¹(8ê°)ì ìíì¬ ìì±ëë ìì : ë¬, ë
+ public static int IDX_IRRPLE = 29; // '르' ë¶ê·ì¹(193ê°)ì ìíì¬ ìì±ëë ìì
+ public static int IDX_IRROO = 30; // 'ì°' ë¶ê·ì¹ì ìíì¬ ìì±ëë ìì : í¼, í
+ public static int IDX_IRROU = 31; // 'ì´' ë¶ê·ì¹ì ìíì¬ ìì±ëë ìì : í´, í
+ public static int IDX_IRRDA = 32; // 'ã·' ë¶ê·ì¹(37ê°)ì ìíì¬ ìì±ëë ìì
+ public static int IDX_IRRBA = 33; // 'ã
' ë¶ê·ì¹(446ê°)ì ìíì¬ ìì±ëë ìì
+ public static int IDX_IRRSA = 34; // 'ã
' ë¶ê·ì¹(39ê°)ì ìíì¬ ìì±ëë ìì
+ public static int IDX_IRRHA = 35; // 'ã
' ë¶ê·ì¹(96ê°)ì ìíì¬ ìì±ëë ìì
+ public static int IDX_PEND = 36; // ì ì´ë§ ì´ë¯¸ : ì ì
¨ ì ì ì ê²
+
+ public static int IDX_YNPEOMI = 37; // ì©ì¸ì´ ì´ë¯¸ì ê²°í©í ë ìì±ëë ìì ì ì 734ê°
+
+ /** ì©ì¸ì í층 ííë¡ë§ ì¬ì©ëë ìì */
+ public static int IDX_WDSURF = 38;
+
+ public static int IDX_EOGAN = 39; // ì´ë¯¸ ëë ì´ë¯¸ì ë³íì¼ë¡ ì¡´ì¬í ì ìë ì (ì¦ IDX_EOMI ì´ê±°ë IDX_YNPNA ì´íì 1ì´ ìë ìì )
+
+ private static List Syllables; // ìì í¹ì± ì ë³´
+
+ /**
+ * ì¸ë±ì¤ ê°ì í´ë¹íë ìì ì í¹ì±ì ë°ííë¤.
+ * ìì ëë ì«ìì¼ ê²½ì°ë 모ë í´ë¹ì´ ìëë¯ë¡ ê°ì¥ ë§ì§ë§ ê¸ìì¸ 'í£' ì ìì í¹ì±ì ë°ííë¤.
+ *
+ * @param idx 'ê°'(0xAC00)ì´ 0ë¶í° ì ëì½ëì ìí´ íê¸ìì ì ìì°¨ì ì¼ë¡ ëì´í ê°
+ * @return
+ * @throws Exception
+ */
+ public static char[] getFeature(int idx) throws MorphException {
+
+ if(Syllables==null) Syllables = getSyllableFeature();
+
+ if(idx<0||idx>=Syllables.size())
+ return (char[])Syllables.get(Syllables.size()-1);
+ else
+ return (char[])Syllables.get(idx);
+
+ }
+
+ /**
+ * ê° ìì ì í¹ì±ì ë°ííë¤.
+ * @param syl ìì íë
+ * @return
+ * @throws Exception
+ */
+ public static char[] getFeature(char syl) throws MorphException {
+
+ int idx = syl - 0xAC00;
+ return getFeature(idx);
+
+ }
+
+ /**
+ * ìì ì ë³´í¹ì±ì íì¼ìì ì½ëë¤.
+ *
+ * @return
+ * @throws Exception
+ */
+ private static List getSyllableFeature() throws MorphException {
+
+ try{
+ Syllables = new ArrayList<char[]>();
+
+ List<String> line = FileUtil.readLines(KoreanEnv.getInstance().getValue(KoreanEnv.FILE_SYLLABLE_FEATURE),"UTF-8");
+ for(int i=0;i<line.size();i++) {
+ if(i!=0)
+ Syllables.add(line.get(i).toCharArray());
+ }
+ }catch(IOException e) {
+ throw new MorphException(e.getMessage());
+ }
+
+ return Syllables;
+
+ }
+
+ public static boolean isAlpanumeric(char ch) {
+ return (ch>='0'&&ch<='z');
+ }
+}
Added: lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/Trie.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/Trie.java?rev=1479234&view=auto
==============================================================================
--- lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/Trie.java (added)
+++ lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/Trie.java Sun May 5 03:39:51 2013
@@ -0,0 +1,830 @@
+package org.apache.lucene.analysis.kr.utils;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.NoSuchElementException;
+
+/**
+ * An information reTRIEval tree, a.k.a., a prefix tree. A Trie is similar to a
+ * dictionary, except that keys must be strings. Furthermore, Trie provides an
+ * efficient means (getPrefixedBy()) to find all values given just a PREFIX of a
+ * key.
+ * <p>
+ *
+ * All retrieval operations run in O(nm) time, where n is the size of the
+ * key/prefix and m is the size of the alphabet. Some implementations may reduce
+ * this to O(n log m) or even O(n) time. Insertion operations are assumed to be
+ * infrequent and may be slower. The space required is roughly linear with
+ * respect to the sum of the sizes of all keys in the tree, though this may be
+ * reduced if many keys have common prefixes.
+ * <p>
+ *
+ * The Trie can be set to ignore case. Doing so is the same as making all keys
+ * and prefixes lower case. That means the original keys cannot be extracted
+ * from the Trie.
+ * <p>
+ *
+ * Restrictions (not necessarily limitations!)
+ * <ul>
+ * <li><b>This class is not synchronized.</b> Do that externally if you
+ * desire.
+ * <li>Keys and values may not be null.
+ * <li>The interface to this is not complete.
+ * </ul>
+ *
+ * See http://www.csse.monash.edu.au/~lloyd/tildeAlgDS/Tree/Trie.html for a
+ * discussion of Tries.
+ */
+public class Trie<S,V> {
+ /**
+ * Our representation consists of a tree of nodes whose edges are labelled
+ * by strings. The first characters of all labels of all edges of a node
+ * must be distinct. Typically the edges are sorted, but this is determined
+ * by TrieNode.
+ * <p>
+ *
+ * An abstract TrieNode is a mapping from String keys to values, { <K1, V1>,
+ * ..., <KN, VN> }, where all Ki and Kj are distinct for all i != j. For any
+ * node N, define KEY(N) to be the concatenation of all labels on the edges
+ * from the root to that node. Then the abstraction function is:
+ * <p>
+ *
+ * <blockquote> { <KEY(N), N.getValue() | N is a child of root and
+ * N.getValue() != null} </blockquote>
+ *
+ * An earlier version used character labels on edges. This made
+ * implementation simpler but used more memory because one node would be
+ * allocated to each character in long strings if that string had no common
+ * prefixes with other elements of the Trie.
+ * <p>
+ *
+ * <dl>
+ * <dt>INVARIANT:</td>
+ * <dd>For any node N, for any edges Ei and Ej from N,<br>
+ * i != j <==> Ei.getLabel().getCharAt(0) !=
+ * Ej.getLabel().getCharAt(0)</dd>
+ * <dd>Also, all invariants for TrieNode and TrieEdge must hold.</dd>
+ * </dl>
+ */
+ private TrieNode<V> root;
+
+ /**
+ * Indicates whever search keys are case-sensitive or not. If true, keys
+ * will be canonicalized to lowercase.
+ */
+ private boolean ignoreCase;
+
+ /**
+ * The constant EmptyIterator to return when nothing matches.
+ */
+ private final static Iterator EMPTY_ITERATOR = new EmptyIterator();
+
+ /**
+ * Constructs a new, empty tree.
+ */
+ public Trie(boolean ignoreCase) {
+ this.ignoreCase = ignoreCase;
+ clear();
+ }
+
+ /**
+ * Makes this empty.
+ *
+ * @modifies this
+ */
+ public void clear() {
+ this.root = new TrieNode<V>();
+ }
+
+ /**
+ * Returns the canonical version of the given string.
+ * <p>
+ *
+ * In the basic version, strings are added and searched without
+ * modification. So this simply returns its parameter s.
+ * <p>
+ *
+ * Other overrides may also perform a conversion to the NFC form
+ * (interoperable across platforms) or to the NFKC form after removal of
+ * accents and diacritics from the NFKD form (ideal for searches using
+ * strings in natural language).
+ * <p>
+ *
+ * Made public instead of protected, because the public Prefix operations
+ * below may need to use a coherent conversion of search prefixes.
+ */
+ public String canonicalCase(final String s) {
+ if (!ignoreCase)
+ return s;
+ return s.toUpperCase(Locale.US).toLowerCase(Locale.US);
+ }
+
+ /**
+ * Matches the pattern <tt>b</tt> against the text
+ * <tt>a[startOffset...stopOffset - 1]</tt>.
+ *
+ * @return the first <tt>j</tt> so that:<br>
+ * <tt>0 <= i < b.length()</tt> AND<br>
+ * <tt>a[startOffset + j] != b[j]</tt> [a and b differ]<br>
+ * OR <tt>stopOffset == startOffset + j</tt> [a is undefined];<br>
+ * Returns -1 if no such <tt>j</tt> exists, i.e., there is a
+ * match.<br>
+ * Examples:
+ * <ol>
+ * <li>a = "abcde", startOffset = 0, stopOffset = 5, b = "abc"<br>
+ * abcde ==> returns -1<br>
+ * abc
+ * <li>a = "abcde", startOffset = 1, stopOffset = 5, b = "bXd"<br>
+ * abcde ==> returns 1 bXd
+ * <li>a = "abcde", startOffset = 1, stopOffset = 3, b = "bcd"<br>
+ * abc ==> returns 2<br>
+ * bcd
+ * </ol>
+ *
+ * @requires 0 <= startOffset <= stopOffset <= a.length()
+ */
+ private final int match(String a, int startOffset, int stopOffset, String b) {
+ // j is an index into b
+ // i is a parallel index into a
+ int i = startOffset;
+ for (int j = 0; j < b.length(); j++) {
+ if (i >= stopOffset)
+ return j;
+ if (a.charAt(i) != b.charAt(j))
+ return j;
+ i++;
+ }
+ return -1;
+ }
+
+
+ /**
+ * Maps the given key (which may be empty) to the given value.
+ *
+ * @return the old value associated with key, or <tt>null</tt> if none
+ * @requires value != null
+ * @modifies this
+ */
+ public V add(String key, V value) {
+ // early conversion of key, for best performance
+ key = canonicalCase(key);
+ // Find the largest prefix of key, key[0..i - 1], already in this.
+ TrieNode<V> node = root;
+ int i = 0;
+ while (i < key.length()) {
+ // Find the edge whose label starts with key[i].
+ TrieEdge<V> edge = node.get(key.charAt(i));
+ if (edge == null) {
+ // 1) Additive insert.
+ TrieNode<V> newNode = new TrieNode<V>(value);
+ node.put(key.substring(i), newNode);
+ return null;
+ }
+ // Now check that rest of label matches
+ String label = edge.getLabel();
+ int j = match(key, i, key.length(), label);
+ if (j >= 0) {
+ // 2) Prefix overlaps perfectly with just part of edge label
+ // Do split insert as follows...
+ //
+ // node node ab = label
+ // ab | ==> a | a = label[0...j - 1] (inclusive)
+ // child intermediate b = label[j...] (inclusive)
+ // b / \ c c = key[i + j...] (inclusive)
+ // child newNode
+ //
+ // ...unless c = "", in which case you just do a "splice
+ // insert" by ommiting newNew and setting intermediate's value.
+ TrieNode<V> child = edge.getChild();
+ TrieNode<V> intermediate = new TrieNode<V>();
+ String a = label.substring(0, j);
+ // Assert.that(canonicalCase(a).equals(a), "Bad edge a");
+ String b = label.substring(j);
+ // Assert.that(canonicalCase(b).equals(b), "Bad edge a");
+ String c = key.substring(i + j);
+ if (c.length() > 0) {
+ // Split.
+ TrieNode<V> newNode = new TrieNode<V>(value);
+ node.remove(label.charAt(0));
+ node.put(a, intermediate);
+ intermediate.put(b, child);
+ intermediate.put(c, newNode);
+ } else {
+ // Splice.
+ node.remove(label.charAt(0));
+ node.put(a, intermediate);
+ intermediate.put(b, child);
+ intermediate.setValue(value);
+ }
+ return null;
+ }
+ // Prefix overlaps perfectly with all of edge label.
+ // Keep searching.
+ node = edge.getChild();
+ i += label.length();
+ }
+ // 3) Relabel insert. Prefix already in this, though not necessarily
+ // associated with a value.
+ V ret = node.getValue();
+ node.setValue(value);
+ return ret;
+ }
+
+ /**
+ * Returns the node associated with prefix, or null if none. (internal)
+ */
+ private TrieNode<V> fetch(String prefix) {
+ // This private method uses prefixes already in canonical form.
+ TrieNode<V> node = root;
+ for (int i = 0; i < prefix.length();) {
+ // Find the edge whose label starts with prefix[i].
+ TrieEdge<V> edge = node.get(prefix.charAt(i));
+ if (edge == null)
+ return null;
+ // Now check that rest of label matches.
+ String label = edge.getLabel();
+ int j = match(prefix, i, prefix.length(), label);
+ if (j != -1)
+ return null;
+ i += label.length();
+ node = edge.getChild();
+ }
+ return node;
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if none.
+ *
+ * @return the <tt>Object</tt> value or <tt>null</tt>
+ */
+ public Object get(String key) {
+ // early conversion of search key
+ key = canonicalCase(key);
+ // search the node associated with key, if it exists
+ TrieNode node = fetch(key);
+ if (node == null)
+ return null;
+ // key exists, return the value
+ return node.getValue();
+ }
+
+ /**
+ * Ensures no values are associated with the given key.
+ *
+ * @return <tt>true</tt> if any values were actually removed
+ * @modifies this
+ */
+ public boolean remove(String key) {
+ // early conversion of search key
+ key = canonicalCase(key);
+ // search the node associated with key, if it exists
+ TrieNode<V> node = fetch(key);
+ if (node == null)
+ return false;
+ // key exists and can be removed.
+ // TODO: prune unneeded nodes to save space
+ boolean ret = node.getValue() != null;
+ node.setValue(null);
+ return ret;
+ }
+
+ /**
+ * Returns an iterator (of Object) of the values mapped by keys in this that
+ * start with the given prefix, in any order. That is, the returned iterator
+ * contains exactly the values v for which there exists a key k so that
+ * k.startsWith(prefix) and get(k) == v. The remove() operation on the
+ * iterator is unimplemented.
+ *
+ * @requires this not modified while iterator in use
+ */
+ public Iterator getPrefixedBy(String prefix) {
+ // Early conversion of search key
+ prefix = canonicalCase(prefix);
+ // Note that canonicalization MAY have changed the prefix length!
+ return getPrefixedBy(prefix, 0, prefix.length());
+ }
+
+ /**
+ * Same as getPrefixedBy(prefix.substring(startOffset, stopOffset). This is
+ * useful as an optimization in certain applications to avoid allocations.
+ * <p>
+ *
+ * Important: canonicalization of prefix substring is NOT performed here!
+ * But it can be performed early on the whole buffer using the public method
+ * <tt>canonicalCase(String)</tt> of this.
+ *
+ * @requires 0 <= startOffset <= stopOffset <= prefix.length
+ * @see #canonicalCase(String)
+ */
+ public Iterator getPrefixedBy(String prefix, int startOffset, int stopOffset) {
+ // Find the first node for which "prefix" prefixes KEY(node). (See the
+ // implementation overview for a definition of KEY(node).) This code is
+ // similar to fetch(prefix), except that if prefix extends into the
+ // middle of an edge label, that edge's child is considered a match.
+ TrieNode node = root;
+ for (int i = startOffset; i < stopOffset;) {
+ // Find the edge whose label starts with prefix[i].
+ TrieEdge edge = node.get(prefix.charAt(i));
+ if (edge == null) {
+ return EMPTY_ITERATOR;
+ }
+ // Now check that rest of label matches
+ node = edge.getChild();
+ String label = edge.getLabel();
+ int j = match(prefix, i, stopOffset, label);
+ if (i + j == stopOffset) {
+ // a) prefix overlaps perfectly with just part of edge label
+ break;
+ } else if (j >= 0) {
+ // b) prefix and label differ at some point
+ node = null;
+ break;
+ } else {
+ // c) prefix overlaps perfectly with all of edge label.
+ }
+ i += label.length();
+ }
+ // Yield all children of node, including node itself.
+ if (node == null)
+ return EMPTY_ITERATOR;
+ else
+ return new ValueIterator(node);
+ }
+
+ /**
+ * Returns all the (non-null) values associated with a given node and its
+ * children. (internal)
+ */
+ private class ValueIterator extends NodeIterator {
+ ValueIterator(TrieNode start) {
+ super(start, false);
+ }
+
+ // inherits javadoc comment
+ public Object next() {
+ return ((TrieNode) super.next()).getValue();
+ }
+ }
+
+ /**
+ * Yields nothing. (internal)
+ */
+ private static class EmptyIterator implements Iterator {
+ // inherits javadoc comment
+ public boolean hasNext() {
+ return false;
+ }
+
+ // inherits javadoc comment
+ public Object next() {
+ throw new NoSuchElementException();
+ }
+
+ public void remove() {
+
+ }
+ }
+
+ public class NodeIterator extends UnmodifiableIterator {
+ /**
+ * Stack for DFS. Push and pop from back. The last element of stack is
+ * the next node who's value will be returned.
+ * <p>
+ *
+ * INVARIANT: Top of stack contains the next node with not null value to
+ * pop. All other elements in stack are iterators.
+ */
+ private ArrayList /* of Iterator of TrieNode */stack = new ArrayList();
+ private boolean withNulls;
+
+ /**
+ * Creates a new iterator that yields all the nodes of start and its
+ * children that have values (ignoring internal nodes).
+ */
+ public NodeIterator(TrieNode start, boolean withNulls) {
+ this.withNulls = withNulls;
+ if (withNulls || start.getValue() != null)
+ // node has a value, push it for next
+ stack.add(start);
+ else
+ // scan node children to find the next node
+ advance(start);
+ }
+
+ // inherits javadoc comment
+ public boolean hasNext() {
+ return !stack.isEmpty();
+ }
+
+ // inherits javadoc comment
+ public Object next() {
+ int size;
+ if ((size = stack.size()) == 0)
+ throw new NoSuchElementException();
+ TrieNode node = (TrieNode) stack.remove(size - 1);
+ advance(node);
+ return node;
+ }
+
+ /**
+ * Scan the tree (top-down) starting at the already visited node until
+ * finding an appropriate node with not null value for next(). Keep
+ * unvisited nodes in a stack of siblings iterators. Return either an
+ * empty stack, or a stack whose top will be the next node returned by
+ * next().
+ */
+ private void advance(TrieNode node) {
+ Iterator children = node.childrenForward();
+ while (true) { // scan siblings and their children
+ int size;
+ if (children.hasNext()) {
+ node = (TrieNode) children.next();
+ if (children.hasNext()) // save siblings
+ stack.add(children);
+ // check current node and scan its sibling if necessary
+ if (withNulls || node.getValue() == null)
+ children = node.childrenForward(); // loop from there
+ else { // node qualifies for next()
+ stack.add(node);
+ return; // next node exists
+ }
+ } else if ((size = stack.size()) == 0)
+ return; // no next node
+ else
+ // no more siblings, return to parent
+ children = (Iterator) stack.remove(size - 1);
+ }
+ }
+ }
+
+ /**
+ * Returns a string representation of the tree state of this, i.e., the
+ * concrete state. (The version of toString commented out below returns a
+ * representation of the abstract state of this.
+ */
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("<root>"); //$NON-NLS-1$
+ toStringHelper(root, buf, 1);
+ return buf.toString();
+ }
+
+ /**
+ * Prints a description of the substree starting with start to buf. The
+ * printing starts with the given indent level. (internal)
+ */
+ private void toStringHelper(TrieNode start, StringBuffer buf, int indent) {
+ // Print value of node.
+ if (start.getValue() != null) {
+ buf.append(" -> "); //$NON-NLS-1$
+ buf.append(start.getValue().toString());
+ }
+ buf.append("\n"); //$NON-NLS-1$
+ // For each child...
+ for (Iterator iter = start.labelsForward(); iter.hasNext();) {
+ // Indent child appropriately.
+ for (int i = 0; i < indent; i++)
+ buf.append(" "); //$NON-NLS-1$
+ // Print edge.
+ String label = (String) iter.next();
+ buf.append(label);
+ // Recurse to print value.
+ TrieNode child = start.get(label.charAt(0)).getChild();
+ toStringHelper(child, buf, indent + 1);
+ }
+ }
+}
+
+/**
+ * A node of the Trie. Each Trie has a list of children, labelled by strings.
+ * Each of these [String label, TrieNode child] pairs is considered an "edge".
+ * The first character of each label must be distinct. When managing children,
+ * different implementations may trade space for time. Each node also stores an
+ * arbitrary Object value.
+ * <p>
+ *
+ * Design note: this is a "dumb" class. It is <i>only</i> responsible for
+ * managing its value and its children. None of its operations are recursive;
+ * that is Trie's job. Nor does it deal with case.
+ */
+final class TrieNode<V> {
+ /**
+ * The value of this node.
+ */
+ private V value = null;
+
+ /**
+ * The list of children. Children are stored as a sorted Vector because it
+ * is a more compact than a tree or linked lists. Insertions and deletions
+ * are more expensive, but they are rare compared to searching.
+ * <p>
+ *
+ * INVARIANT: children are sorted by distinct first characters of edges,
+ * i.e., for all i < j,<br>
+ * children[i].edge.charAt(0) < children[j].edge.charAt(0)
+ */
+ private ArrayList<TrieEdge<V>> /* of TrieEdge */children = new ArrayList<TrieEdge<V>>(0);
+
+ /**
+ * Creates a trie with no children and no value.
+ */
+ public TrieNode() {
+ }
+
+ /**
+ * Creates a trie with no children and the given value.
+ */
+ public TrieNode(V value) {
+ this.value = value;
+ }
+
+ /**
+ * Gets the value associated with this node, or null if none.
+ */
+ public V getValue() {
+ return value;
+ }
+
+ /**
+ * Sets the value associated with this node.
+ */
+ public void setValue(V value) {
+ this.value = value;
+ }
+
+ /**
+ * Get the nth child edge of this node.
+ *
+ * @requires 0 <= i < children.size()
+ */
+ private final TrieEdge<V> get(int i) {
+ return children.get(i);
+ }
+
+ /**
+ * (internal) If exact, returns the unique i so that:
+ * children[i].getLabelStart() == c<br>
+ * If !exact, returns the largest i so that: children[i].getLabelStart()
+ * <= c<br>
+ * In either case, returns -1 if no such i exists.
+ * <p>
+ *
+ * This method uses binary search and runs in O(log N) time, where N =
+ * children.size().<br>
+ * The standard Java binary search methods could not be used because they
+ * only return exact matches. Also, they require allocating a dummy Trie.
+ *
+ * Example1: Search non exact c == '_' in {[0] => 'a...', [1] => 'c...'};
+ * start loop with low = 0, high = 1; middle = 0, cmiddle == 'a', c <
+ * cmiddle, high = 0 (low == 0); middle = 0, cmiddle == 'a', c < cmiddle,
+ * high = -1 (low == 0); end loop; return high == -1 (no match, insert at
+ * 0). Example2: Search non exact c == 'a' in {[0] => 'a', [1] => 'c'} start
+ * loop with low = 0, high = 1; middle = 0, cmiddle == 'a', c == cmiddle,
+ * abort loop by returning middle == 0 (exact match). Example3: Search non
+ * exact c == 'b' in {[0] => 'a...', [1] => 'c...'}; start loop with low =
+ * 0, high = 1; middle = 0, cmiddle == 'a', cmiddle < c, low = 1 (high ==
+ * 1); middle = 1, cmiddle == 'c', c < cmiddle, high = 0 (low == 1); end
+ * loop; return high == 0 (no match, insert at 1). Example4: Search non
+ * exact c == 'c' in {[0] => 'a...', [1] => 'c...'}; start loop with low =
+ * 0, high = 1; middle = 0, cmiddle == 'a', cmiddle < c, low = 1 (high ==
+ * 1); middle = 1, cmiddle == 'c', c == cmiddle, abort loop by returning
+ * middle == 1 (exact match). Example5: Search non exact c == 'd' in {[0] =>
+ * 'a...', [1] => 'c...'}; start loop with low = 0, high = 1; middle = 0,
+ * cmiddle == 'a', cmiddle < c, low = 1 (high == 1); middle = 1, cmiddle ==
+ * 'c', cmiddle < c, low = 2 (high == 1); end loop; return high == 1 (no
+ * match, insert at 2).
+ */
+ private final int search(char c, boolean exact) {
+ // This code is stolen from IntSet.search.
+ int low = 0;
+ int high = children.size() - 1;
+ while (low <= high) {
+ int middle = (low + high) / 2;
+ char cmiddle = get(middle).getLabelStart();
+ if (cmiddle < c)
+ low = middle + 1;
+ else if (c < cmiddle)
+ high = middle - 1;
+ else
+ // c == cmiddle
+ return middle; // Return exact match.
+ }
+ if (exact)
+ return -1; // Return no match.
+ return high; // Return closest *lower or equal* match. (This works!)
+ }
+
+ /**
+ * Returns the edge (at most one) whose label starts with the given
+ * character, or null if no such edge.
+ */
+ public TrieEdge<V> get(char labelStart) {
+ int i = search(labelStart, true);
+ if (i < 0)
+ return null;
+ TrieEdge<V> ret = get(i);
+ return ret;
+ }
+
+ /**
+ * Inserts an edge with the given label to the given child to this. Keeps
+ * all edges binary sorted by their label start.
+ *
+ * @requires label not empty.
+ * @requires for all edges E in this, label.getLabel[0] != E not already
+ * mapped to a node.
+ * @modifies this
+ */
+ public void put(String label, TrieNode<V> child) {
+ int i;
+ // If there's a match it is the closest lower or equal one, and
+ // precondition requires it to be lower, so we add the edge *after*
+ // it. If there's no match, there are two cases: the Trie is empty,
+ // or the closest match returned is the last edge in the list.
+ if ((i = search(label.charAt(0), // find closest match
+ false)) >= 0) {
+ }
+ children.add(i + 1, new TrieEdge<V>(label, child));
+ }
+
+ /**
+ * Removes the edge (at most one) whose label starts with the given
+ * character. Returns true if any edges where actually removed.
+ */
+ public boolean remove(char labelStart) {
+ int i;
+ if ((i = search(labelStart, true)) < 0)
+ return false;
+ children.remove(i);
+ return true;
+ }
+
+ /**
+ * Ensures that this's children take a minimal amount of storage. This
+ * should be called after numerous calls to add().
+ *
+ * @modifies this
+ */
+ public void trim() {
+ children.trimToSize();
+ }
+
+ /**
+ * Returns the children of this in forward order, as an iterator of
+ * TrieNode.
+ */
+ public Iterator childrenForward() {
+ return new ChildrenForwardIterator();
+ }
+
+ /**
+ * Maps (lambda(edge) edge.getChild) on children.iterator().
+ */
+ private class ChildrenForwardIterator extends UnmodifiableIterator {
+ int i = 0;
+
+ public boolean hasNext() {
+ return i < children.size();
+ }
+
+ public Object next() {
+ if (i < children.size())
+ return get(i++).getChild();
+ throw new NoSuchElementException();
+ }
+ }
+
+ /**
+ * Returns the children of this in forward order, as an iterator of
+ * TrieNode.
+ */
+ /*
+ * public Iterator childrenBackward() { return new
+ * ChildrenBackwardIterator(); }
+ */
+
+ /**
+ * Maps (lambda(edge) edge.getChild) on children.iteratorBackward().
+ */
+ /*
+ * private class ChildrenBackwardIterator extends UnmodifiableIterator { int
+ * i = children.size() - 1;
+ *
+ * public boolean hasNext() { return i >= 0; }
+ *
+ * public Object next() { if (i >= 0) return get(i--).getChild(); throw new
+ * NoSuchElementException(); } }
+ */
+
+ /**
+ * Returns the labels of the children of this in forward order, as an
+ * iterator of Strings.
+ */
+ public Iterator labelsForward() {
+ return new LabelForwardIterator();
+ }
+
+ /**
+ * Maps (lambda(edge) edge.getLabel) on children.iterator()
+ */
+ private class LabelForwardIterator extends UnmodifiableIterator {
+ int i = 0;
+
+ public boolean hasNext() {
+ return i < children.size();
+ }
+
+ public Object next() {
+ if (i < children.size())
+ return get(i++).getLabel();
+ throw new NoSuchElementException();
+ }
+ }
+
+ /**
+ * Returns the labels of the children of this in backward order, as an
+ * iterator of Strings.
+ */
+ /*
+ * public Iterator labelsBackward() { return new LabelBackwardIterator(); }
+ */
+
+ /**
+ * Maps (lambda(edge) edge.getLabel) on children.iteratorBackward()
+ */
+ /*
+ * private class LabelBackwardIterator extends UnmodifiableIterator { int i =
+ * children.size() - 1;
+ *
+ * public boolean hasNext() { return i >= 0; }
+ *
+ * public Object next() { if (i >= 0) return get(i--).getLabel(); throw new
+ * NoSuchElementException(); } }
+ */
+
+ // inherits javadoc comment.
+ public String toString() {
+ Object val = getValue();
+ if (val != null)
+ return val.toString();
+ return "NULL"; //$NON-NLS-1$
+ }
+
+ /**
+ * Unit test.
+ *
+ * @see TrieNodeTest
+ */
+}
+
+/**
+ * A labelled edge, i.e., a String label and a TrieNode endpoint.
+ */
+final class TrieEdge<V> {
+ private String label;
+ private TrieNode<V> child;
+
+ /**
+ * @requires label.size() > 0
+ * @requires child != null
+ */
+ TrieEdge(String label, TrieNode<V> child) {
+ this.label = label;
+ this.child = child;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * Returns the first character of the label, i.e., getLabel().charAt(0).
+ */
+ public char getLabelStart() {
+ // You could store this char as an optimization if needed.
+ return label.charAt(0);
+ }
+
+ public TrieNode<V> getChild() {
+ return child;
+ }
+
+}
\ No newline at end of file
Added: lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/UnhandledException.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/UnhandledException.java?rev=1479234&view=auto
==============================================================================
--- lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/UnhandledException.java (added)
+++ lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/UnhandledException.java Sun May 5 03:39:51 2013
@@ -0,0 +1,49 @@
+package org.apache.lucene.analysis.kr.utils;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class UnhandledException extends RuntimeException {
+
+ /**
+ * Required for serialization support.
+ *
+ * @see java.io.Serializable
+ */
+ private static final long serialVersionUID = 1832101364842773720L;
+
+ /**
+ * Constructs the exception using a cause.
+ *
+ * @param cause the underlying cause
+ */
+ public UnhandledException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Constructs the exception using a message and cause.
+ *
+ * @param message the message to use
+ * @param cause the underlying cause
+ */
+ public UnhandledException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+
+}
Added: lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/UnmodifiableIterator.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/UnmodifiableIterator.java?rev=1479234&view=auto
==============================================================================
--- lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/UnmodifiableIterator.java (added)
+++ lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/UnmodifiableIterator.java Sun May 5 03:39:51 2013
@@ -0,0 +1,28 @@
+package org.apache.lucene.analysis.kr.utils;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.Iterator;
+
+public abstract class UnmodifiableIterator implements Iterator {
+
+ public void remove() {
+ throw new UnsupportedOperationException("Cannot remove from this iterator");
+ }
+
+}
\ No newline at end of file
Added: lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/Utilities.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/Utilities.java?rev=1479234&view=auto
==============================================================================
--- lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/Utilities.java (added)
+++ lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/Utilities.java Sun May 5 03:39:51 2013
@@ -0,0 +1,140 @@
+package org.apache.lucene.analysis.kr.utils;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.lucene.analysis.kr.morph.AnalysisOutput;
+import org.apache.lucene.analysis.kr.morph.MorphException;
+import org.apache.lucene.analysis.kr.morph.PatternConstants;
+
+public class Utilities {
+
+ public static String arrayToString(String[] strs) {
+ StringBuffer sb = new StringBuffer();
+ for(String str:strs) {
+ sb.append(str);
+ }
+ return sb.toString();
+ }
+
+ public static AnalysisOutput cloneOutput(AnalysisOutput o) throws MorphException {
+ try {
+ return o.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new MorphException(e.getMessage(),e);
+ }
+ }
+
+ public static String buildOutputString(AnalysisOutput o) {
+
+
+ StringBuffer buff = new StringBuffer();
+
+ buff.append(MorphUtil.buildTypeString(o.getStem(),o.getPos()));
+ if(o.getNsfx()!=null)
+ buff.append(",").append(MorphUtil.buildTypeString(o.getNsfx(),PatternConstants.POS_SFX_N));
+
+ if(o.getPatn()==PatternConstants.PTN_NJ || o.getPatn()==PatternConstants.PTN_ADVJ) {
+ buff.append(",").append(MorphUtil.buildTypeString(o.getJosa(),PatternConstants.POS_JOSA));
+ }else if(o.getPatn()==PatternConstants.PTN_NSM) {
+ buff.append(",").append(MorphUtil.buildTypeString(o.getVsfx(),PatternConstants.POS_SFX_V));
+ if(o.getPomi()!=null)
+ buff.append(",").append(MorphUtil.buildTypeString(o.getPomi(),PatternConstants.POS_PEOMI));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getEomi(),PatternConstants.POS_EOMI));
+ }else if(o.getPatn()==PatternConstants.PTN_NSMJ) {
+ buff.append(",").append(MorphUtil.buildTypeString(o.getVsfx(),PatternConstants.POS_SFX_V));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getElist().get(0),PatternConstants.POS_NEOMI));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getJosa(),PatternConstants.POS_JOSA));
+ }else if(o.getPatn()==PatternConstants.PTN_NSMXM) {
+ buff.append(",").append(MorphUtil.buildTypeString(o.getVsfx(),PatternConstants.POS_SFX_V));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getElist().get(0),PatternConstants.POS_COPULA));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getXverb(),PatternConstants.POS_XVERB));
+ if(o.getPomi()!=null)
+ buff.append(",").append(MorphUtil.buildTypeString(o.getPomi(),PatternConstants.POS_PEOMI));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getEomi(),PatternConstants.POS_EOMI));
+ }else if(o.getPatn()==PatternConstants.PTN_NJCM) {
+ buff.append(",").append(MorphUtil.buildTypeString(o.getJosa(),PatternConstants.POS_JOSA));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getElist().get(0),PatternConstants.POS_SFX_V));
+ if(o.getPomi()!=null)
+ buff.append(",").append(MorphUtil.buildTypeString(o.getPomi(),PatternConstants.POS_PEOMI));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getEomi(),PatternConstants.POS_EOMI));
+ }else if(o.getPatn()==PatternConstants.PTN_NSMXMJ) {
+ buff.append(",").append(MorphUtil.buildTypeString(o.getVsfx(),PatternConstants.POS_SFX_V));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getElist().get(1),PatternConstants.POS_COPULA));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getXverb(),PatternConstants.POS_XVERB));
+ if(o.getPomi()!=null)
+ buff.append(",").append(MorphUtil.buildTypeString(o.getPomi(),PatternConstants.POS_PEOMI));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getElist().get(0),PatternConstants.POS_NEOMI));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getJosa(),PatternConstants.POS_JOSA));
+ }else if(o.getPatn()==PatternConstants.PTN_VM) {
+ if(o.getPomi()!=null)
+ buff.append(",").append(MorphUtil.buildTypeString(o.getPomi(),PatternConstants.POS_PEOMI));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getEomi(),PatternConstants.POS_EOMI));
+ }else if(o.getPatn()==PatternConstants.PTN_VMJ) {
+ buff.append(",").append(MorphUtil.buildTypeString(o.getElist().get(0),PatternConstants.POS_NEOMI));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getJosa(),PatternConstants.POS_JOSA));
+ }else if(o.getPatn()==PatternConstants.PTN_VMCM) {
+ buff.append(",").append(MorphUtil.buildTypeString(o.getElist().get(0),PatternConstants.POS_NEOMI));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getElist().get(1),PatternConstants.POS_SFX_N));
+ if(o.getPomi()!=null)
+ buff.append(",").append(MorphUtil.buildTypeString(o.getPomi(),PatternConstants.POS_PEOMI));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getEomi(),PatternConstants.POS_EOMI));
+ }else if(o.getPatn()==PatternConstants.PTN_VMXM) {
+ buff.append(",").append(MorphUtil.buildTypeString(o.getElist().get(0),PatternConstants.POS_COPULA));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getXverb(),PatternConstants.POS_XVERB));
+ if(o.getPomi()!=null)
+ buff.append(",").append(MorphUtil.buildTypeString(o.getPomi(),PatternConstants.POS_PEOMI));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getEomi(),PatternConstants.POS_EOMI));
+ }else if(o.getPatn()==PatternConstants.PTN_VMXMJ) {
+ buff.append(",").append(MorphUtil.buildTypeString(o.getElist().get(1),PatternConstants.POS_COPULA));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getXverb(),PatternConstants.POS_XVERB));
+ if(o.getPomi()!=null)
+ buff.append(",").append(MorphUtil.buildTypeString(o.getPomi(),PatternConstants.POS_PEOMI));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getElist().get(0),PatternConstants.POS_NEOMI));
+ buff.append(",").append(MorphUtil.buildTypeString(o.getJosa(),PatternConstants.POS_JOSA));
+ }
+ return buff.toString();
+
+ }
+
+ // -----------------------------------------------------------------------
+ /**
+ * <p>
+ * Gets a System property, defaulting to <code>null</code> if the property cannot be read.
+ * </p>
+ *
+ * <p>
+ * If a <code>SecurityException</code> is caught, the return value is <code>null</code> and a message is written to
+ * <code>System.err</code>.
+ * </p>
+ *
+ * @param property
+ * the system property name
+ * @return the system property value or <code>null</code> if a security problem occurs
+ */
+ public static String getSystemProperty(String property) {
+ try {
+ return System.getProperty(property);
+ } catch (SecurityException ex) {
+ // we are not allowed to look at this property
+ System.err.println("Caught a SecurityException reading the system property '" + property
+ + "'; the SystemUtils property value will default to null.");
+ return null;
+ }
+ }
+
+}
Added: lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/VerbUtil.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/VerbUtil.java?rev=1479234&view=auto
==============================================================================
--- lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/VerbUtil.java (added)
+++ lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/java/org/apache/lucene/analysis/kr/utils/VerbUtil.java Sun May 5 03:39:51 2013
@@ -0,0 +1,305 @@
+package org.apache.lucene.analysis.kr.utils;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.lucene.analysis.kr.morph.AnalysisOutput;
+import org.apache.lucene.analysis.kr.morph.MorphException;
+import org.apache.lucene.analysis.kr.morph.PatternConstants;
+import org.apache.lucene.analysis.kr.morph.WordEntry;
+
+public class VerbUtil {
+
+ public static final Map verbSuffix = new HashMap();
+
+ public static final Map XVerb = new HashMap();
+
+ static {
+ String[] suffixs = {
+ "ì´","í","ë","ë´", "ë", "ì¤ë½","ìí¤","ì","ì","ê°","ë¹í","ë§í","ë리","ë°","ì§"};
+ for(int i=0;i<suffixs.length;i++) verbSuffix.put(suffixs[i], suffixs[i]);
+
+ String[] xverbs = {"ì¤","ë´","주","ë³´","ì§","ì¤ë¥´","ì¬ë¦¬"};
+ for(int i=0;i<xverbs.length;i++) XVerb.put(xverbs[i], xverbs[i]);
+ }
+
+ /**
+ * ì´ê°ì´ ì©ì¸íì 미ì¬ë¡ ëëë©´ index 를 ë°ííë¤. ìëë©´ -1ì ë°ííë¤.
+ * @param result
+ * @return
+ */
+ public static int endsWithVerbSuffix(String stem) {
+ int len = stem.length();
+ if(len<2) return -1;
+ int start = 2;
+ if(len==2) start = 1;
+ for(int i=start;i>0;i--) { // suffix ì ê°ì¥ 긴 ê¸ììê° 2ì´ë¤.
+ if(verbSuffix.get(stem.substring(len-i))!=null) return (len-i);
+ }
+ return -1;
+ }
+
+ /**
+ * ì´ê°ë¶ì ë³´ì¡°ì©ì¸ [í,ë,ì¤,ë´,주,ì§]ê° ìëì§ ì¡°ì¬íë¤.
+ * @param stem
+ * @return
+ */
+ public static int endsWithXVerb(String stem) {
+ int len = stem.length();
+ if(len<2) return -1;
+ int start = 2;
+ if(len==2) start = 1;
+ for(int i=start;i>0;i--) { //xverbs ì ê°ì¥ 긴 ê¸ììë 2ì´ë¤.
+ if(XVerb.get(stem.substring(len-i))!=null) return (len-i);
+ }
+ return -1;
+ }
+
+ public static boolean verbSuffix(String stem) {
+
+ return verbSuffix.get(stem)!=null;
+
+ }
+
+ public static boolean constraintVerb(String start, String end) {
+
+ char[] schs = MorphUtil.decompose(start.charAt(start.length()-1));
+ char[] echs = MorphUtil.decompose(end.charAt(0));
+
+ if(schs.length==3&&schs[2]=='ã¹'&&echs[0]=='ã¹') return false;
+
+ return true;
+ }
+
+ /**
+ * 3. íêµììì´ë¤ : ì²´ì¸ + 'ìì/ë¶í°/ììë¶í°' + 'ì´' + ì´ë¯¸ (PTN_NJCM) <br>
+ */
+ public static boolean ananlysisNJCM(AnalysisOutput o, List candidates) throws MorphException {
+
+ int strlen = o.getStem().length();
+ boolean success = false;
+
+ if(strlen>3&&(o.getStem().endsWith("ììì´")||o.getStem().endsWith("ë¶í°ì´"))) {
+ o.addElist(o.getStem().substring(strlen-1));
+ o.setJosa(o.getStem().substring(strlen-3,strlen-1));
+ o.setStem(o.getStem().substring(0,strlen-3));
+ success = true;
+ }else if(strlen>5&&(o.getStem().endsWith("ììë¶í°ì´"))) {
+ o.addElist(o.getStem().substring(strlen-1));
+ o.setJosa(o.getStem().substring(strlen-5,strlen-1));
+ o.setStem(o.getStem().substring(0,strlen-5));
+ success = true;
+ }
+ if(!success) return false;
+
+ if(success&&DictionaryUtil.getNoun(o.getStem())!=null) {
+ o.setScore(AnalysisOutput.SCORE_CORRECT);
+// }else {
+// NounUtil.confirmCNoun(o);
+ }
+
+ o.setPatn(PatternConstants.PTN_NJCM);
+ o.setPos(PatternConstants.POS_NOUN);
+ candidates.add(o);
+
+ return true;
+ }
+
+ /**
+ * ì´ë¯¸ë¶ì ì´ê°ë¶ê° ë¶ë¦¬ë ìíìì ì©ì¸íì 미ì¬ê° ê²°í©ë ì ìëì§ ì¡°ì¬íë¤.
+ * @param o ì´ë¯¸ë¶ì ì´ê°ë¶ê° ë¶ë¦¬ë ê²°ê³¼
+ * @param candidates
+ * @return
+ * @throws MorphException
+ */
+ public static boolean ananlysisNSM(AnalysisOutput o, List candidates) throws MorphException {
+
+ if(o.getStem().endsWith("ì¤ë¬ì°")) o.setStem(o.getStem().substring(0,o.getStem().length()-3)+"ì¤ë½");
+ int idxVbSfix = VerbUtil.endsWithVerbSuffix(o.getStem());
+ if(idxVbSfix<1) return false;
+
+ o.setVsfx(o.getStem().substring(idxVbSfix));
+ o.setStem(o.getStem().substring(0,idxVbSfix));
+ o.setPatn(PatternConstants.PTN_NSM);
+ o.setPos(PatternConstants.POS_NOUN);
+
+ WordEntry entry = DictionaryUtil.getWordExceptVerb(o.getStem());
+
+// if(entry==null&&NounUtil.confirmCNoun(o)&&o.getCNounList().size()>0) {
+// entry = DictionaryUtil.getNoun(o.getCNounList().get(o.getCNounList().size()-1).getWord());
+// }
+
+// if(entry==null) return false;
+// if(entry==null) {
+// NounUtil.confirmDNoun(o);
+// if(o.getScore()!=AnalysisOutput.SCORE_CORRECT) return false;
+// }
+
+ if(entry!=null) {
+ if(entry.getFeature(WordEntry.IDX_NOUN)=='0') return false;
+ else if(o.getVsfx().equals("í")&&entry.getFeature(WordEntry.IDX_DOV)!='1') return false;
+ else if(o.getVsfx().equals("ë")&&entry.getFeature(WordEntry.IDX_BEV)!='1') return false;
+ else if(o.getVsfx().equals("ë´")&&entry.getFeature(WordEntry.IDX_NE)!='1') return false;
+ o.setScore(AnalysisOutput.SCORE_CORRECT); // 'ì
ëë¤'ì¸ ê²½ì° ì¸ëª
ë± ë¯¸ë±ë¡ì´ê° ë§ì´ ë°ìëë¯ë¡ ë¶ìì±ê³µì¼ë¡ ê°ì íë¤.
+ }else {
+ o.setScore(AnalysisOutput.SCORE_ANALYSIS); // 'ì
ëë¤'ì¸ ê²½ì° ì¸ëª
ë± ë¯¸ë±ë¡ì´ê° ë§ì´ ë°ìëë¯ë¡ ë¶ìì±ê³µì¼ë¡ ê°ì íë¤.
+ }
+
+ candidates.add(o);
+
+ return true;
+
+ }
+
+ public static boolean ananlysisNSMXM(AnalysisOutput o, List candidates) throws MorphException {
+
+ int idxXVerb = VerbUtil.endsWithXVerb(o.getStem());
+ if(idxXVerb==-1) return false;
+
+ String eogan = o.getStem().substring(0,idxXVerb);
+ String[] stomis = null;
+
+ if((eogan.endsWith("ì")||eogan.endsWith("ì´"))&&eogan.length()>1)
+ stomis = EomiUtil.splitEomi(eogan.substring(0,eogan.length()-1),eogan.substring(eogan.length()-1));
+ else
+ stomis = EomiUtil.splitEomi(eogan,"");
+
+ if(stomis[0]==null) return false;
+
+ o.addElist(stomis[1]);
+ int idxVbSfix = VerbUtil.endsWithVerbSuffix(stomis[0]);
+ if(idxVbSfix==-1) return false;
+
+ o.setXverb(o.getStem().substring(idxXVerb));
+ o.setVsfx(stomis[0].substring(idxVbSfix));
+ o.setStem(stomis[0].substring(0,idxVbSfix));
+ o.setPatn(PatternConstants.PTN_NSMXM);
+ o.setPos(PatternConstants.POS_NOUN);
+ WordEntry entry = DictionaryUtil.getNoun(o.getStem());
+// if(entry==null&&NounUtil.confirmCNoun(o)&&o.getCNounList().size()>0) {
+// entry = DictionaryUtil.getNoun(o.getCNounList().get(o.getCNounList().size()-1));
+// }
+ if(entry==null) return false;
+
+ if(o.getVsfx().equals("í")&&entry.getFeature(WordEntry.IDX_DOV)!='1') return false;
+ if(o.getVsfx().equals("ë")&&entry.getFeature(WordEntry.IDX_BEV)!='1') return false;
+ o.setScore(AnalysisOutput.SCORE_CORRECT);
+
+ candidates.add(o);
+
+
+ return true;
+ }
+
+ public static boolean analysisVMCM(AnalysisOutput o, List candidates) throws MorphException {
+
+ int strlen = o.getStem().length();
+
+ if(strlen<2) return false;
+
+ if(!o.getStem().endsWith("ì´")) return false;
+
+ char[] chrs = MorphUtil.decompose(o.getStem().charAt(strlen-2));
+ boolean success = false;
+
+ if(strlen>2&&o.getStem().endsWith("기ì´")) {
+ o.setStem(o.getStem().substring(0,strlen-2));
+ o.addElist("기");
+ success = true;
+ } else if(chrs.length>2&&chrs[2]=='ã
'){
+ String[] eres = EomiUtil.splitEomi(o.getStem().substring(0,strlen-1), "");
+ if(eres[0]==null) return false;
+
+ o.addElist(eres[1]);
+ String[] irrs = IrregularUtil.restoreIrregularVerb(eres[0], eres[1]);
+
+ if(irrs!=null) o.setStem(irrs[0]);
+ else o.setStem(eres[0]);
+
+ success = true;
+ }
+
+ if(success) {
+
+ o.addElist("ì´");
+ if(DictionaryUtil.getVerb(o.getStem())!=null) {
+ o.setPos(PatternConstants.POS_VERB);
+ o.setPatn(PatternConstants.PTN_VMCM);
+ o.setScore(AnalysisOutput.SCORE_CORRECT);
+ candidates.add(o);
+ return true;
+ }
+ }
+
+ return false;
+
+ }
+
+ /**
+ *
+ * 6. ëìì£¼ë¤ : ì©ì¸ + 'ì/ì´' + ë³´ì¡°ì©ì¸ + ì´ë¯¸ (PTN_VMXM)
+ *
+ * @param o
+ * @param candidates
+ * @return
+ * @throws MorphException
+ */
+ public static boolean analysisVMXM(AnalysisOutput o, List candidates) throws MorphException {
+
+ int idxXVerb = VerbUtil.endsWithXVerb(o.getStem());
+
+ if(idxXVerb==-1) return false;
+
+ o.setXverb(o.getStem().substring(idxXVerb));
+
+ String eogan = o.getStem().substring(0,idxXVerb);
+
+ String[] stomis = null;
+ if(eogan.endsWith("ì")||eogan.endsWith("ì´")) {
+ stomis = EomiUtil.splitEomi(eogan.substring(0,eogan.length()-1),eogan.substring(eogan.length()-1));
+ if(stomis[0]==null) return false;
+ }else {
+ stomis = EomiUtil.splitEomi(eogan, "");
+ if(stomis[0]==null||!(stomis[1].startsWith("ì")||stomis[1].startsWith("ì´"))) return false;
+ }
+
+ String[] irrs = IrregularUtil.restoreIrregularVerb(stomis[0], stomis[1]);
+ if(irrs!=null) {
+ o.setStem(irrs[0]);
+ o.addElist(irrs[1]);
+ } else {
+ o.setStem(stomis[0]);
+ o.addElist(stomis[1]);
+ }
+
+ if(DictionaryUtil.getVerb(o.getStem())!=null) {
+ o.setPos(PatternConstants.POS_VERB);
+ o.setPatn(PatternConstants.PTN_VMXM);
+ o.setScore(AnalysisOutput.SCORE_CORRECT);
+ candidates.add(o);
+ return true;
+ }
+
+ return false;
+ }
+
+}
Added: lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/resources/org/apache/lucene/analysis/kr/dic/cj.dic
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/resources/org/apache/lucene/analysis/kr/dic/cj.dic?rev=1479234&view=auto
==============================================================================
--- lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/resources/org/apache/lucene/analysis/kr/dic/cj.dic (added)
+++ lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/resources/org/apache/lucene/analysis/kr/dic/cj.dic Sun May 5 03:39:51 2013
@@ -0,0 +1,2 @@
+###################
+ï¤è:ê¸ìµ
\ No newline at end of file
Added: lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/resources/org/apache/lucene/analysis/kr/dic/compounds.dic
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/resources/org/apache/lucene/analysis/kr/dic/compounds.dic?rev=1479234&view=auto
==============================================================================
--- lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/resources/org/apache/lucene/analysis/kr/dic/compounds.dic (added)
+++ lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/resources/org/apache/lucene/analysis/kr/dic/compounds.dic Sun May 5 03:39:51 2013
@@ -0,0 +1,8 @@
+###################
+ë°¤íë:ë°¤,íë
+ê²½ì ì² :ê²½,ì ì²
+ê°ìëª
:ê°,ìëª
+ê°ì
êµ:ê°,ì
êµ
+ê°ê¹ì¹:ê°,ê¹ì¹
+ê³¼ìë¹:ê³¼,ìë¹
+ê³ í¬ìì¨:ê³ í¬ì,í¬ì,í¬ìì¨
\ No newline at end of file
Added: lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/resources/org/apache/lucene/analysis/kr/dic/eomi.dic
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/resources/org/apache/lucene/analysis/kr/dic/eomi.dic?rev=1479234&view=auto
==============================================================================
--- lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/resources/org/apache/lucene/analysis/kr/dic/eomi.dic (added)
+++ lucene/dev/branches/lucene4956/lucene/analysis/arirang/src/resources/org/apache/lucene/analysis/kr/dic/eomi.dic Sun May 5 03:39:51 2013
@@ -0,0 +1,748 @@
+//#######
+ê±°ë
+ê±°ë
+ê±°ë
+ê±°ëì
+ê±°ëë©´
+ê±°ëë©´ì
+ê±°ë
+ê±°ë¤ë
+ê±°ë¤ëì
+ê±´
+ê±´ë
+ê±´ë
+ê±´ë§ë
+ê±´ë§
+ê²ë¤
+ê²
+ê²ë
+ê²ë
+ê²ëë§
+ê²ë
+ê²ë
+ê²ë¼ë
+ê²ë§
+ê²ë§ì
+ê²ì리
+ê²ì
+ê³
+ê³ ë
+ê³ ë
+ê³ ë§
+ê³ ë§ê³
+ê³ ì
+ê³ ìë
+ê³ ìë
+ê³ ì
+ê³ ì¼
+ê³ ì
+ê³ ì
+곤
+ê´ë°
+구ë
+êµ¬ë ¤
+구ë£
+구먼
+êµ°
+êµ°ì
+기
+기ê¹ì§
+기ê¹ì§ë
+기ê¹ì§ë
+기ê¹ì§ë§
+기ê¹ì§ë§ì
+기ë¡
+기ë¡ì
+기ë¡ìë
+기ë¡ì ë¤
+기ì
+긴
+길
+ë
+ëë
+ëë§
+ëì
+ëì´ê¹
+ëì´ë¤
+ë
+ëê³
+ëë
+ëë¼ê³
+ëë¼ê³ ë
+ëë¼ê³ ë§
+ëì
+ë¤
+ë¤ë§
+ë¤ì
+ë
¸
+ë
¸ë¼
+ë
¸ë¼ê³
+ë
¸ë¼ë
+ë
¸ë¼ë©´
+ëë
+ëëê³
+ëëë
+ëëë¼ê³
+ëëë¼ê³ ë
+ëëë¼ê³ ë
+ëëë¼ê³ ë§
+ëëë¼ê³ ë§ì
+ëëì
+ëë¨
+ëë
+ëëë¼
+ëëë§
+ëë¼
+ëë¼ê³
+ë
+ëê°
+ëê°ë¼ê³
+ëê°ë¼ë
+ëê°ë¥¼
+ëê°ì
+ë걸
+ëê³
+ë구ë
+ëêµ¬ë ¤
+ë구ë£
+ë구먼
+ëêµ°
+ëë¤
+ëë¤ê±°ë
+ëë¤ê³
+ëë¤ê³ ë
+ëë¤ë
+ëë¤ëë°
+ëë¤ë
+ëë¤ëê¹
+ëë¤ë ì§
+ëë¤ë§ë
+ëë¤ë§
+ëë¤ë§ì
+ëë¤ë©°
+ëë¤ë©°ë
+ëë¤ë©´
+ëë¤ë©´ì
+ëë¤ë©´ì
+ëë¨ë¤
+ëë´
+ëëµëê¹
+ëëµëë¤
+ëëµëê¹
+ëëµëë¤
+ëëµìê³
+ëë
+ëëë¡
+ëëì
+ëëìì¼
+ëëì¼
+ëëì
+ëë°
+ëë°ë
+ëë°ë¤
+ëë°ë
+ëë°ì
+ëë§í¼
+ëë§í¼ë§
+ëë°
+ëì§
+ëì§ê°
+ëì§ê³
+ëì§ë
+ëì§ë
+ëì§ë¼
+ëì§ë¥¼
+ëì§ë§
+ëì§ì
+ëì§ì
+ëì§ì
+ë
+ëê¹
+ëê¹ë
+ëê¹
+ëë¼
+ëë§ì¹
+ëë§í¼
+ë¤
+ë¤ê°
+ë¤ê°ë
+ë¤ê°ë
+ë¤ê°
+ë¤ê±°ë
+ë¤ê³
+ë¤ê³ ê¹ì§
+ë¤ê³ ê¹ì§ë
+ë¤ê³ ê¹ì§ë
+ë¤ê³ ê¹ì§ë¼ë
+ë¤ê³ ê¹ì§ë§
+ë¤ê³ ê¹ì§ë§ì
+ë¤ê³ ë
+ë¤ê³ ë
+ë¤ê³ ë§
+ë¤ê³ ë§ì
+ë¤ê³ ì
+ë¤ê³¤
+ë¤ëë
+ë¤ëë
+ë¤ë
+ë¤ëë°
+ë¤ë
+ë¤ë§ë
+ë¤ë§ë¤
+ë¤ë§
+ë¤ë§ì
+ë¤ë©°
+ë¤ë©°ë
+ë¤ë©´
+ë¤ë©´ì
+ë¤ë©´ìë
+ë¤ë©´ì¼
+ë¤ë©´ì
+ë¤ìí¼
+ë¤ì¤
+ë¨
+ë¨ë¤
+ë´
+ëµìê³
+ë구ë
+ëêµ¬ë ¤
+ë구먼
+ëêµ°
+ëêµ°ì
+ëë
+ëë
+ëëë¼
+ëëë§ë
+ëëë§
+ëë¼
+ëë¼ë
+ëë¼ë©°ë
+ëë¼ë©´
+ëë
+ëë©´
+ë
+ëê°
+ëê°ì
+ë걸
+ë걸ì
+ëê³
+ëë°
+ëë°ë¤
+ëë°ì
+ëë¤
+ëì§
+ë°
+ë°ë
+ë°ì
+ëë¡
+ëë¡ê¹ì§
+ëë¡ê¹ì§ë
+ëë¡ê¹ì§ë§
+ëë¡ê¹ì§ë§ì
+ëë¡ê¹ì§ë§ì
+ë
+ë
+ë ì§
+ë¯
+ë¯ì´
+ë
+ë¼
+ë¼ê³
+ë¼ê³ ê¹ì§
+ë¼ê³ ê¹ì§ë
+ë¼ê³ ê¹ì§ë
+ë¼ê³ ê¹ì§ë§
+ë¼ê³ ê¹ì§ë§ì
+ë¼ê³ ë
+ë¼ê³ ë
+ë¼ê³ ë§
+ë¼ê³ ë§ì
+ë¼ê³¤
+ë¼ëë
+ë¼ë
+ë¼ëë°
+ë¼ëë°ë
+ë¼ëë°ì
+ë¼ë
+ë¼ëê¹
+ë¼ëê¹ì
+ë¼ë
+ë¼ë ì§
+ë¼ë©°
+ë¼ë©´
+ë¼ë©´ì
+ë¼ë©´ìê¹ì§
+ë¼ë©´ìê¹ì§ë
+ë¼ë©´ìë
+ë¼ë©´ìì
+ë
+ëë¤
+ëë¤ê³
+ë
+ëëê¹
+ëëë¤
+ëëê¹
+ëëë¤
+ëìê³
+ë
+ëë
+ë´
+ë´ë§ë
+ë¬
+ë¬ë
+ë¬ëë¼
+ë¬ëì´ê¹
+ë¬ëì´ë¤
+ë¬ë§
+ë¬ë§ì
+ë¬ì´ê¹
+ë¬ì´ë¤
+ë°ê°
+ë°ë¤
+ë ¤
+ë ¤ê±°ë
+ë ¤ê³
+ë ¤ê³ ê¹ì§
+ë ¤ê³ ê¹ì§ë
+ë ¤ê³ ê¹ì§ë§
+ë ¤ê³ ê¹ì§ë§ì
+ë ¤ê³ ë
+ë ¤ê³ ë
+ë ¤ê³ ë§
+ë ¤ê³ ë§ì
+ë ¤ê³ ì
+ë ¤ê¸°ì
+ë ¤ë
+ë ¤ë¤
+ë ¤ëë
+ë ¤ë
+ë ¤ëê°
+ë ¤ëë°
+ë ¤ëë°ì
+ë ¤ëì§
+ë ¤ë
+ë ¤ëê¹
+ë ¤ëì
+ë ¤ë¤
+ë ¤ë¤ê°
+ë ¤ë¤ê°ë
+ë ¤ë¤ê°ë
+ë ¤ë¤ê°ì
+ë ¤ëë
+ë ¤ëëë§
+ë ¤ë
+ë ¤ë©´
+ë ¤ë©´ì
+ë ¤ë©´ì
+ë ¤ë¬´ë
+ë ¨
+ë ¨ë§ë
+ë ¨ë§
+ë ´
+ë ·ë¤
+리
+리ê¹
+리ë
+리ëë¼
+리ë¤
+리ë¼
+리ë¼ë
+리ë
+리ë¡ë¤
+리ë§ì¹
+리ë§í¼
+리ì
+리ìë§ë
+ë§
+매
+ë©°
+ë©°ë
+ë©´
+ë©´ì
+ë©´ìê¹ì§
+ë©´ìê¹ì§ë
+ë©´ìê¹ì§ë§ì
+ë©´ìë
+ë©´ìë¶í°
+ë©´ìë¶í°ë
+ë©´ì
+ë©´ì
+ë¯ë¡
+ì¬
+ì¬ì¤ì´ë¤
+ì¬ìµëê¹
+ì¬ìµëë¤
+ì¬ìµëê¹
+ì¬ìµëë¤
+ì¬ì¸ë¤
+ì¸
+ì¸ì
+ì
+ìì
+ìì´ë¤
+ì ë¤
+ìì¤
+ìµëê¹
+ìµëë¤
+ìµëë¤ë§ë
+ìµëë¤ë§
+ìµëê¹
+ìµëë¤
+ìµëë¤ë§ë
+ìµëë¤ë§
+ì
+ìë¤
+ìë¤ê°
+ìë
+ìë¼
+ìì
+ììê¹ì§
+ììë
+ììë
+ììë§
+ììì
+ìì
+ìì¼
+ìì¼ë§
+ìì
+ì´
+ì´ë¤
+ì´ë¤ê°
+ì´ë
+ì´ë¼
+ì´ì
+ì´ìê¹ì§
+ì´ìë
+ì´ìë
+ì´ìë§
+ì´ìë§ì
+ì´ì
+ì´ì¼
+ì´ì¼ë§
+ì´ì¼ì§
+ì´ì¼ì§ë§
+ì´ì
+ì´ì§ì´ë¤
+ì¸ì
+ìë¤
+ì¤
+ì¤ë¦¬ê¹
+ì¤ë¦¬ê¹ë§ë
+ì¤ë¦¬ê¹ë§
+ì¤ë¦¬ë¤
+ì¤ì´ë¤
+ì¬ìµëë¤
+ì¬ìµëë¤ë§ë
+ì¬ìµëë¤ë§
+ì¬ìë¤
+ìµëì´ê¹
+ìµëì´ë¤
+ìµëê¹
+ìµëë¤
+ìµëë¤ë§
+ìµëê¹
+ìµëë¤
+ì¸ë¤
+ì
+ì¼ë
+ì¼ëë§
+ì¼ë
+ì¼ëê³
+ì¼ë
+ì¼ëê¹
+ì¼ëê¹ë
+ì¼ëê¹
+ì¼ëë¼
+ì¼ëë§ì¹
+ì¼ëë§í¼
+ì¼ë¼
+ì¼ë¼ê³
+ì¼ë¼ê³ ê¹ì§
+ì¼ë¼ê³ ê¹ì§ë
+ì¼ë¼ê³ ê¹ì§ë
+ì¼ë¼ê³ ê¹ì§ë§ì
+ì¼ë¼ê³ ë
+ì¼ë¼ê³ ë
+ì¼ë¼ê³ ë§
+ì¼ë¼ê³ ë§ì
+ì¼ë¼ê³ ì
+ì¼ë¼ëë
+ì¼ë¼ë
+ì¼ë¼ë
+ì¼ë¼ëê¹
+ì¼ë¼ë ì§
+ì¼ë¼ë©°
+ì¼ë¼ë©´
+ì¼ë¼ë©´ì
+ì¼ë¼ë©´ì
+ì¼ë
+ì¼ë
+ì¼ëëê¹
+ì¼ëëë¤
+ì¼ë
+ì¼ëì
+ì¼ëìì¼
+ì¼ëì¼
+ì¼ëì
+ì¼ë´
+ì¼ë´ë§ë
+ì¼ë¬
+ì¼ë¬ê¹ì§
+ì¼ë¬ê¹ì§ë
+ì¼ë ¤
+ì¼ë ¤ê±°ë
+ì¼ë ¤ê³
+ì¼ë ¤ê³ ê¹ì§
+ì¼ë ¤ê³ ê¹ì§ë
+ì¼ë ¤ê³ ê¹ì§ë
+ì¼ë ¤ê³ ê¹ì§ë§
+ì¼ë ¤ê³ ê¹ì§ë§ì
+ì¼ë ¤ê³ ë
+ì¼ë ¤ê³ ë
+ì¼ë ¤ê³ ë§
+ì¼ë ¤ê³ ë§ì
+ì¼ë ¤ê³ ì
+ì¼ë ¤ê¸°ì
+ì¼ë ¤ë
+ì¼ë ¤ëë
+ì¼ë ¤ëëë
+ì¼ë ¤ë
+ì¼ë ¤ëê°
+ì¼ë ¤ëë°
+ì¼ë ¤ëë°ë
+ì¼ë ¤ëë°ì
+ì¼ë ¤ëì§
+ì¼ë ¤ë
+ì¼ë ¤ëê¹
+ì¼ë ¤ëì
+ì¼ë ¤ë¤
+ì¼ë ¤ë¤ê°
+ì¼ë ¤ë¤ê°ë
+ì¼ë ¤ë¤ê°ì
+ì¼ë ¤ë¤ê°
+ì¼ë ¤ëë
+ì¼ë ¤ë©´
+ì¼ë ¤ë©´ì¼
+ì¼ë ¤ë©´ì
+ì¼ë ¤ë¬´ë
+ì¼ë ¤ìì¼
+ì¼ë ¤ì¤
+ì¼ë ¨
+ì¼ë ¨ë¤
+ì¼ë ¨ë§ë
+ì¼ë ¨ë§
+ì¼ë ¨ë§ì
+ì¼ë ´
+ì¼ë µëê¹
+ì¼ë µëë¤
+ì¼ë ·ë¤
+ì¼ë¦¬
+ì¼ë¦¬ê¹
+ì¼ë¦¬ë
+ì¼ë¦¬ëë¼
+ì¼ë¦¬ë¤
+ì¼ë¦¬ë¼
+ì¼ë¦¬ë¡ë¤
+ì¼ë¦¬ë§ì¹
+ì¼ë¦¬ë§í¼
+ì¼ë¦¬ì
+ì¼ë§
+ì¼ë§¤
+ì¼ë©°
+ì¼ë©´
+ì¼ë©´ì
+ì¼ë©´ìê¹ì§
+ì¼ë©´ìê¹ì§ë
+ì¼ë©´ìê¹ì§ë§
+ì¼ë©´ìê¹ì§ë§ì
+ì¼ë©´ìë
+ì¼ë©´ìë
+ì¼ë©´ìë¶í°
+ì¼ë©´ìë¶í°ê¹ì§
+ì¼ë©´ìë¶í°ê¹ì§ë
+ì¼ë©´ìë¶í°ë
+ì¼ë©´ìì
+ì¼ë©´ì
+ì¼ë©´ì
+ì¼ë¯ë¡
+ì¼ì¸ì
+ì¼ì
ì
+ì¼ìì
+ì¼ìì´ì
+ì¼ì¤
+ì¼ì¤ë¦¬ê¹
+ì¼ì¤ë¦¬ë¤
+ì¼ì¤ì´ë¤
+ì¼ìµëê¹
+ì¼ìµëë¤
+ì¼ìµëë¤ë§
+ì¼ìµëê¹
+ì¼ìµëë¤
+ì¼ì¸ë¤
+ì¼ì´
+ì
+ìê°
+ìê°ë¥¼
+ìê°ì
+ìê°ìë
+ìê°ìë§
+ìê°ì
+ì걸
+ì걸ì
+ìê³
+ìë¤
+ìë¤ê³
+ìë¤ê³ ê¹ì§
+ìë¤ê³ ê¹ì§ë
+ìë¤ê³ ë
+ìë¤ë
+ìë¤ëë°
+ìë¤ë
+ìë¤ëê¹
+ìë¤ë ì§
+ìë¤ë§ë
+ìë¤ë©°
+ìë¤ë©´
+ìë¤ë©´ì
+ìë¤ë©´ìë
+ìë¤ë©´ì
+ìë¤ë©´ì
+ìë¨ë¤
+ìë´
+ìëµëê¹
+ìëµëë¤
+ìëµëê¹
+ìëµëë¤
+ìëµìê³
+ìë
+ìëì
+ìëìì¼
+ìëì¼
+ìëì
+ìë°
+ìë°ë
+ìë°ë¤
+ìë°ë
+ìë°ëì
+ìë°ì
+ìë¤
+ìë§í¼
+ìë§í¼ë
+ìë§í¼ë§ì
+ìë§í¼ì
+ìë°
+ìì¦
+ìì¦ì¨
+ìì§
+ìì§ê°
+ìì§ê³
+ìì§ë
+ìì§ë
+ìì§ë¼
+ìì§ë¼ë
+ìì§ë¥¼
+ìì§ë§
+ìì§ë§ì
+ìì§ì
+ì
+ìê±°ë
+ìê±°ë
+ìê±°ë¤
+ìê±°ì¼
+ìê±°ì§ì
+ì걸
+ìê¹
+ìê¹ë§ë
+ìê¹ë´
+ìê¹ì
+ìê»
+ìê»ì
+ì꼬
+ìëì§
+ìëì§ì
+ìë¼
+ìë¼ê³
+ìë¼ê³ ê¹ì§
+ìë¼ê³ ê¹ì§ë
+ìë¼ê³ ê¹ì§ë§
+ìë¼ê³ ë
+ìë¼ê³ ë
+ìë¼ê³ ë§
+ìë¼ê³ ë§ì
+ìë¼ê³ ì
+ìë¼ì
+ìë¼ì¹ë©´
+ìë½
+ìë
+ìëë
+ìëì
+ìë¬ë
+ìë¬ë¼
+ìë°ê°
+ìë°ê³
+ìë
+ìë ë¼
+ìë§í
+ìë§ì
+ìë°ì
+ìë°ìì
+ìë¿ëë¬
+ìì
+ìì¸ë¼
+ìì¸ë§ì´ì§
+ììë
+ììë¡
+ììë
+ìì´ë§í¼
+ììì´ë©´
+ìì§
+ìì§ê°
+ìì§ë
+ìì§ë
+ìì§ëë¼
+ìì§ë
+ìì§ë¼
+ìì§ë¼ë
+ìì§ì´ë¤
+ìì§ì¸ì
+ìì§ì
+ìì§ë
+ìì§ë
+ìì§ì
+ìí
ë¤
+ìí
ë°
+ì
+ìì¸
+ììë
+ììë´
+ìì¼
+ììë¤
+ììë¤ì
+ììì¤
+ì´
+ì¼ê¹
+ì
+ìê³
+ìê³ ê¹ì§
+ìê³ ê¹ì§ë
+ìê³ ê¹ì§ë¼ë
+ìê³ ë
+ìê³ ë
+ìê³ ë§
+ìê³ ë§ì
+ì꾸ë
+ìë
+ìë§ì
+ìë©´
+ìë©´ì
+ì
+ì
+ì§
+ì§ë
+ì§ë
+ì§ë¥¼
+ì§ë§ë
+ì§ë§
+ì§ì
+ì§
+ì§
\ No newline at end of file