├── .gitignore ├── GenerateText.py ├── PrepareChain.py ├── README.md ├── post-hatena-script.sh ├── post-hatena.py ├── sample.txt └── schema.sql /.gitignore: -------------------------------------------------------------------------------- 1 | chain.db 2 | -------------------------------------------------------------------------------- /GenerateText.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | u""" 4 | マルコフ連鎖を用いて適当な文章を自動生成するファイル 5 | """ 6 | 7 | import os.path 8 | import sqlite3 9 | import random 10 | import sys 11 | 12 | from PrepareChain import PrepareChain 13 | 14 | numb_sentence = 5 15 | 16 | class GenerateText(object): 17 | u""" 18 | 文章生成用クラス 19 | """ 20 | 21 | # def __init__(self, n=10): 22 | def __init__(self): 23 | # print ("sentence_numb=" + str(numb_sentence)) 24 | u""" 25 | 初期化メソッド 26 | @param n いくつの文章を生成するか 27 | """ 28 | self.n = numb_sentence 29 | 30 | def generate(self): 31 | u""" 32 | 実際に生成する 33 | @return 生成された文章 34 | """ 35 | # DBが存在しないときは例外をあげる 36 | if not os.path.exists(PrepareChain.DB_PATH): 37 | raise IOError(u"DBファイルが存在しません") 38 | 39 | # DBオープン 40 | con = sqlite3.connect(PrepareChain.DB_PATH) 41 | con.row_factory = sqlite3.Row 42 | 43 | # 最終的にできる文章 44 | generated_text = u"" 45 | 46 | # 指定の数だけ作成する 47 | for i in xrange(self.n): 48 | text = self._generate_sentence(con) 49 | generated_text += text 50 | 51 | # DBクローズ 52 | con.close() 53 | 54 | return generated_text 55 | 56 | def _generate_sentence(self, con): 57 | u""" 58 | ランダムに一文を生成する 59 | @param con DBコネクション 60 | @return 生成された1つの文章 61 | """ 62 | # 生成文章のリスト 63 | morphemes = [] 64 | 65 | # はじまりを取得 66 | first_triplet = self._get_first_triplet(con) 67 | morphemes.append(first_triplet[1]) 68 | morphemes.append(first_triplet[2]) 69 | 70 | # 文章を紡いでいく 71 | while morphemes[-1] != PrepareChain.END: 72 | prefix1 = morphemes[-2] 73 | prefix2 = morphemes[-1] 74 | triplet = self._get_triplet(con, prefix1, prefix2) 75 | morphemes.append(triplet[2]) 76 | 77 | # 連結 78 | result = "".join(morphemes[:-1]) 79 | 80 | return result 81 | 82 | def _get_chain_from_DB(self, con, prefixes): 83 | u""" 84 | チェーンの情報をDBから取得する 85 | @param con DBコネクション 86 | @param prefixes チェーンを取得するprefixの条件 tupleかlist 87 | @return チェーンの情報の配列 88 | """ 89 | # ベースとなるSQL 90 | sql = u"select prefix1, prefix2, suffix, freq from chain_freqs where prefix1 = ?" 91 | 92 | # prefixが2つなら条件に加える 93 | if len(prefixes) == 2: 94 | sql += u" and prefix2 = ?" 95 | 96 | # 結果 97 | result = [] 98 | 99 | # DBから取得 100 | cursor = con.execute(sql, prefixes) 101 | for row in cursor: 102 | result.append(dict(row)) 103 | 104 | return result 105 | 106 | def _get_first_triplet(self, con): 107 | u""" 108 | 文章のはじまりの3つ組をランダムに取得する 109 | @param con DBコネクション 110 | @return 文章のはじまりの3つ組のタプル 111 | """ 112 | # BEGINをprefix1としてチェーンを取得 113 | prefixes = (PrepareChain.BEGIN,) 114 | 115 | # チェーン情報を取得 116 | chains = self._get_chain_from_DB(con, prefixes) 117 | 118 | # 取得したチェーンから、確率的に1つ選ぶ 119 | triplet = self._get_probable_triplet(chains) 120 | 121 | return (triplet["prefix1"], triplet["prefix2"], triplet["suffix"]) 122 | 123 | def _get_triplet(self, con, prefix1, prefix2): 124 | u""" 125 | prefix1とprefix2からsuffixをランダムに取得する 126 | @param con DBコネクション 127 | @param prefix1 1つ目のprefix 128 | @param prefix2 2つ目のprefix 129 | @return 3つ組のタプル 130 | """ 131 | # BEGINをprefix1としてチェーンを取得 132 | prefixes = (prefix1, prefix2) 133 | 134 | # チェーン情報を取得 135 | chains = self._get_chain_from_DB(con, prefixes) 136 | 137 | # 取得したチェーンから、確率的に1つ選ぶ 138 | triplet = self._get_probable_triplet(chains) 139 | 140 | return (triplet["prefix1"], triplet["prefix2"], triplet["suffix"]) 141 | 142 | def _get_probable_triplet(self, chains): 143 | u""" 144 | チェーンの配列の中から確率的に1つを返す 145 | @param chains チェーンの配列 146 | @return 確率的に選んだ3つ組 147 | """ 148 | # 確率配列 149 | probability = [] 150 | 151 | # 確率に合うように、インデックスを入れる 152 | for (index, chain) in enumerate(chains): 153 | for j in xrange(chain["freq"]): 154 | probability.append(index) 155 | 156 | # ランダムに1つを選ぶ 157 | chain_index = random.choice(probability) 158 | 159 | return chains[chain_index] 160 | 161 | 162 | if __name__ == '__main__': 163 | param = sys.argv 164 | if (len(param) != 2): 165 | print ("Usage: $ python " + param[0] + " number") 166 | quit() 167 | 168 | numb_sentence = int(param[1]) 169 | 170 | generator = GenerateText() 171 | gen_txt = generator.generate() 172 | print (gen_txt.encode('utf_8')) 173 | -------------------------------------------------------------------------------- /PrepareChain.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | u""" 4 | 与えられた文書からマルコフ連鎖のためのチェーン(連鎖)を作成して、DBに保存するファイル 5 | """ 6 | 7 | import unittest 8 | 9 | import re 10 | import MeCab 11 | import sqlite3 12 | from collections import defaultdict 13 | 14 | import sys 15 | 16 | class PrepareChain(object): 17 | u""" 18 | チェーンを作成してDBに保存するクラス 19 | """ 20 | 21 | BEGIN = u"__BEGIN_SENTENCE__" 22 | END = u"__END_SENTENCE__" 23 | 24 | DB_PATH = "chain.db" 25 | DB_SCHEMA_PATH = "schema.sql" 26 | 27 | def __init__(self, text): 28 | u""" 29 | 初期化メソッド 30 | @param text チェーンを生成するための文章 31 | """ 32 | if isinstance(text, str): 33 | text = text.decode("utf-8") 34 | self.text = text 35 | 36 | # 形態素解析用タガー 37 | self.tagger = MeCab.Tagger('-Ochasen') 38 | 39 | def make_triplet_freqs(self): 40 | u""" 41 | 形態素解析から3つ組の出現回数まで 42 | @return 3つ組とその出現回数の辞書 key: 3つ組(タプル) val: 出現回数 43 | """ 44 | # 長い文章をセンテンス毎に分割 45 | sentences = self._divide(self.text) 46 | 47 | # 3つ組の出現回数 48 | triplet_freqs = defaultdict(int) 49 | 50 | # センテンス毎に3つ組にする 51 | for sentence in sentences: 52 | # 形態素解析 53 | morphemes = self._morphological_analysis(sentence) 54 | # 3つ組をつくる 55 | triplets = self._make_triplet(morphemes) 56 | # 出現回数を加算 57 | for (triplet, n) in triplets.items(): 58 | triplet_freqs[triplet] += n 59 | 60 | return triplet_freqs 61 | 62 | def _divide(self, text): 63 | u""" 64 | 「。」や改行などで区切られた長い文章を一文ずつに分ける 65 | @param text 分割前の文章 66 | @return 一文ずつの配列 67 | """ 68 | # 改行文字以外の分割文字(正規表現表記) 69 | delimiter = u"。|.|\." 70 | 71 | # 全ての分割文字を改行文字に置換(splitしたときに「。」などの情報を無くさないため) 72 | text = re.sub(ur"({0})".format(delimiter), r"\1\n", text) 73 | 74 | # 改行文字で分割 75 | sentences = text.splitlines() 76 | 77 | # 前後の空白文字を削除 78 | sentences = [sentence.strip() for sentence in sentences] 79 | 80 | return sentences 81 | 82 | def _morphological_analysis(self, sentence): 83 | u""" 84 | 一文を形態素解析する 85 | @param sentence 一文 86 | @return 形態素で分割された配列 87 | """ 88 | morphemes = [] 89 | sentence = sentence.encode("utf-8") 90 | node = self.tagger.parseToNode(sentence) 91 | while node: 92 | if node.posid != 0: 93 | morpheme = node.surface.decode("utf-8") 94 | morphemes.append(morpheme) 95 | node = node.next 96 | return morphemes 97 | 98 | def _make_triplet(self, morphemes): 99 | u""" 100 | 形態素解析で分割された配列を、形態素毎に3つ組にしてその出現回数を数える 101 | @param morphemes 形態素配列 102 | @return 3つ組とその出現回数の辞書 key: 3つ組(タプル) val: 出現回数 103 | """ 104 | # 3つ組をつくれない場合は終える 105 | if len(morphemes) < 3: 106 | return {} 107 | 108 | # 出現回数の辞書 109 | triplet_freqs = defaultdict(int) 110 | 111 | # 繰り返し 112 | for i in xrange(len(morphemes)-2): 113 | triplet = tuple(morphemes[i:i+3]) 114 | triplet_freqs[triplet] += 1 115 | 116 | # beginを追加 117 | triplet = (PrepareChain.BEGIN, morphemes[0], morphemes[1]) 118 | triplet_freqs[triplet] = 1 119 | 120 | # endを追加 121 | triplet = (morphemes[-2], morphemes[-1], PrepareChain.END) 122 | triplet_freqs[triplet] = 1 123 | 124 | return triplet_freqs 125 | 126 | def save(self, triplet_freqs, init=False): 127 | u""" 128 | 3つ組毎に出現回数をDBに保存 129 | @param triplet_freqs 3つ組とその出現回数の辞書 key: 3つ組(タプル) val: 出現回数 130 | """ 131 | # DBオープン 132 | con = sqlite3.connect(PrepareChain.DB_PATH) 133 | 134 | # 初期化から始める場合 135 | if init: 136 | # DBの初期化 137 | with open(PrepareChain.DB_SCHEMA_PATH, "r") as f: 138 | schema = f.read() 139 | con.executescript(schema) 140 | 141 | # データ整形 142 | datas = [(triplet[0], triplet[1], triplet[2], freq) for (triplet, freq) in triplet_freqs.items()] 143 | 144 | # データ挿入 145 | p_statement = u"insert into chain_freqs (prefix1, prefix2, suffix, freq) values (?, ?, ?, ?)" 146 | con.executemany(p_statement, datas) 147 | 148 | # コミットしてクローズ 149 | con.commit() 150 | con.close() 151 | 152 | def show(self, triplet_freqs): 153 | u""" 154 | 3つ組毎の出現回数を出力する 155 | @param triplet_freqs 3つ組とその出現回数の辞書 key: 3つ組(タプル) val: 出現回数 156 | """ 157 | for triplet in triplet_freqs: 158 | print "|".join(triplet), "\t", triplet_freqs[triplet] 159 | 160 | 161 | class TestFunctions(unittest.TestCase): 162 | u""" 163 | テスト用クラス 164 | """ 165 | 166 | def setUp(self): 167 | u""" 168 | テストが実行される前に実行される 169 | """ 170 | self.text = u"こんにちは。 今日は、楽しい運動会です。hello world.我輩は猫である\n 名前はまだない。我輩は犬である\r\n名前は決まってるよ" 171 | self.chain = PrepareChain(self.text) 172 | 173 | def test_make_triplet_freqs(self): 174 | u""" 175 | 全体のテスト 176 | """ 177 | triplet_freqs = self.chain.make_triplet_freqs() 178 | answer = {(u"__BEGIN_SENTENCE__", u"今日", u"は"): 1, (u"今日", u"は", u"、"): 1, (u"は", u"、", u"楽しい"): 1, (u"、", u"楽しい", u"運動会"): 1, (u"楽しい", u"運動会", u"です"): 1, (u"運動会", u"です", u"。"): 1, (u"です", u"。", u"__END_SENTENCE__"): 1, (u"__BEGIN_SENTENCE__", u"hello", u"world"): 1, (u"hello", u"world", u"."): 1, (u"world", u".", u"__END_SENTENCE__"): 1, (u"__BEGIN_SENTENCE__", u"我輩", u"は"): 2, (u"我輩", u"は", u"猫"): 1, (u"は", u"猫", u"で"): 1, (u"猫", u"で", u"ある"): 1, (u"で", u"ある", u"__END_SENTENCE__"): 2, (u"__BEGIN_SENTENCE__", u"名前", u"は"): 2, (u"名前", u"は", u"まだ"): 1, (u"は", u"まだ", u"ない"): 1, (u"まだ", u"ない", u"。"): 1, (u"ない", u"。", u"__END_SENTENCE__"): 1, (u"我輩", u"は", u"犬"): 1, (u"は", u"犬", u"で"): 1, (u"犬", u"で", u"ある"): 1, (u"名前", u"は", u"決まっ"): 1, (u"は", u"決まっ", u"てる"): 1, (u"決まっ", u"てる", u"よ"): 1, (u"てる", u"よ", u"__END_SENTENCE__"): 1} 179 | self.assertEqual(triplet_freqs, answer) 180 | 181 | def test_divide(self): 182 | u""" 183 | 一文ずつに分割するテスト 184 | """ 185 | sentences = self.chain._divide(self.text) 186 | answer = [u"こんにちは。", u"今日は、楽しい運動会です。", u"hello world.", u"我輩は猫である", u"名前はまだない。", u"我輩は犬である", u"名前は決まってるよ"] 187 | self.assertEqual(sentences.sort(), answer.sort()) 188 | 189 | def test_morphological_analysis(self): 190 | u""" 191 | 形態素解析用のテスト 192 | """ 193 | sentence = u"今日は、楽しい運動会です。" 194 | morphemes = self.chain._morphological_analysis(sentence) 195 | answer = [u"今日", u"は", u"、", u"楽しい", u"運動会", u"です", u"。"] 196 | self.assertEqual(morphemes.sort(), answer.sort()) 197 | 198 | def test_make_triplet(self): 199 | u""" 200 | 形態素毎に3つ組にしてその出現回数を数えるテスト 201 | """ 202 | morphemes = [u"今日", u"は", u"、", u"楽しい", u"運動会", u"です", u"。"] 203 | triplet_freqs = self.chain._make_triplet(morphemes) 204 | answer = {(u"__BEGIN_SENTENCE__", u"今日", u"は"): 1, (u"今日", u"は", u"、"): 1, (u"は", u"、", u"楽しい"): 1, (u"、", u"楽しい", u"運動会"): 1, (u"楽しい", u"運動会", u"です"): 1, (u"運動会", u"です", u"。"): 1, (u"です", u"。", u"__END_SENTENCE__"): 1} 205 | self.assertEqual(triplet_freqs, answer) 206 | 207 | def test_make_triplet_too_short(self): 208 | u""" 209 | 形態素毎に3つ組にしてその出現回数を数えるテスト 210 | ただし、形態素が少なすぎる場合 211 | """ 212 | morphemes = [u"こんにちは", u"。"] 213 | triplet_freqs = self.chain._make_triplet(morphemes) 214 | answer = {} 215 | self.assertEqual(triplet_freqs, answer) 216 | 217 | def test_make_triplet_3morphemes(self): 218 | u""" 219 | 形態素毎に3つ組にしてその出現回数を数えるテスト 220 | ただし、形態素がちょうど3つの場合 221 | """ 222 | morphemes = [u"hello", u"world", u"."] 223 | triplet_freqs = self.chain._make_triplet(morphemes) 224 | answer = {(u"__BEGIN_SENTENCE__", u"hello", u"world"): 1, (u"hello", u"world", u"."): 1, (u"world", u".", u"__END_SENTENCE__"): 1} 225 | self.assertEqual(triplet_freqs, answer) 226 | 227 | def tearDown(self): 228 | u""" 229 | テストが実行された後に実行される 230 | """ 231 | pass 232 | 233 | 234 | if __name__ == '__main__': 235 | # unittest.main() 236 | 237 | param = sys.argv 238 | if (len(param) != 2): 239 | print ("Usage: $ python " + param[0] + " sample.txt") 240 | quit() 241 | 242 | 243 | f = open(param[1]) 244 | text = f.read() 245 | f.close() 246 | 247 | # print (text) 248 | 249 | chain = PrepareChain(text) 250 | triplet_freqs = chain.make_triplet_freqs() 251 | chain.save(triplet_freqs, True) 252 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Text Generator 2 | マルコフ連鎖を使った文章自動生成プログラム 3 | 4 | ## バージョン 5 | ver 0.1 base karaage modify version 6 | 7 | ## 使い方 8 | 文章の自動生成の方法 9 | 10 | ### インストール(git clone) 11 | 12 | ~~~~ 13 | $ git clone https://github.com/karaage0703/TextGenerator.git 14 | $ cd TextGenerator 15 | ~~~~ 16 | 17 | ### 事前準備 18 | まずは、事前準備として、適当な長い文章が入ったテキストデータを用意 ex:`sample txt` 19 | 以下コマンド実行 20 | ~~~~ 21 | $ python PrepareChain.py sample.txt 22 | ~~~~ 23 | 24 | ### 文章の生成 25 | 事前準備を実施した後、以下コマンド実行。 26 | 引数は文章の数を表す。以下は文章数が10のときの例 27 | 28 | ~~~~ 29 | $ python GenerateText.py 10 30 | ~~~~ 31 | 32 | ファイルに出力も可能 33 | 34 | ~~~~ 35 | $ python GenerateText.py 10 > output.txt 36 | ~~~~ 37 | 38 | ### はてなブログに投稿 39 | `post-hatena.py`の以下の箇所を自身のはてなブログに合わせて修正 40 | 41 | ~~~~ 42 | username = 'username' 43 | password = 'API key' 44 | blogname = 'yourblogname.hatenablog.com' 45 | ~~~~ 46 | 47 | 以下ではてなブログに投稿できる。`title.txt` `body.txt`にはそれぞれ記事のタイトルと本文を書いたテキストファイルを入れる 48 | 49 | ~~~~ 50 | $ post-hatena.py title.txt body.txt 51 | ~~~~ 52 | 53 | ### はてなブログに自動で連続投稿 54 | 以下で実行権限を付与 55 | ~~~~ 56 | $ chmod 755 post-hatena-script.sh 57 | ~~~~ 58 | 59 | 例えば10回連続で投稿するには以下 60 | ~~~~ 61 | $ ./post-hatena-script 10 62 | ~~~~ 63 | 64 | はてなブログは24時間に100回までしか投稿できないので注意すること 65 | 66 | 67 | ## 各ファイル 68 | ### README.md 69 | このファイル 70 | 71 | ### PrepareChain.py 72 | 適当なテキストを与えて、そこから3つ組のチェーンを作成し、DBに保存するファイル 73 | 74 | ### schema.sql 75 | DB作成のためのスキーマファイル 76 | 77 | ### GenerateText.py 78 | 実際にランダムで文章を生成するファイル 79 | 80 | ### chain.db 81 | gitで管理はされていないが、3つ組チェーンの情報が保存されているDBファイル 82 | -------------------------------------------------------------------------------- /post-hatena-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | CMDNAME=`basename $0` 4 | if [ $# -ne 1 ]; then 5 | echo "Usage: $CMDNAME number" 6 | exit 1 7 | fi 8 | 9 | i=0 10 | start_time=`date +%s` 11 | while [ $i -ne $1 ] 12 | do 13 | i=`expr $i + 1` 14 | python GenerateText.py 1 > title.txt 15 | python GenerateText.py 20 > body.txt 16 | python post-hatena.py title.txt body.txt 17 | done 18 | 19 | end_time=`date +%s` 20 | time=$((end_time - start_time)) 21 | 22 | echo $time 23 | -------------------------------------------------------------------------------- /post-hatena.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import datetime 3 | import random 4 | import hashlib 5 | import base64 6 | import requests 7 | import sys 8 | 9 | username = 'username' 10 | password = 'API key' 11 | blogname = 'yourblogname.hatenablog.com' 12 | 13 | def wsse(username, password): 14 | created = datetime.datetime.now().isoformat() + 'Z' 15 | nonce = hashlib.sha1(str(random.random())).digest() 16 | digest = hashlib.sha1(nonce + created + password).digest() 17 | 18 | return 'UsernameToken Username="{}", PasswordDigest="{}", Nonce="{}", Created="{}"'.format(username, base64.b64encode(digest), base64.b64encode(nonce), created) 19 | 20 | 21 | def posthatena(data): 22 | headers = {'X-WSSE': wsse(username, password)} 23 | 24 | url = 'http://blog.hatena.ne.jp/{}/{}/atom/entry'.format(username, blogname) 25 | 26 | r = requests.post(url, data=data, headers=headers) 27 | print (r) 28 | 29 | if __name__ == '__main__': 30 | 31 | param = sys.argv 32 | if (len(param) != 3): 33 | print ("Usage: $ python " + param[0] + " title.txt body.txt") 34 | quit() 35 | 36 | f = open(param[1]) 37 | title = f.read() 38 | f.close() 39 | 40 | f = open(param[2]) 41 | body = f.read() 42 | f.close() 43 | 44 | data = """ 45 | 47 | """ + title + """ 48 | name 49 | 50 | """ + body + """ 51 | 52 | 53 | 54 | no 55 | 56 | 57 | """ 58 | 59 | posthatena(data) 60 | -------------------------------------------------------------------------------- /sample.txt: -------------------------------------------------------------------------------- 1 | オリジナル名刺をつくろう! 2 |  最近、仕事以外の活動で名刺をもらうことが多くなりました。そんなある日、ろんすた (id:lonestartx) さん、lomomaria (id:marialite)さんから「You 名刺つくっちゃいなYO!」と言われて、いつも貰いっぱなしも何だしなということで名刺を作ってみることにしました。 3 |  せっかく作るのだから、会社の名刺みたいにクソみたいなテンプレートに縛られない、オリジナルデザインの名刺を作ってみることにしました。ちなみに私は入社2年目くらいのとき、会社の名刺に多少カスタムで注文を入れたら、何故か管理課のオッサンが激怒して言い争いになったことがあります。最近では流石にそんなこともないですけど。 4 | オリジナルなデザイン名刺を安くつくる方法 5 |  というわけで、自分が名刺を作った具体的な方法を公開します。もちろん後で忘れないようにするためです。名刺を作るにあたって決めたクライテリアは以下 6 | オリジナルのデザイン 7 | 枚数は100枚くらい 8 | コストは1000円以下 9 | Macのフリーのソフトでデザイン 10 | 納期は1週間以内 11 |  巨大な名刺とか、基板名刺とかも面白そうだなと思ったのですが、コストと貰った人の迷惑を考えて今回は標準的なサイズと材質の名刺にすることにしました。 12 |  TOKIOだったら「名刺を作るってどのレベルで?紙から?」となるところですが、便利なサービスも溢れていることですし今回は外注。色々なサービス比較したのですが、標準的な材質、サイズだとどこもコストと納期は似たり寄ったりな感じでした。 13 |  その中でも、パワーポイントやpdfで入稿を受け付けてくれるラクスルを選定しました。意外にイラストレータとかPhotoshopのデータ形式でしか受け付けていないサービスが多かったです。そんな高級ソフト持ってないよ! 14 |  なんと名刺のテンプレートも公開されています。こりゃ使うしか無いね!ラクスルさん最高! 15 |  ラクスルさんのパワポのテンプレートを使用します。ソフトは、私はKeynoteを使いました。Keynote持ってない人は、OpenOfficeとかフリーのオフィスソフト使えばよいかなと思います。あとはサクっとお絵描き。 16 |  できた! 17 | 18 |  文字は「けいおん!フォント」を使いました。「けいおん!フォント」に関しては以下記事参照。 19 | 20 |  独自のフォントをつかったのと、パワポはデザイン崩れないか少し不安だったので、pdfに変換して入稿 21 |  コストパフォーマンスの高い入稿から5日以内を選択 22 |  合計はサービスの100ptがついて、691円也!! 23 |  一日で仕上がりの確認データがきます(確認しないでもOKですが、初回なので確認しました)。問題なかったのでOKをクリック。後はじっと待つのみです。 24 |  入稿から5日以内とあったのですが、なんとデータ確認の次の日には発送されていました。早い!!空いていたのかな? 25 |  ラクスルさんからお名刺きたよ☆(メール便で注文しました) 26 |  しっかりしたケースに入っています 27 |  じゃじゃーん!クオリティ、安いのに悪くないんじゃない。やったねー。 28 |  というわけで名刺を作ってみました。会社以外の名刺を持つのはそんなに良い印象を持ってなかったのですが、作ってみると楽しいものですね。抵抗ある人も、安いし手軽にできるので一度気軽に名刺つくってみてもよいのではないかなと思います。あと最大の問題は100枚ももらってくれる人がいるかどうかですね。欲しい人は是非是非声かけて下さいー。 29 |  「uonome」バージョンアップしています。 30 |  新規点は以下です。よければ新しいバージョンを使ってみて下さい。 31 | バイリニア(Bilinear)・バイキュービック(Bicubic)補間機能追加 32 | 画像天地クロップ機能追加 33 | 動作高速化(+リファクタリング) 34 | Processing3対応 35 | 魚眼レンズ写真を超広角レンズ写真に変換 36 |  実は id:OKP さんから、以前から魚眼ボディキャップ購入を勧められると共に、購入したら魚眼レンズの写真を広角写真に変換するアプリ開発してと要望うけていました。てっきり忘れていると思ったのですが、ブコメでもしっかり要望されてましたw 37 | 38 |  そんなもん需要あるんかいなと思っていましたが、調べてみると意外に手頃で使い勝手の良いアプリが無く、わざわざPhotoshopを使っている人もいたりしてビックリしました。困っている人もいるようなのと、何より面白そうなので自分で作ってみることにしました。 39 |  といわけでできました。半日くらいかな?ソフトと関係ないところで時間かかりました。githubで公開、リリースします。ライセンスはMITとしますので、好きに使用・改変下さい。 40 |  アイコンはけいおんフォントとkeynoteで適当に作りました。 41 | 42 |  githubって何?気取ってんじゃねーぞ!という方、安心して下さい、ついてますよ。下記リンク先にバイナリファイルを置いておくのでダウンロードして開けば使用できます。下の方のDownloadsの下のzipファイルがソフトです。 43 |  Macの方はuonome_for_mac_v0_1.zipをダウンロード。Windowsの方はuonome_for_win_v0_1.zipをダウンロードして下さい。ただWindowsの方はテストしてないので動くかわからないです。動かなかったらごめんなさい。 44 |  Processing 1.5.1で作っています。pythonで作ろうかと思ったのですが、使い勝手等考えてProcessingにしました。ProcessingはUIが簡単に作れるのでほんとうに楽です。以前作った自作の多重露光ソフト「Multiple Exposed Holic」をベースに作ったのすんなりできました。ライブラリの関係でProcessing 2以降は対応していません。随時改良中です。最新verをチェック下さい。 45 | 46 |  作り方などは、最後の方に書くので興味ある方はみてください。あと、ちゃんとした補間してないので画質はイマイチです。バイリニアとかの補間プログラム書いてpull requestもらえると泣いて喜びます。おしゃれなアイコンも募集中。Processing 3にも対応したいかな。 47 | 48 |  起動した後は、小さい方のウィンドウの上の方にあるLOAD SOURCE IMAGEをクリックして下さい。ダイアログボックスが開くので、魚眼レンズで撮影した写真を選択して下さい。試すだけなら、別に魚眼レンズで撮影した写真じゃなくても大丈夫です。あんまり大きいファイルだと落ちるかもしれないので、お手数ですがファイル縮小してみてください。 49 |  写真を開いた後は、その下のスライダでパラメータを調整してみましょう。上の2つのGAMMA_SとGAINはガンマカーブと明るさの調整で魚眼の補正とは関係ないです。 50 |  その下のRAD_FISH_VALとDIST_FISH_VALが魚眼の補正のパラメータです。私の魚眼ボディキャップレンズ(BCL-0980)だと RAD_FISH_VAL=0.7、DIST_FISH_VAL=0.5付近だと良い感じに補正されました。 51 |  その下のCONVERT MODEはおまけです。基本は魚眼から超広角への変換ですが下のNORMAL FISHEYECONVをクリックすると、普通の写真を魚眼レンズで撮ったような写真に変換することができます。よくあるやつですね。 52 |  良い感じに変換できたら SAVE IMAGEをクリックして下さい。ダイアログが出てきますので、好きなファイル名を入れて保存して下さい。image.jpgみたいな感じに拡張子まで入力する必要あるので注意して下さい。pngとかでも保存できます。 53 |  魚眼レンズで撮影した写真を「uonome」で変換すると… 54 |  こうじゃ! 55 |  同じ構図で9mm(35mm換算で18mm)のレンズで撮影した写真が以下です。 56 |  9mmのレンズより全然広い画角!35mm換算で14mm相当くらいになるのではないでしょうか? 57 |  8000円程度で14mm相当のレンズが変える。そうマイクロフォーサーズとuonomeならね! 58 |  あとはお待ちかねの(退屈な?)作り方です。 59 |  魚眼レンズどうやって変換するかなと調べていたら、まさに求めていたような回答ずばりの記事が。 60 |  神がいた…。もうちょっと頭使って自分で考えた方が良かったかもしれません、でも自分だけだとひょっとしたらできなかったかも。ネット万歳ですね。自分の理解の整理に絵を入れて補足すると以下かな。 61 |  左が魚眼で、右が普通のレンズの投影のイメージ。詳しく聞かないで、私もよくわかりません(笑) 62 |  上記の角度を同じに保つ拘束条件で、以下の式が得られる 63 |  上記式を変形していくと、魚眼レンズと普通のレンズの変換式が得られます。「uonome」のパラメータRAD_FISH_VALとDIST_FISH_VALは、上の式のrとDにそれぞれ対応します。Do you understand? I can't understand. 64 |  プログラムはGitHubに公開しているので、好きに使用ください。 65 |  というわけで今年最後にふさわしい記事で締め括れて満足しています。意味がわからない!電波すぎる!宇宙語!という声も多いので、来年はちょっと電波な感じの記事は減らしていこうかなと思います。読み手の期待に応える男ですからね。褒めてください。 66 |  折角ソフト作ったので、誰か使ってくれると嬉しいです。私は使うかわかりませんが。 67 | 68 | 東京ではてなブログ繋がりのブロガーさんとお会いしました 69 |  先週末は東京に仕事で泊まりで出張だったのですが、なんとはてなブログ繋がりのブロガーさんであるOKP(id:OKP) さんからお誘いいただき、一緒にご飯を食べてきました!東京出張ではてなブロガーさんと会うのはなんと今月2度目!フットワーク軽いと思われていたようですが、フットワークというか全体的に軽いです、フワフワだよぅ。 70 |  ことの詳細などは以下のOKPさんの記事が詳しいので参照ください(完全に手抜き)。ちなみに最近、私は色々な方に何故か先生と呼ばれるのですが、私の方が年下ですし特に何も教えれるようなことないですから! 71 |  ただ、はてなブログで知っているとは言え、初めて会う人なので会う前は万一のことを考えて、別用途で持ってきていたRaspberry Piで日付が変わるまでに解除しないと自動的に「犯人はOKP(id:OKP)」と呟く時限式のTwitter Botをホテルに仕込んだ上で、フンドシを綺麗にしてから待ち合わせの場所に向かいました。 72 |  OKPさんの記事にあるように、色々お話してきたのですが、やはりOKPさんからはなんというか、一流ブロガーの匂いがプンプン漂っていました。それもそのはず!OKPさんといえば、はてな東京オフィスに行っていたり、他のメディアに寄稿していたりと今乗りに乗っているブロガー。そして何よりはてなTシャツをもらっている! 73 |  一方私はといえば、はてなTシャツゲット、はてなオフィス訪問という2大目標を掲げながら、はてなTシャツをもらい損ね続けてついにはてなブログさんを脅迫し出す始末!。完敗だわー、こりゃ完全に負け犬ワンワンだわー。 74 |  しかし、なんとはてなブログの中の人にこの零細ブログがちゃんと認識されているという情報を得ました。たまに記事ツイートしてもらってたけどボットじゃなかったんだ!これはアピールする最大のチャンス!美味しそうなご飯の写真とかレビュを載せれば、はてなの人に寄稿の依頼を受けて、オフィスに招待してもらいTシャツをお土産にもらてやるぜ!幸いなことに、お手本をOKPさんが記事で示していてくれているので、これをベースに私が独自の表現を加えれば…勝てる!これは勝てるぞ!下克上…なる!! 75 |  いつものように料理の写真貼り付けて「すごくおいしかったです」という小学生並みの感想書いてる場合じゃないですね。今回、料理の表現のために「神の雫」を漫画喫茶で読み込んできた私に死角は無い! 76 |  というわけでここからアピール箇所ですので関係者の方は注意深く読んでみてくださいね! 77 |  そんなこんなでやってきました。東京のスペイン料理居酒屋。お店の名前難しくてなんて読むかちょっとわからないです。お店の詳細はOKPさんの記事を参考にしてくださいね! 78 |  外観はこんな感じ。超オシャレ! 79 | 80 |  しばらく待つと次々と美味しい料理が!! 81 |  お… おお…… お…… この艶かしいタコの肌触り。その肌の滑らかさはまさにギリシア神話の美と愛の女神アプロディーテに抱かれているかのよう。ほんのり香るバナナの香りにフィリピーナの情熱が溶け出しているではないか!!麗しきカルパッチョ、ああカルパッチョ 82 |  お… おお…… お…… そのそそり勃つ肉棒。まさにギリシャ神話最強の英雄ヘラクレスの股間の如し!噛むたびに肉汁がピュッピュピュッピュ!味の助もびっくり!結構辛くてびっくり! 83 |  お… おお…… お…… このくらいになってくるとだいぶ酔っぱらっていて記憶がなくなりつつある。この後めちゃくちゃデキャンタした。 84 |  お… おお…… お…… これこそまさにギリシャ神話女神の、なんていうか、誰だろうな。ギリシャ神話の女神とか知らないけど、たぶん全員抱いたぜ 85 |  すごくおいしかったです 86 |  からあげ美味しかった! 87 | 88 |  OKPさんありがとうございました。こんなですが今後もよろしくお願いします。OKPさんのブログは私のよりずっと面白いので、みなさん是非見に行きましょう。 89 |  あとはてなブログさん、私まだ今年の目標諦めてないですから! 90 | 東大生のノートはここが違うとか、できる男はこう手帳を使うなど、ノートの取り方で勉強の優秀さ、仕事の優秀さが分かるといいます。まあそうですよね、その人のノートをみれば、人柄だったり、知識だったりが滲みでてくるものです。 91 |  特に私のような「鳥並の記憶力を持つ男」としてノートは必須。役員や上司の大切なお言葉だったり、大切なお客さん、取引先の似顔絵を描いたりと、もはやなくてはならない必須ツールなのです。できる男として基本ノートを見返すことはないのですが、今日久しぶりに自分のノートを見直してみると、色々な気づきがありました。以前、ロンスタ (id:lonestartx) さんから「からあげ君の手帳を見てみたい」という声もあったので、今日は思い切って自分の仕事手帳の一部をみなさんに大公開しようと思います。 92 |  ちなみに、できる男としてツールにももちろんこだわっていてトラベラーズノートに激安万年筆プレピー0.2を使っています。 93 |  というわけで手帳の中身のほんの一部を公開。プライバシや業務上の機密に関わる恐れのある箇所は塗りつぶさせていただきましたが、極力私が手帳を書くときに込めた思いや息遣いが生々しく伝わるように最小限の修正で公開いたします。 94 |  どっかの先生。多分激似 95 |  メーカの営業さん。鳥並の記憶力を持つ男として、似顔絵は必須。私が似顔絵描いているのを、メーカさんは私が興味を示してメモを取ってくれていると勘違いしてトークを待ってくれるのが非常に申し訳なかったです。 96 |  多分これ描いたときは、何か凄いヒラメキがあったんだと思います。完全に勘違いでしたね。 97 |  謎の生物 98 |  なんかいいこと書いてあるっぽいけど、顔文字が謎!そして、字が汚すぎて読めない!なんだこれ! 99 |  偉い先生だったと思う。かなり激似 100 |  これも書いたときは凄いヒラメキあったんだと思います。 101 |  これは丁寧。なにか気になる人だったんだと思います。 102 |  結構イケメン。大学の先生だったかな?自信ないです 103 |  これに至っては、何なのか今となっては検討もつきません。ブラックホールとホワイトホール? 104 |  こんな感じでほんの一部ですが、私の手帳を公開させていただきました。私がいかにできる男であるかが伝わったと思います。そしてあらためて思ったのが、「昔の手帳は全て燃やして良いな」ということでした。 105 |  ちなみに私は、学生時代はそもそもノート自体を使っておらず、教科書の余白にメモを書き込んで済ませていました。数学で途中式が書ききれないときは、フェルマーのごとく「ここに記すには余白が狭すぎる」といいながら答えだけ書いていた記憶があります。そんなだったので残念ながら東大には行けませんでした。 106 |  ちなみに、できる男として2016年も手帳とペンは「トラベラーズノート」と「激安万年筆プレピー0.2」の組み合わせで攻めようと思います。書きやすいし使い込むほど味がでるのでオススメの組み合わせです。 107 | 実は妻は、ブドウが大好きです。私はというと、嫌いではないのですがあまり種があるのが好きじゃないので巨峰が苦手なのと、種無しブドウは皮を剥くのが面倒臭いという、ダメッぷり。 108 |  そんな私にピッタリの、種も無くて皮ごと食べられるというブドウがあるということで食べてみることにしました。その名も「ナガノパープル」。ブドウ好きの妻は嬉々として注文。 109 | 超美味しかったです。さすが1房1000円以上するだけあります。だいたい一粒に換算すると50円くらいでしょうか。こんなブドウならいくらでも食べれてしまいますね。私のようにブドウの種も皮も嫌いな人でもブドウが好きになるかもしれません。ついついムシャムシャ食べすぎて妻から怒られてしまいました。ごめんなさい。 110 | 今週、変デジ研究所のロンスタ夫妻とお会いしました。子供が出来てからなかなかお店にも遊びに行けなかったので、思い切って平日に有休をとって会うことにしたのです。早速ロンスタさんブログの記事で取り上げていただきました。しかも2つも! 111 | お昼は一緒に「cafe kaya (カフェ カヤ)」というお店にいきました。子供にも優しい素敵なお店です。自分は3回目くらいなので、ふんふーんという感じでくつろいでいたのですが、ロンスタさんは鋭い目つきであたりをチェックし始めました。「これはブログのネタになる匂いがプンプンするぜー!」とでも言いたげな目をしていました。 112 | 写真撮影開始 113 | ちゃんと、ブログのネタになるようにツマーさんと注文するメニュも分けて細かく写真を撮っていきます。 114 | 完全にプロの目つき 115 | 116 |  一方の私はというと、ここにくると大好きな「からあげプレート」一択。他のメニューには目もくれません。そして、ロンスタさんの鋭いチェックに気圧されて、なんとからあげプレートの写真を撮り忘れるという体たらく。iPhoneで撮って完全に満足してました。 117 | このように、同じことを体験してもブログの内容は全く異なるから面白いですね。そして、私の適当っぷりが改めてよくわかりましたw 118 |  ちゃんとブログを見る人のことを考えて、価値を提供するのが一流のブロガー。私のように自分が気に入ったもの、好きなものを全く見る人のこと考えずに自分のためだけにデータをただアップするのが三流のブロガーです。みなさんも気をつけましょうね。 119 |  ただ、一応自分なりのポリシはあって、嫌いなものとか、辛いこと、興味がないことにはブログでは基本的に触れないようにしていることです。生きていると楽しいこともありますが、やはり色々と辛いことや腹が立つこともたまにはあります。でも、せめてネットの中くらいは自由に好きなことに囲まれていたいなと思います。そうでないと悲しすぎますよね。 120 | 121 |  ロンスタさんからは、ブログのネタになるような色々なお土産ももらったので、一流のブロガーになるための宿題と思ってしっかり生かそうと思います。 122 | 123 | 自分は結構昔からこのサービスを使っていて2010年からのログを貯めています。こうするとEvernoteで自分の過去のつぶやきを検索できます。Twitter単体だと、自分の過去のつぶやきを簡単に全検索することは意外に難しいので、こうやってEvernoteに自分の記録を貯めておくと結構役に立つことがあります。 124 | 去年地元の忘年会で、昔の出来事の話をしていたとき。細かいところが思い出せなくなったりすることがよくあります。例えば、「スカイライン」ってクソ映画って、誰と何をみにいったっけ?といったような話が出たとき、なかなか思い出せないのですが、Evernoteで「スカイライン」と検索すれば一発。同じ日に「スーパーエイト」というこれまたETの焼き直し映画を見て、その後びっくりドンキーにいったことまで分かり、話が盛り上がりました。忘れちゃってたらそれまでなのですが、こうやってログを取っておくと思い出話も盛り上がります。 125 | 126 |  これだけだとなんかしょぼいですね。でもログって後から色々活用できたりするので、自動でとれるならとっておいたほうが便利です。なんたって時代はビッグデータとIoTと人工知能ですからね(適当)。個人的には、脈拍だったり、身体のモーション(加速度)だったり、視覚(画像)データ等のあらゆるデータを自動で記録してクラウドにあげておきたいですね。 127 |  今はInstagramとかforsquare等とTwitterを連携して、各サービスの情報を一旦twitterに集約してツイエバでEvernoteに保存するという使い方をしています。 128 |  Evernoteのノートをはてなブログに貼り付けることもできます。ブログのアイディアとかをメモ代わりにEvernoteに書いておくとそのままはてなブログに貼り付けられるので便利かもしれません。特にEvernoteはiPhone6plusの横向きに対応しているので移動中とかに書きやすいかなと思います。 129 |  下記は、その名の通りクソ記事をEvernoteから貼り付ける例です。 130 | 一昔前使いこなし記事がやたらに出て「そこまでして無理に使わなくても…」と思ったような記憶があるEvernote。最近はあまり話題に出なくなった気がしますが、何気に検索は非常に強力だと思っているので(写真の文字まで認識してくれる!)、ちょっとしたメモや、Twitterとの連携先として使い続けています。ちなみに記憶力が鳥並なので自分の住所もEvernoteみないとわかりません。 131 | 今世の中はスティーブ・ジョブズ人気ですね。ジョブズのプレゼンが凄いだの、ジョブズのようなイノベーションを起こせるような人を育てるべきだの。正直自分は、ジョブズは凄い人だとは思うのですが、たいして興味とか憧れはないです。それより、ジョブズと一緒にAppleを立ち上げたもう一人のスティーブ。スティーブ・ウォズニアック(通称ウォズ)の方が断然興味深いし、生き方に憧れます。 132 |  そんなスティーブ・ウォズニアックの自伝と言える本が以下です。エンジニアなら、この本を読めばウォズさんの凄さがわかると思います。少しトーマス=エジソンとニコラ=テスラの関係とも近いものがあるかもしれませんね。 133 | ジョブズタイプかウォズタイプか 134 |  両名共凄すぎて、正直凡人には到底たどり着けないですが、方向性としては両極端なのでエンジニアなら自分がどちらを目指すのか、どちらに向いているのかは少し考えてみてもよいかもしれません。誰から憎まれようとも、壮大なビジョンと抜群のプレゼンテーションで、必要なお金と人材をかき集め新しい製品をプロデュースして革命を起こすジョブズタイプか、内気で人前で話すことは苦手でも、こつこつ技術を少しづつ極めてとんでもない技術力を持ち、誰からも必要とされ、誰からも愛されるウォズタイプか。 135 |  ウォズはアップル退社後、何故かUSフェスティバルなるロックフェスを開催しています。この本読むまでウォズがこんなことしていたなんて、全然知りませんでした。 136 | 137 |  1200万ドル以上の損失出したり、ほんとはカントリーフェスにしたかったのに、若い人の意見聞いてたらいつの間にかロックフェスになってたり、フェス当日に子供が生まれてステージで観客から祝福されたり、ヴァン・ヘイレンに150万ドルギャラ払って、後から過去最高のギャラだったことを知ったり、冷戦当時のソ連と中継繋げたりとメチャクチャなエピソードw完全に頭のネジが外れているとしか思えないですw 138 |  以下の記事にもUSフェスティバルのエピソードがいくつか記載されています 139 | ウォズさんの自伝、最高に面白かったです。自分はやはりジョブズよりウォズの生き方に憧れますね。そしてウォズの「一人でやれ」というアドバイスがかなり印象的でした。新しいことをするなら、企業にいてはダメだ、そのアイディアは潰される。副業でやった方がよい。という意味合いです。Apple 1, Apple2の回路をほぼ一人で作り上げた男の言葉の重みは違いますし、ジョブズとは正反対のアプローチですね。 140 |  正直今、自分がやりたいことを会社でやるべきか個人でやるべきか色々迷っているところだったので、ウォズの言葉は結構ズシリときました。特にモノづくりにおける個人の力が増している今はあまり会社でやることに拘る意味はそれほどないのですよね。 141 |  子供が産まれました。母子ともに順調です。一時は帝王切開かという状況でしたが、妻が頑張ってくれました。 142 | 最近は医療も発展してきましたが、やはり新しい生命の誕生というのは一大事ですし、出産の時危うい状況になってしまったという話が身近にあったりしたので結構心配していました。とにかく無事に産まれてくれてよかったです。 143 | 144 |  というわけで、明日からこのブログは、突然子供の写真ばかり載せる親バカブログとなります。といきたいところですが、赤ちゃんといえども一個人ですのでほどほどにしておこうかなと思います。 145 |  あと、このブログですがそのうち育児休暇をいただくかもしれません。期間も開始時期も未定ですが、そのときはまた事前に連絡いたします(しないかも)。本当は仕事も育児休暇をとりたかったのですが、色々な事情であきらめました。一番はやはりお金でしょうか。 146 |  もし第2子誕生のときがあればですが、10年くらい育児休暇をとるべく、クラウドファンディングで大儲けしておきたいですね。 147 | 148 |  それでは明日から親バカブログになるかもしれませんが、それでもよければ引き続きこのブログをよろしくお願いいたします。 149 | 家族に関しては、ひょっとしたら増えたりするかも!こればかりはどうなるか分かりません。少なくとも減ることなく無事に過ごすことができれば良いなと思います。 150 |  仕事に関しては、ノーコメントで。ただ、周りの人たちや、関わる人が変わって自分の中では少し前向きな方向になっている気がします。2%くらいの確率で仕事関係のことがメディアに露出する可能性があるかもしれませんが、ここに書くことはないでしょう。 151 |  ブログに関しては、ここ4年は安定してきたので4年後も変わらず更新し続けているような気がします。昔はしょっちゅう閉鎖したり、下ネタを垂れ流して、ネットの繋がりというものを完璧に拒絶していて、インターネットの孤島と化していたこのブログが、今ではブログをきっかけに人とつながったり、新しいことに挑戦するきっかけになったりしているので自分でも驚きです。 152 |  こうやって、冷静に分析してみるとこの4年でブログで自分の世界が当社比25%くらいは広がったんじゃないかなと思います。人見知りするので、なかなか自分から世界を広げられない自分からするとこれは驚きの数字です。今後4年では、ブログを通じて色々な人に会って、自分の世界をあと5%くらい広げてもよいかなとか自分にしては凄く前向きなことを考えています。 153 |  はてなブログも4年後もあるとよいなと思います。はてなブログが無くなる可能性は、私がブログを辞める確率に比べるとずっと低いと思うので、それほど心配していませんが。あとは、はてなTシャツゲットとはてなオフィスへの訪問を実現するぞ!おー! 154 | 155 | 自分が初めてネットに情報を公開しだしたのは、もう20年前近くでそのとき自分は中学生でした。当時は、パソコンを持っている家も少数派で、ネットをしている中学生はクラスに1、2人というレベルだったような気がします。当時から色々な人に「パソコンは1人1台の時代がくるし、インターネットはインフラとして普及する」というようなことを言っていましたが、自分の周りでは誰も同調してくれるような人もいなくて寂しい思いをしたのを覚えています。もうちょっと早く生まれていればITバブルに乗れていたかもしれません。 156 |  当然今のようなHTMLを自動生成してくれるようなブログツールもない時代ですので、HTMLを自分で手打ちしてホームページを作っていました。今思うとよくあんな面倒くさいことやったものです。芸能人ですらほとんどホームページを持っていませんでした。記憶にあるのは、小室哲哉さんくらいでしょうか。たしか作っていたのはホリエモンだったはずです。 157 | 158 |  で、肝心なブログ(ホームページ)を始めたきっかけですが、正直全く思い出せません。というか自分はほぼ中学生のころの記憶がないのですよね。想像するに、自分は孤独だったのだと思います。中二病的な「周囲は自分のことを全く理解してくれない、きっと世界中のどこかに自分のことを完全に理解してくれる同士が存在するはず」という妄想に取り憑かれていたのでしょう。 159 |  そしてときは流れ、大学生になると一時的なホームページブームが来て、周りの友人が次々とホームページを開設しては、閉鎖していきました。自分がホームページにkaraageという名前をつけだしたのはこのころです。ひねくれていた自分は他の人と同じじゃ嫌だとばかりにLinux入れた古いPCに自宅サーバ立てて、2ch風の掲示板システムを立ち上げて、そこに自分でスレッドを立てて日記を書くというかなりアバンギャルドなスタイルをとっていました。1ヶ月に1度は閉鎖していました。多分病んでいたのでしょう。そして、はてなさんに移行しました。こんにちは、はてなさん。 160 | 久しぶりに長文を書きました。最近でこそ写真ペタペタ貼って終わりですが、昔はこんなことをよく書いていた気がします。強い想いとか、悲しい想いとか。日々の出来事とか。もうなかなか書けないですね。少し悲しい気もしますが、ネットも20年で変わりオタクの遊び場から立派なインフラになりました。インフラになると、道路に信号機がつくように、色々な窮屈なルールや、免許をとれ(実名公開しろ)というわけのわからない風潮が出たり、リアルと強く結び付いて、適当なことや過激なことを言うだけで多くの人に責められるようなことも多くなってきました。 161 |  結局は、私は未だにネットでは自由でいたいのだと思います。誰にも縛られず、何をしてもよい、そんな20年前のネットで感じた高揚感を未だに忘れられず、囚われているだけなのかもしれません。 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /schema.sql: -------------------------------------------------------------------------------- 1 | drop table if exists chain_freqs; 2 | create table chain_freqs ( 3 | id integer primary key autoincrement not null, 4 | prefix1 text not null, 5 | prefix2 text not null, 6 | suffix text not null, 7 | freq integer not null 8 | ); 9 | --------------------------------------------------------------------------------