ブログトップ 記事一覧 ログイン 無料ブログ開設

それはそれ。これはこれ。 このページをアンテナに追加 RSSフィード

2003 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2004 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2005 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 03 | 04 | 05 | 06 | 07 | 09 | 10 | 11 | 12 |
2012 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 11 | 12 |
2013 | 01 | 02 | 04 | 05 | 07 | 08 | 10 | 11 | 12 |
2014 | 02 | 03 | 07 | 08 | 09 | 10 | 11 | 12 |
2015 | 01 | 02 | 03 | 05 | 06 | 07 | 11 |
2016 | 07 |
2017 | 01 | 03 | 06 | 07 | 11 |
2018 | 05 | 07 |

2016-07-16(土)

[][][] MS Exchange/OutlookカレンダーGoogle Calendarの同期 (続編)  MS Exchange/Outlook のカレンダーとGoogle Calendarの同期 (続編) - それはそれ。これはこれ。 を含むブックマーク  MS Exchange/Outlook のカレンダーとGoogle Calendarの同期 (続編) - それはそれ。これはこれ。 のブックマークコメント

id:otn:20150901MS Exchange/OutlookカレンダーGoogle Calendarの同期」のその後。

google-api-client が 0.9 になってそのままでは動かなくなった。0.8のまま使っていたのだが、認証がおかしくなった(毎回認証しないとタイムスタンプがおかしいというエラーになる)ので、0.9 対応修正。いろいろあった。

認証については、googleauth の README.md を参考に。しかし、以前のように「ブラウザ自動的に開いて、認証するとアプリが続行」という風には出来ず、自分ブラウザを開いて、認証したあと、そこに表示された文字列入力しないといけない。これは不便だがしょうが無い。

あともAPIが色々変わっており、ソースを追ったり、gemデバッグプリントを入れたりしてなんとかなった。手こずったのがリマインダ。リマインダメソッド指定キーが、"method" から :reminder_method に変わっている!


#! ruby
CAL_ID = "xxxxxxxxxxxxxxxxx@gmail.com" #GOOGLEアカウントのメールアドレス
DAYS = 30
AUTH_FILE = "authfile.yaml"
SECRET_FILE = "client_secret.json"

ENV["http_proxy"]  = "http://user:pass@proxyserver:port" # proxyの設定
ENV["https_proxy"] = "http://user:pass@proxyserver:port" # proxyの設定

Dir.chdir File.dirname($0)

require "googleauth"
require "googleauth/stores/file_token_store"
require "google/apis/calendar_v3"
require "google/api_client/client_secrets"
require "win32ole"

class Event
  def to_s # デバッグ用に書いたもの
    [@start.strftime("%Y-%m-%d %H:%M"),
    @end.strftime("%Y-%m-%d %H:%M"),
    @allday.to_s[0],
    @reminder.to_s,
    @title, @body.gsub(/\s/," "), @location].join(",")
  end

  def ==(other)
    @start    == other.instance_variable_get(:@start)  and
    @end      == other.instance_variable_get(:@end)    and
    @allday   == other.instance_variable_get(:@allday) and
    reminder_eql?(@start, @reminder, other.instance_variable_get(:@reminder)) and
    @title    == other.instance_variable_get(:@title)  and
    @body     == other.instance_variable_get(:@body)   and
    @location == other.instance_variable_get(:@location)
  end

  def delete
    Gcal.delete(@id)
  end

  def add
    event = {
      summary:      @title,
      description:  @body,
      start:        start,
      end:          ende,
      location:     @location,
      reminders:    reminder,
      source:       {title: "Exchange", url: "http://localhost"}
    }
    Gcal.add(event)
  end

  def is_holiday
    @allday and @location=="日本"
  end

  private
  def start
    if @allday
      {date: @start.strftime("%Y-%m-%d")}
    else
      {date_time: @start.iso8601}
    end
  end
  def ende
    if @allday
      {date:  @end.strftime("%Y-%m-%d")}
    else
      {date_time:  @end.iso8601}
    end
  end
  def reminder
    if @reminder
      {use_default: false, overrides: [{reminder_method: :popup, minutes: @reminder}]}
    else
      {use_default: false}
    end
  end
  def reminder_eql?(start, x, y)
    @@now ||= Time.now
    ( x == y ) or
    # リマインダー時刻を過ぎている場合はリマインダーの有無を無視
    ( x and not y and start - x < @@now ) or
    ( y and not x and start - y < @@now )
  end
end

# Googleカレンダー
class Gcal < Event
  def self.get_auth(calendar_id, auth_filename, secret_filename)
    @@cal_id = calendar_id

    client_id   = Google::Auth::ClientId.from_file(SECRET_FILE)
    scope       = "https://www.googleapis.com/auth/calendar"
    token_store = Google::Auth::Stores::FileTokenStore.new(file: AUTH_FILE)
    authorizer  = Google::Auth::UserAuthorizer.new(client_id, scope, token_store)

    credentials = authorizer.get_credentials(@@cal_id)
    if credentials.nil?
      url = authorizer.get_authorization_url(base_url: "urn:ietf:wg:oauth:2.0:oob")
	  system(%Q|CMD /c start "" "#{url}"|)
      print "Enter the resulting code: "
      code = gets
      credentials = authorizer.get_and_store_credentials_from_code(
                    user_id: @@cal_id, code: code, base_url: "urn:ietf:wg:oauth:2.0:oob")
    end

	@@client = Google::Apis::CalendarV3::CalendarService.new
	@@client.authorization = credentials
  end

  def self.delete(id)
    @@client.delete_event(@@cal_id, id)
  end

  def self.add(event)
    @@client.insert_event(@@cal_id, Google::Apis::CalendarV3::Event.new(event))
  end

  def self.is_exchange(item)
    item.source and item.source.title == "Exchange"
  end

  def self.list(from, to)
    @@client.list_events(@@cal_id,
      order_by:  "startTime",
      time_min:  from.iso8601,
      time_max:  to.iso8601,
      single_events:  "True"
    ).items
  end

  def initialize(event)
    if event.start.date
      @start  = Time.parse(event.start.date)
      @end    = Time.parse(event.end.date)
      @allday = true
    else
      @start  = event.start.date_time.to_time
      @end    = event.end.date_time.to_time
      @allday = false
    end
    if event.reminders.use_default
      @reminder = 10 # 正確にはそのユーザーのデフォルト値を取得する必要がある
    elsif event.reminders.overrides
      @reminder = event.reminders.overrides[0].minutes
    else
      @reminder = nil
    end
    @title = event.summary || ""
    @body  = event.description || ""
    @location = event.location || ""
    @id = event.id
  end
end

# Exchangeカレンダー
class Ecal < Event
  FolderCalendar = 9
  def self.list(from, to)
    @@calendar ||= WIN32OLE.new("Outlook.Application")
      .GetNamespace("MAPI").GetDefaultFolder(FolderCalendar)

    items = @@calendar.Items
    items.Sort "[Start]"
    items.IncludeRecurrences = true
    item = items.Find(%Q/[Start] < "#{to.strftime("%Y-%m-%d %H:%M")}" AND [End] >= "#{from.strftime("%Y-%m-%d %H:%M")}"/)

    Enumerator.new do |y|
      while item 
        y << item
        item = items.FindNext
      end
    end
  end

  def initialize(event)
    @start = event.Start
    @end   = event.End
    @allday = event.AllDayEvent
    @reminder = event.ReminderSet ? event.ReminderMinutesBeforeStart : nil
    @title  = event.Subject.encode(Encoding::UTF_8)
    @body   = event.Body.encode(Encoding::UTF_8)
    @location = event.Location.encode(Encoding::UTF_8)
  end
end

# 期間設定
today = Time.now
time_min = today - 3600*24*DAYS
time_max = today + 3600*24*DAYS

# Exchangeイベント取得
e_events = Ecal.list(time_min, time_max).map{|ev| Ecal.new(ev)}.reject(&:is_holiday)

# Google認証
Gcal.get_auth(CAL_ID, AUTH_FILE, SECRET_FILE)

# Googleイベント取得
g_events = Gcal.list(time_min, time_max)
  .select{|ev| Gcal.is_exchange(ev)}.map{|ev| Gcal.new(ev)}

# イベント削除
g_events.reject{|ev| e_events.include?(ev)}.each{|ev| ev.delete}

# イベント追加
e_events.reject{|ev| g_events.include?(ev)}.each{|ev| ev.add}

2014-09-01(月)

[][][] MS Exchange/OutlookカレンダーGoogle Calendarの同期 その4  MS Exchange/Outlook のカレンダーとGoogle Calendarの同期 その4 - それはそれ。これはこれ。 を含むブックマーク  MS Exchange/Outlook のカレンダーとGoogle Calendarの同期 その4 - それはそれ。これはこれ。 のブックマークコメント

仕様再掲。

3つめの仕様のために、Google Calendarに登録するときに、Exchangeからの反映であることをマークしないといけない。

使えそうな属性をみて、sourceという属性を使うことにする。ウェブページを元にイベントを登録するときにそのページのURLタイトルを書くようだ。

2014-09-19修正

コメントで、Googleのdescriptionは長さ上限*1があると教えていただいたので、Ecal#initializeで8192文字までに制限


全体のプログラム

#! ruby
CAL_ID = "xxxxxxxxxxxxxxxxx@gmail.com" #GOOGLEアカウントのメールアドレス
AUTH_FILE = "authfile.json"
SECRET_FILE = "client_secret.json"

ENV["http_proxy"] = "http://user:pass@proxyserver:port" # proxyの設定

Dir.chdir File.dirname($0)

require "google/api_client"
require "google/api_client/client_secrets"
require "google/api_client/auth/installed_app"
require "google/api_client/auth/file_storage"
require "win32ole"

class Event
  def to_s # デバッグ用に書いたもの
    [@start.strftime("%Y-%m-%d %H:%M"),
    @end.strftime("%Y-%m-%d %H:%M"),
    @allday.to_s[0],
    @reminder.to_s,
    @title, @body.gsub(/\s/," "), @location].join(",")
  end

  def ==(other)
    @start    == other.instance_variable_get(:@start)  and
    @end      == other.instance_variable_get(:@end)    and
    @allday   == other.instance_variable_get(:@allday) and
    reminder_eql?(@start, @reminder, other.instance_variable_get(:@reminder)) and
    @title    == other.instance_variable_get(:@title)  and
    @body     == other.instance_variable_get(:@body)   and
    @location == other.instance_variable_get(:@location)
  end

  def delete
    Gcal.execute(:delete,{"eventId" => @id})
  end

  def add
    event = {
      "summary" => @title,
      "description" => @body,
      "start" => start,
      "end" => ende,
      "location" => @location,
      "reminders" => reminder,
      "source" => {"title" => "Exchange", "url" => "http://localhost"}
    }
    Gcal.execute(:insert,
      {},
      :body => JSON.dump(event),
      :headers => {"Content-Type" => "application/json"}
    )
  end

  private
  def start
    if @allday
      {"date" => @start.strftime("%Y-%m-%d")}
    else
      {"dateTime" => @start.iso8601}
    end
  end
  def ende
    if @allday
      {"date" => @end.strftime("%Y-%m-%d")}
    else
      {"dateTime" => @end.iso8601}
    end
  end
  def reminder
    if @reminder
      {"useDefault" => false, "overrides"=>[{"method"=>"popup","minutes"=>@reminder}]}
    else
      {"useDefault" => false}
    end
  end
  def reminder_eql?(start, x, y)
    @@now ||= Time.now
    ( x == y ) or
    ( x and not y and start - x < @@now ) or # リマインダー時刻を過ぎている場合はリマインダーの有無を無視
    ( y and not x and start - y < @@now )
  end
end

# Googleカレンダー
class Gcal < Event
  def self.get_auth(calendar_id, auth_filename, secret_filename)
    @@cal_id = calendar_id
    @@client = Google::APIClient.new(:application_name => "")
    
    authfile = Google::APIClient::FileStorage.new(auth_filename)
    if authfile.authorization
      @@client.authorization = authfile.authorization
    else
      client_secrets = Google::APIClient::ClientSecrets.load(secret_filename)
      flow = Google::APIClient::InstalledAppFlow.new(
        :client_id => client_secrets.client_id,
        :client_secret => client_secrets.client_secret,
        :scope => ["https://www.googleapis.com/auth/calendar"]
      )
      @@client.authorization = flow.authorize(authfile)
    end
    @@service = @@client.discovered_api("calendar", "v3")
  end

  def self.execute(cmd, params, opt={})
    x = @@client.execute({:api_method => @@service.events.send(cmd),
      :parameters => params.merge("calendarId" => @@cal_id)}
      .merge(opt))
    if x.error?
      raise "#{x.status} #{x.error_message}"
    end
    x
  end

  def self.is_exchange(item)
    item.source and item.source.title == "Exchange"
  end

  def self.list(from, to)
    execute(:list,
         {"orderBy" => "startTime",
          "timeMin" => from.iso8601,
          "timeMax" => to.iso8601,
          "singleEvents" => "True"}
    ).data.items
  end

  def initialize(event)
    if event.start.date
      @start  = Time.parse(event.start.date)
      @end    = Time.parse(event.end.date)
      @allday = true
    else
      @start  = event.start.date_time
      @end    = event.end.date_time
      @allday = false
    end
    if event.reminders.use_default
      @reminder = 10 # 正確にはそのユーザーのデフォルト値を取得する必要がある
    elsif event.reminders.overrides[0]
      @reminder = event.reminders.overrides[0].minutes
    else
      @reminder = nil
    end
    @title = event.summary || ""
    @body  = event.description || ""
    @location = event.location || ""
    @id = event.id
  end
end

# Exchangeカレンダー
class Ecal < Event
  FolderCalendar = 9
  def self.list(from, to)
    @@calendar ||= WIN32OLE.new("Outlook.Application")
      .GetNamespace("MAPI").GetDefaultFolder(FolderCalendar)

    items = @@calendar.Items
    items.Sort "[Start]"
    items.IncludeRecurrences = true
    item = items.Find(%Q/[Start] < "#{to.strftime("%Y-%m-%d %H:%M")}" AND [End] >= "#{from.strftime("%Y-%m-%d %H:%M")}"/)

    Enumerator.new do |y|
      while item 
        y << item
        item = items.FindNext
      end
    end
  end

  def initialize(event)
    @start = event.Start
    @end   = event.End
    @allday = event.AllDayEvent
    @reminder = event.ReminderSet ? event.ReminderMinutesBeforeStart : nil
    @title  = event.Subject.encode(Encoding::UTF_8)
    @body   = event.Body.encode(Encoding::UTF_8)[0,8192]
    @location = event.Location.encode(Encoding::UTF_8)
  end
end

# 期間設定
today = Time.now
time_min = today - 3600*24*30
time_max = today + 3600*24*30

# Exchangeイベント取得
e_events = Ecal.list(time_min, time_max).map{|ev| Ecal.new(ev)}

# Google認証
Gcal.get_auth(CAL_ID, AUTH_FILE, SECRET_FILE)

# Googleイベント取得
g_events = Gcal.list(time_min, time_max)
  .select{|ev| Gcal.is_exchange(ev)}.map{|ev| Gcal.new(ev)}

# イベント削除
g_events.reject{|ev| e_events.include?(ev)}.map{|ev| ev.delete}

# イベント追加
e_events.reject{|ev| g_events.include?(ev)}.map{|ev| ev.add}

ハッシュキーシンボルでも良い場所もあるようだが、どうせ最後文字列になって送られるので文字列のままにしておく。

*1:改行を1文字として8192文字……バイトではない

kk 2014/09/17 22:09 ソース公開ありがとうございます。まったく同じ理由で困ってました。ありがたく使わせていただきます。
1点だけ。Outlook の Body のサイズは制限がないのですが、Google カレンダー の description は 8K byte (?) の制限があり、8K byte を超える部分は切り捨てられるようです。outlook 側のBodyが 8K byte 以上だった場合、比較が = にならずに、毎回 delete/add をしてしまいます。メールをそのまま、スケジュールとして登録することが多いので、たまにBodyが 8K を超えてしまいます。
とりあえずの quick hack で "active_support/core_ext/string/filters" を require して、181行目を
@body = event.Body.encode(Encoding::UTF_8)
==>
@body = event.Body.truncate(4096).encode(Encoding::UTF_8)
に修正して使っています。(Body/Description サイズを 4K に制限)
ご報告まで。

otnotn 2014/09/19 22:43 コメントありがとうございます。長い文章を入力してみましたが、8192文字(≠バイト、改行は1文字とカウント)のようですね。
まず大丈夫だと思いますが、本文にはメールを貼り付けることもあるので、越えることがないとも限りませんね。
修正しておきます。

2014-08-30(土)

[][][] MS Exchange/OutlookカレンダーGoogle Calendarの同期 その3  MS Exchange/Outlook のカレンダーとGoogle Calendarの同期 その3 - それはそれ。これはこれ。 を含むブックマーク  MS Exchange/Outlook のカレンダーとGoogle Calendarの同期 その3 - それはそれ。これはこれ。 のブックマークコメント

id:otn:20140829 の続き。


どういうときに、ExchangeイベントGoogle Calendarイベントを等しいと判断するか。

考慮が必要なのは3点。

タイトル、内容、場所など文字列の文字コードがCP932か、utf-8かの違い。これはutf-8に揃えることにする。

また、内容がないときはExchangeは空文字列で、Google Calendarではnilで、これは空文字列に揃える。

Exchangeだと0時から翌日0時の予定で、全日フラグ(AllDayEvent)がtrueになっている。

Google Calendarだと、日付だけが文字列でセットされている。これはExchange式に揃える。

  • リマインダー

Exchangeは、リマインダー有無のフラグ(ReminderSet)と、分数がセットされている。また、リマインダー時刻が過ぎると、分数はそのままでフラグがfalseになる。

Google Calendarは、複数のリマインダーがセットできるようで配列になっている。また、リマインダーのデフォルト値があり、デフォルトかどうかのフラグ(use_default)がある。リマインダーがないときは、デフォルトフラグがfalseで配列が空。リマインダー時刻が過ぎても値は変化しない。


class Event
  def ==(other)
    @start    == other.instance_variable_get(:@start)  and
    @end      == other.instance_variable_get(:@end)    and
    @allday   == other.instance_variable_get(:@allday) and
    reminder_eql?(@start, @reminder, other.instance_variable_get(:@reminder)) and
    @title    == other.instance_variable_get(:@title)  and
    @body     == other.instance_variable_get(:@body)   and
    @location == other.instance_variable_get(:@location)
  end
  private
  def reminder_eql?(start, x, y)
    @@now ||= Time.now
    ( x == y ) or
    ( x and not y and start - x < @@now ) or # リマインダー時刻を過ぎている場合はリマインダーの有無を無視
    ( y and not x and start - y < @@now )
  end
end

class Gcal < Event
  def initialize(event)
    if event.start.date # 全日イベント
      @start  = Time.parse(event.start.date)
      @end    = Time.parse(event.end.date)
      @allday = true
    else
      @start  = event.start.date_time
      @end    = event.end.date_time
      @allday = false
    end
    if event.reminders.use_default
      @reminder = 10 # 正確にはそのユーザーのデフォルト値を取得する必要がある
    elsif event.reminders.overrides[0]
      @reminder = event.reminders.overrides[0].minutes
    else
      @reminder = nil
    end
    @title = event.summary || ""
    @body  = event.description || ""
    @location = event.location || ""
    @id = event.id
  end
end

class Ecal < Evant
  def initialize(event)
    @start = event.Start
    @end   = event.End
    @allday = event.AllDayEvent
    @reminder = event.ReminderSet ? event.ReminderMinutesBeforeStart : nil
    @title  = event.Subject.encode(Encoding::UTF_8)
    @body   = event.Body.encode(Encoding::UTF_8)
    @location = event.Location.encode(Encoding::UTF_8)
  end
end

2014-08-29(金)

[][][] MS Exchange/OutlookカレンダーGoogle Calendarの同期 その2  MS Exchange/Outlook のカレンダーとGoogle Calendarの同期 その2 - それはそれ。これはこれ。 を含むブックマーク  MS Exchange/Outlook のカレンダーとGoogle Calendarの同期 その2 - それはそれ。これはこれ。 のブックマークコメント

id:otn:20140827 の続き。


Exchangeからのデータ取得は以前調べてVBScriptで書いたものRubyで書き直す。

元のVBScriptを書くときに参考にしたサイトがちょっと見つからない。


結果の取得は、FindNextしながらwhileループしていたので、Enumeratorに変換する。

class Ecal
  FolderCalendar = 9
  def self.list(from, to)
    @@calendar ||= WIN32OLE.new("Outlook.Application")
      .GetNamespace("MAPI").GetDefaultFolder(FolderCalendar)

    items = @@calendar.Items
    items.Sort "[Start]"
    items.IncludeRecurrences = true
    item = items.Find(%Q/[Start] < "#{to.strftime("%Y-%m-%d %H:%M")}" AND [End] >= "#{from.strftime("%Y-%m-%d %H:%M")}"/)

    Enumerator.new do |y|
      while item 
        y << item
        item = items.FindNext
      end
    end
  end
end

now = Time.now
time_min = now - 3600*24*7 #前後一週間
time_max = now + 3600*24*7
Ecal.list(time_min, time_max).each do |event|
  puts [event.Start, event.End, event.Subject].join(",")
end

strftimeの書式を調べると、"%Y-%m-%d %H:%M" は "%F %R" で良いが、覚えられないのでそのまま。

2014-08-27(水)

[][][] MS Exchange/OutlookカレンダーGoogle Calendarの同期 その1  MS Exchange/Outlook のカレンダーとGoogle Calendarの同期 その1 - それはそれ。これはこれ。 を含むブックマーク  MS Exchange/Outlook のカレンダーとGoogle Calendarの同期 その1 - それはそれ。これはこれ。 のブックマークコメント

Google Calendar Syncのサービスが2014-08-01に停止された。今まで使っていたので、困ってしまい、代替を調べたが認証proxy越えがうまくいかないので、自分で作ることにした。


仕様としては、

ロジックとしては、これで良いはず。

  1. Exchangeの前後30日間のイベントを取得→リストE
  2. Google CalendarからExchange起因の前後30日間のイベントを取得→リストG
  3. リストGにあってリストEにないものを、Google Calendarから削除
  4. リストEにあってリストGにないものを、Google Calendarに追加

Exchangeイベント取得は前にやったことがあるので、まずはGoogle CalendarAPIの確認。

ググって、下記ページを参考にした。

http://qiita.com/iron-breaker/items/2440c4ab41a482b1b096

http://qiita.com/mechamogera/items/bf2ed20e332dc31d2352


プロジェクト作成

目的のGoogleアカウントでログインしていることを確認した上で、管理コンソールページ https://cloud.google.com/console にアクセス*1

[Create Project]ボタンを押す。

PROJECT NAME と PROJECT ID を適当に入力する。

I have read and agree to all Terms of Service for the Google Cloud Platform products.

にチェックを入れて、[Create]ボタンをクリック。

ここで、PROJECT IDGoogleシステム全体でユニークでないと、サーバーエラーになる*2

The Project ID specified is not available. Please select another.

These identifiers must be unique.

って、入力時に言ってくれよ!どうせ後で使わないようなので、おすすめに任せるのが吉。

PROJECT NAMEは、システム全体でユニークである必要はない。アカウント毎の管理。


APIの設定

プロジェクトが出来たら、左サイドバーの、[API&auth]の[APIs]をクリック。

Calendar API の Status が[OFF]になっているので、クリック。

Terms of Serviceの確認ダイアログが出るので、チェックして[Accept]をクリック。

1日に200,000リクエストまで使えるらしい。


クライアントIDの取得

サイドバーの[APIs]の下の[Credentials]をクリック。

"Compute Engine and App Engine" 用のClient IDが出来ているが、これは関係ないので、

OAuthの下の[Create new Client ID]をクリック。

APPLICATION TYPEは、"Installed application"を選択し、INSTALLED APPLICATION TYPEは、"Other"を選択。

[Create Client ID]をクリック。

すると、"Client ID for native application"のClient IDが出来ている。

IDをコピペする必要はなくて、[Download JSON]をクリックして、ダウンロードしておく。

ファイル名は、"client_secret.json" とかに縮めておく。

これで前準備は完了。


疎通確認

確認のため、Googleカレンダーに何か登録しておく。

google-api-clientgemをインストール。

C> gem install google-api-client

イベントリストを取得して表示するだけのサンプルプログラム*3

require "google/api_client"
require "google/api_client/client_secrets"
require "google/api_client/auth/installed_app"
require "google/api_client/auth/file_storage"

ENV["http_proxy"] = "http://user:pass@proxyserver:port" # proxyの設定
client = Google::APIClient.new(application_name: "")

authfile = Google::APIClient::FileStorage.new("authfile.json") #このファイルはなくて良い。作られる
if authfile.authorization
  client.authorization = authfile.authorization
else
  client_secrets = Google::APIClient::ClientSecrets.load("client_secret.json") #ダウンロードしたJSONファイル

  flow = Google::APIClient::InstalledAppFlow.new(
    client_id: client_secrets.client_id,
    client_secret: client_secrets.client_secret,
    scope: ["https://www.googleapis.com/auth/calendar"]
  )
  client.authorization = flow.authorize(authfile)
end

service = client.discovered_api(:calendar, :v3)

now = Time.now
time_min = now - 3600*24*7 #前後一週間
time_max = now + 3600*24*7
params = {calendarId:   "xxxxxxxxxxxxxxxxx@gmail.com", #GOOGLEアカウントのメールアドレス
          orderBy:      "startTime",
          timeMax:      time_max.iso8601,
          timeMin:      time_min.iso8601,
          singleEvents: true}

result = client.execute(api_method: service.events.list,
                        parameters: params)
if result.error?
  puts "#{result.status} #{result.error_message}"
else
  result.data.items.each do |event|
    puts [event.start.date_time||event.start.date,
          event.end.date_time||event.end.date, event.summary].join(",")
  end
end

これを実行すると、ブラウザOAuth認証画面が出る。

「このアプリが次の許可をリクエストしています:」

と出るので、[承認]をクリック。

さっき登録したイベントの日時とタイトルが出ればOK。

Googleアカウントがまちがっていると、404 Not Found が出る。


一度OAuthの承認をしておくと、"authfile.json" に情報が保存され、以降はそれが使われる。

*1:左側の Account settings で Language を日本語にすることも出来るが、各種解説ページが英語ベースだったりするので、そのままにしておく

*2:Create Projectボタンが再び出なければ、左サイドバーの [Projects]というリンクをクリックする。あとは、[Create Project]ボタンからやり直し

*3google-api-client は faraday というライブラリ経由でウェブアクセスしているが、faraday は https 接続でも http_proxy を使うようだ

2014-02-22(土)

[][] Yahoo検索結果から広告を削除するGreasemonkey  Yahoo検索結果から広告を削除するGreasemonkey - それはそれ。これはこれ。 を含むブックマーク  Yahoo検索結果から広告を削除するGreasemonkey - それはそれ。これはこれ。 のブックマークコメント

昨今の話題で、Yahoo検索結果の広告部分がマルウェアに汚染されているようだ。

普段はGoogle検索を使ってるけど、今後絶対にYahoo検索を使わないとも言い切れず、そのときはきっと汚染を忘れていそうなので、Greasemonkeyを書いておく。

// ==UserScript==
// @name        Yahoo検索結果の広告削除
// @namespace   http://d.hatena.ne.jp/otn/
// @include     http://search.yahoo.co.jp/search?*
// @version     1
// @grant       none
// ==/UserScript==
var x;
x=document.getElementById("So1");
if(x)x.parentNode.removeChild(x);
x=document.getElementById("So2");
if(x)x.parentNode.removeChild(x);

二回くらいなので、ベタで書いた方がシンプルだと思うけど、繰り返しで書くとこうか。

["So1","So2"].forEach(function(id){
	var x=document.getElementById(id);
	if(x)x.parentNode.removeChild(x);
});

2012-02-27(月)

[]Facebookで夢のような体験 Facebookで夢のような体験 - それはそれ。これはこれ。 を含むブックマーク Facebookで夢のような体験 - それはそれ。これはこれ。 のブックマークコメント

Facebookから時々メールが来る。

最近の友達に関する情報をいくつかご紹介します。

○○ ○○さん、△ △△さん、□□ □□さん、他友達4人がFacebookに近況や写真を投稿しました。

この、○さんは大学時代の友人、△さんは会社の元同僚、□さんは高校の同級生。

夢の中で、とうてい知り合いのはずの無い学生時代の友人と、会社の同僚が一緒にいたりすることがあるけど、それを彷彿とさせる。

2010-03-23(火)

[] Twitterでフォローしている人がフォローしている人  Twitterでフォローしている人がフォローしている人 - それはそれ。これはこれ。 を含むブックマーク  Twitterでフォローしている人がフォローしている人 - それはそれ。これはこれ。 のブックマークコメント

Twitterで自分がフォローしている人がフォローしている人を調べるスクリプトを書いてみた。自分がフォローしている人の複数人がフォローしている人であれば、追加でフォローする候補になるのではないかということだ。


現在フォローしている人は117人。60分で150回というAPI実行回数制限に引っかかったので、制限の緩い(60分で350回((http://watcher.moe-nifty.com/memo/docs/twitterAPI.txt)))という http://api.twitter.comOAuthの登録をして使ってみた。OAuthの登録は id:shibason:20090802:1249204953 を参考にした。APIを何回使ったか数えておけば良かったが数え忘れた。


フォローが重なった人がどれだけいるかという結果はこんな感じ。

○人の人がフォローしている人が○人いました例えばこんな人
201私自身
172鳩山由紀夫さん、孫正義さん
141勝間和代さん
124堀江貴文さん、毎日新聞
113三木谷浩史さん
104古川享さん、朝日新聞
96津田大介さん、広瀬香美さん
87伊集院光さん、野口聡一さん
710佐々木俊尚さん、松尾貴史さん、まつもとゆきひろさん
630以下略
543
4130
3393
22221
121699

って、やはりフォローしている人全員を対象にすると下位の方は収拾が付かない事態に。鳩山首相がフォロー返しした相手とか興味ないし。


というわけで、リストを指定して、そのリストに含まれた人がフォローしている人を調べるように改造だ。

2009-12-31(木)

[] Twitterで自分or他人の過去記事をまとめて簡単に読む方法  Twitterで自分or他人の過去記事をまとめて簡単に読む方法 - それはそれ。これはこれ。 を含むブックマーク  Twitterで自分or他人の過去記事をまとめて簡単に読む方法 - それはそれ。これはこれ。 のブックマークコメント

Twitter API*1ブラウザでも使える。

http://twitter.com/statuses/user_timeline.rss?id=だれそれ&count=200

とか。countの最大値は200で、それ以前はpageを指定する。過去201-400件なら、

http://twitter.com/statuses/user_timeline.rss?id=だれそれ&count=200&page=2

なお、APIは60分間で100回までしか使えない。同一IPからかな?

*1:日本語訳してくださっている方がいる http://watcher.moe-nifty.com/memo/2007/04/twitter_api.html

2009-11-26(木)

[][] オンラインストレージソフトのメモリ使用量比較  オンラインストレージソフトのメモリ使用量比較 - それはそれ。これはこれ。 を含むブックマーク  オンラインストレージソフトのメモリ使用量比較 - それはそれ。これはこれ。 のブックマークコメント

オンラインストレージ(というのが一般名称??)のソフトを現在三種類インストールしている。メモリ使用量は以下の通り。

名前仮想サイト
Dropbox117M52Mhttps://www.dropbox.com/
SugarSync172M84Mhttps://www.sugarsync.com/referral?rf=cipm9g5v7tfks *1
zumodrive773M37Mhttps://www.zumodrive.com/

3つ同時に動かすと、リアルで173MB、バーチャルだとなんと約1GBも必要!!特に、zumodriveのバーチャルは何???

zumodriveを使う人はページファイルのサイズを見直さないといけないかも。

それぞれ性格が違うので、何を目的に使うのかを考え、どれをメインにするか絞り込んでいく必要有り。

・PCデータのバックアップをネット上に行いたい

・複数PCでファイルの同期をしたい

・iPhoneで外出先からPC上のデータを使いたい

・・・・などなど。私は最後ものかな。


性格の似たDropboxとSugarSyncでは、SugarSyncの方が機能が上のようだが、何かアップロード反映が遅い*2。Dropboxだとすぐアップロードされるし、iPhoneアプリの使い勝手もこっちが上。

あと、SugarSyncはときどきCPUをガンと使うようである。これも不審だなあ。やっぱりDropboxがいいかな。

*1:このURLからアカウントを取ると250MB増量

*2:調べると15分ごとに同期らしい

2009-11-19(木)

[][] PASMO履歴照会ページに支払金額を追加するGreasemonkeyスクリプト  PASMO履歴照会ページに支払金額を追加するGreasemonkeyスクリプト - それはそれ。これはこれ。 を含むブックマーク  PASMO履歴照会ページに支払金額を追加するGreasemonkeyスクリプト - それはそれ。これはこれ。 のブックマークコメント

PASMOの前日ベースの使用履歴が、https://www.pasmo-mypage.jp/loginwebform.aspx で見られるが、仕様を決めた人が間抜けなので、利用した後の残額しか表示されない。運賃がいくらだったかとか、いくらの買い物をしたかを知るためには引き算が必要。交通費申請をするときなど不便なので、支払額がわかるようにしてみた。

日本語を使っているので、文字コードはUTF-8でファイルを作成する必要がある。

tdを挿入しながら処理することになるので、前からやるとどんどんずれていって添え字がよくわからなくなるので後から処理している。


// ==UserScript==
// @name           PASMO
// @namespace      http://d.hatena.ne.jp/otn/
// @description    Calculate each expenditure
// @include        https://www.pasmo-mypage.jp/CardStatusWebForm.aspx
// ==/UserScript==

var tbls=document.getElementsByTagName("table");
var ths=tbls[tbls.length-1].getElementsByTagName("th");
var tds=tbls[tbls.length-1].getElementsByTagName("td");

var th=document.createElement("th");
th.width="45";
th.innerHTML="<font color='#ffffff'>支払額</font>"; // 文字コードはUTF-8
ths[0].parentNode.appendChild(th);

function col7(td){
  td.setAttribute("colspan","7");
}
function val(td){
  return td.textContent.replace(/\**/,"");
}
function addexp(here,exp){
  var td=document.createElement("td");
  td.align="right";
  td.textContent=exp;
  here.parentNode.appendChild(td);
}

col7(tds[tds.length-1]);
addexp(tds[tds.length-2],"***");
for(var i=tds.length-10; i>0; i-=7){
  col7(tds[i+1]);
  addexp(tds[i],val(tds[i+7])-val(tds[i]));
}
col7(tds[1]);
col7(tds[0]);

2009-09-20(日)

[]ブラウザとタイムゾーン ブラウザとタイムゾーン - それはそれ。これはこれ。 を含むブックマーク ブラウザとタイムゾーン - それはそれ。これはこれ。 のブックマークコメント

Webブラウザからサーバーに、言語情報は送るのが普通だが、タイムゾーン情報も送るようにするといいのでは?


全世界向け*1の多くのウェブサービスでは、ユーザの属性としてタイムゾーン情報を保持していると思うが、タイムゾーンをまたがって移動したようなケースだと、ブラウザから送ることにしておけば、一回の設定変更で、複数サービスの表示時刻が変えられる。


うーん、今更遅いか。

*1:というか日本ローカル以外か

2009-09-14(月)

[]blogの更新をTwitterに blogの更新をTwitterに - それはそれ。これはこれ。 を含むブックマーク blogの更新をTwitterに - それはそれ。これはこれ。 のブックマークコメント

FriendFeed経由でのRSSを使った通知が何故か動かなくなったので、TwitbackrへのPingを使った通知を試してみる。


はてなダイアリーに、Ping先を固定で入力しておく設定が無いみたいで不便。Greasemonkeyで設定するか。

2009-07-20(月)

[]「あとで読む」方法いろいろありすぎて。。。 「あとで読む」方法いろいろありすぎて。。。 - それはそれ。これはこれ。 を含むブックマーク 「あとで読む」方法いろいろありすぎて。。。 - それはそれ。これはこれ。 のブックマークコメント

ウェブページを後で読みたいときの方法がありすぎて絞れない。


「あとで読む」の元祖とでも言うべき「はてぶ」http://b.hatena.ne.jp は、通常のブックマークとして使っており、単なる「あとで読む」を登録すると収拾が付かないのでやめる。とはいえ「あとで読む」とか「あとで試す」とかのタグはあるんだけど。


メジャー所では「Tumblr」http://otn.tumblr.com 。しかし、イマイチ使い乗れない*1


今は、「あとで読む」http://atode.cc からメールで、Evernote https://www.evernote.com/ に送って登録している。これはどこかで読んだ組み合わせを参考にした。EvernoteはiPhoneアプリも便利だが、先週メモ入力中に落ちてメモを失ったので、ちょっとおっかなびっくり。


今回新規で登録したのは、iPhone用Twitterアプリ「Simply Tweet」と連携できる「Instapaper」http://www.instapaper.com

Simply Tweetは、Twitterで言及されたウェブページを内蔵ブラウザで見ているときに、ワンタッチでInstapaperに登録できるというもの。いままで、Twitterアプリは、「TwitterFon」を使っていたのだが、内蔵ブラウザに「戻る」ボタンがないので困っていた(またタイムラインからたどりなおし)。あと、バージョンアップで、広告がうざくなったし。

紹介記事「こんな秀逸Twitterアプリがあったのか! - SimplyTweet 2.0CommentsAdd Star」id:hiro45jp:20090719 をみると他にも色々便器機能があるので、おいおい使っていこう。多分フリー版でも十分。


Tumblrとの付き合い方が難しい。

*1:"使い乗れない":造語

2009-05-04(月)

[]新手の検索スパム? 新手の検索スパム? - それはそれ。これはこれ。 を含むブックマーク 新手の検索スパム? - それはそれ。これはこれ。 のブックマークコメント

検索していると、意味のないページが少なからず引っかかる。その検索語を検索した結果ページだ。

どういうことかというと、例えば「ORIG_PATH_INFO」で検索すると、「ORIG_PATH_INFO ;の求人情報 | ジョブエンジン : 総合転職支援サイト ...」というサイトが引っかかる。このサイトで「ORIG_PATH_INFO」というのを検索した結果のページな訳だが、当然ながら何の情報もない。


いったいどういう理由でこのようなページがクローラーに引っかかるのか?引っかかると言うことは、

・誰かがこのページでこの検索語で検索した

・そのリンクを別のページから張った

というのが普通の理由だろうけど、それはとても考えられない。

ということは、こういったジャンクページを系統的に生成してリンクをはり回る仕組みがあるということではないか?意図的とすれば目的が不明。まあ、この手の検索サイトのSEOなのかもしれないけど、SEOが必要ないようなメジャーな検索サイトでもよく見かける。うーん、いざ探すとなかなか見つからないけど、普通に検索するとよく出くわす。


これらを検索結果から省くようなことをしてくれればいいのだけど、判断が難しそう。

2008-11-06(木)

[]Yahooブリーフケース終焉 Yahooブリーフケース終焉 - それはそれ。これはこれ。 を含むブックマーク Yahooブリーフケース終焉 - それはそれ。これはこれ。 のブックマークコメント

Yahooブリーフケースサービスが来月から、プレミアム会員とYBB会員のみのサービスになり、それ以外のフリーで利用していた会員のデータは3ヶ月後に消すというメールが来た。


プレミアム会員って、大半の人は一時的な利用のつもりで入ってるんじゃないのだろうか?プレミアム会員でなくなったとたんに削除される(猶予期間はあるだろうけど)ということだと、ブリーフケースのようなサービスは利用しがたい。YBB会員にしても、他社に乗り換えたときの心づもりをしないといけないわけだし。少なくとも私はそうだなあ。

実質的に、サービス廃止と等しいのではないか?かなり仮定をおいた推測だけど。


そういえば、今月いっぱいでYBBの接続をやめます。

やまきたやまきた 2008/11/08 11:42 う~ん、どうだろう。
私はオークションしてるので、ずっとプレミアム会員のままだから、そう言う人には関係ない。
YBBのユーザーのほとんどは、自分が乗り換えた後のことを考えてるとは思えない。
というわけで、関係があるのはフリーで使っていた人だけだと考えれば、使用者は減るけどそれだけなんでは。
Yahoo!としては、ただ乗りの連中を追い出したってつもりだけなんじゃないかなあ。

2008-10-01(水)

[]セガInternet Adventureは死んでなかった セガInternet Adventureは死んでなかった - それはそれ。これはこれ。 を含むブックマーク セガInternet Adventureは死んでなかった - それはそれ。これはこれ。 のブックマークコメント

何度かテストをやったあと数ヶ月音沙汰無かったので、「死んだか?」と思っていた“iA : セガInternet Adventure”ですが、死んでなかったようです。


“クローズドβテスト2”の案内が来ました。“〔iA〕スタートサイト”でもテスターの追加募集をしてます。日時に限定のあるテストですが、なかなか面白いですよ。って、しかし、GoogleのLivelyとちょっと似てるんだよね〜 Livelyの登場を受けて「似てるぞどうするんだ」的な議論が社内で散々やった末での再登場だと思うので、期待。

さっさとリリースしておけば良かったのにね。このあたりはデータセンターの基礎体力の違いか。

2008-07-24(木)

[]Wassr始めました Wassr始めました - それはそれ。これはこれ。 を含むブックマーク Wassr始めました - それはそれ。これはこれ。 のブックマークコメント

Twitterをやってなかったのですが、ふと魔が差して、Wassr を始めてみました。


思っていたのとかなり違って、面白い。

昔の良かった頃の fj を思い出すところもあります*1。メッセージが短いのとスレッド機能が貧弱なので、まず、もめ事は起こらないでしょう。もっとトラフィックが上がればいいけど。

というわけで、Twitterにも登録しようっと。

*1:あー、物知りがほとんどいない点が大違いかwww

2008-06-12(木)

[]「青少年ネット規制法」を前向きに 「青少年ネット規制法」を前向きに - それはそれ。これはこれ。 を含むブックマーク 「青少年ネット規制法」を前向きに - それはそれ。これはこれ。 のブックマークコメント

成立してしまったわけだが、政府が規制しない法律となったことで、結果として悪くないのではないか。これをきっかけに、複数の(まともな)フィルタリング会社が出来ることを期待。複数のポリシーで競い合い、親が自分の望むフィルター会社を利用できるようになればいい。

まかり間違って、携帯事業者やプロバイダが特定のフィルタリング会社とだけ契約して「ある接続業者を利用する限り、このフィルター会社を利用せざるを得ない」ようになると親には選択肢がないわけで、その会社のポリシーと自分のポリシーが合わない場合には「フィルターを利用しない」という選択をせざるを得ない。こういう事態にはならないで欲しいものだ。


しかし、現状ではまともなフィルタリング業者は存在しないわけで(一番近いのは i-フィルター?)、今後まともな複数の会社が出てくるのは、かなり期待薄。

しかも、まともにやるにはかなりのコストがかかるはずで、それを親が負担するのか?あるいは子供のいない人も含めた携帯やプロバイダユーザーが薄く負担するのか?そのあたりも不明瞭。将来への投資という意味で税金の投入を考えてもいいと思うが、財源がないとか言って無理なんだろうな。


あ、べつに複数の会社じゃなくても、1社でも複数のポリシーをサポートすればいいのか。それなら効率的ではあるが、独占になって安くならなかったりして。


読み返すと練れてないなあ。

2008-03-19(水)

[]SEGA Internet Adventureをやってみる SEGA Internet Adventureをやってみる - それはそれ。これはこれ。 を含むブックマーク SEGA Internet Adventureをやってみる - それはそれ。これはこれ。 のブックマークコメント

http://ia-world.jp/ の Internet Adventureをやってみる。

  • IEで表示させたURLにひもづいた「マップ」という土地が現れて、そこで移動や、他人のアバターとチャットが出来る。
  • IEで別のページを表示させると、別の「マップ」に行く。
  • 逆に「マップ」上で別のマップに移動すると、IEの表示も別のサイトになる(自分のサイトへの呼び込みができるということか)。
  • 「マップ」には家も建てられるし、「ミーム」という「コメントつきのアバターの残像」を置くこともできる。
  • 現在ベータで、時間限定の運用みたい(何日の何時から何時とメールが来る)。

よくわからものですが、発想としては面白そう。

2007-06-22(金)

[]突然トラックバックスパムが3件 突然トラックバックスパムが3件 - それはそれ。これはこれ。 を含むブックマーク 突然トラックバックスパムが3件 - それはそれ。これはこれ。 のブックマークコメント

今までトラックバックスパムって、数ヶ月に1件くらいだったのに、今日いきなり3件。

今後この調子で増えたら何か対策を考えなければ。


こら!そこのスパマー、地獄に堕ちろ!!

2007-04-09(月)

[]NiftyForumからfolomyへ NiftyForumからfolomyへ - それはそれ。これはこれ。 を含むブックマーク NiftyForumからfolomyへ - それはそれ。これはこれ。 のブックマークコメント

すでに一週間以上経っているが、3月末でNiftyのForumが停止した(当面参照だけは出来る)。パソコン通信ForumからウェブForumへの移行は技術の変化に伴うものだったが、今回の廃止はどう捉えればいいのか。mixi等のSNSがそれなりに活況なのを思えば、「群れる」ニーズが無くなった訳ではない。固定ハンドルというのも同じだ。mixiのような軽さが無いというのが原因だろうか。


で、当然難民は出るわけで、旧・SYSOPの人たちが、OpenPNEベースのシステムを作って移行というか活動継続の場を提供している。

http://folomy.jp/

SNSではないが、OpenPNEの改造版であるので、掲示板の集合体であったForumとはかなり感触が異なっている。コアなNiftyユーザはどう受け止めるのだろうか。誰かちゃんとウォッチしている人が居るに違いないが、そういうのを見かけたら教えてほしい。

たけおかたけおか 2007/04/10 02:12 パンがなければ、ケーキならぬGoogleGroups(実はNetNews)に行けばよろしいのに…(日本のNetNewsはスパムで荒れてるようですが)

2007-03-21(水)

[]「読み逃げ」…ネットコミュニケーション依存症患者たち 「読み逃げ」…ネットコミュニケーション依存症患者たち - それはそれ。これはこれ。 を含むブックマーク 「読み逃げ」…ネットコミュニケーション依存症患者たち - それはそれ。これはこれ。 のブックマークコメント

最近、「読み逃げ」という概念が生まれているようだ。

http://www.google.co.jp/search?ie=utf8&oe=utf-8&q=%E8%AA%AD%E3%81%BF%E9%80%83%E3%81%92

ブログやmixi日記を読んでコメントしないことを「読み逃げ」と呼んで「マナー違反」と捕らえる人がいる。何を懼れているのだろうか?やはり、中高生から携帯を使って密にコミュニケーションをとることを強制し&強制されている世代の特徴なのだろうか。想像だが、こういう人は、メールしてもすぐに返事がなかったりすると落ち込んだりするんだろうな。


自分の子供がこういった人にならないようにするためには、どういう指導をすればいいのか。


しかし、自分で落ち込むだけじゃなくて、文句を公言するという人もなあ。。。他人に不快な思いをさせるからやめてほしいものだ。

http://okwave.jp/qa2835346.html

ところで、この質問者のアカウント登録日と同じアカウント登録日で回答(もちろん全面賛同)がこの質問にのみという人がいるということに気づいた人もいる。何か後味悪い質問である

2007-02-02(金)

[]コメントスパムが来出す コメントスパムが来出す - それはそれ。これはこれ。 を含むブックマーク コメントスパムが来出す - それはそれ。これはこれ。 のブックマークコメント

昨日、今日とコメントスパムが来た。はてなダイアリーに対しては初めて。両方とも同じ記事に対してなので、どこかにリンクされているのかもしれない。ちょうど今日、id:hatenadiary:20070202コメントスパム対策を強化しました」ということで、

今回強化したスパム対策では、はてなダイアリーの全ユーザーの記事に対して付けられた最近24時間のコメントを解析し、書き込まれた回数が一定以上になったURLを含むゲストコメントをブロックします。

という機能強化がなされたようだ。ということは私だけじゃなくて最近はてなに対して全般的に増えたと言うことだろうか。今回のは2つともURLを含んだスパムなので、これからはましになると思われる。まあ、運が悪いと最初の一定回数までに当たってコメントされるかもしれないけど。

2007-01-27(土)

[]Office Liveに登録しようと思ったのだが Office Liveに登録しようと思ったのだが - それはそれ。これはこれ。 を含むブックマーク Office Liveに登録しようと思ったのだが - それはそれ。これはこれ。 のブックマークコメント

マイクロソフトの Office Live に登録しようとした。無料版であるBasicサービスは、Google のサービス id:otn:20070101 と似ているようだが、なんと独自ドメイン (com/net/org) が無料で持てる。すでに持っているドメインを移管すればそれ以降の維持費用もマイクロソフト持ちとのこと。「太っ腹」と思ったけど、たかだか年に数百円なので、無料で各種サービスを提供するのに対しての追加コストと考えるとそうでもないのか。

ということで、とあるcomドメインで登録して、クレジットカード番号の入力理由も納得して入力すると、「ドメイン登録で住所指名が公開される」と言う旨の画面が出てきた。。。。。。


すでにいくつか独自ドメインを持っているが、いずれも住所は業者のもので登録してある。「自宅の住所が公開されるのもなあ」と思って結局登録を断念。クレジット番号を入力させた後でこの注意書きを出すところがセコイ。クレジット番号入力前なら考えることなく断念だが、「クレジット番号も入力したしなあ」ということでしばし考えてしまった。これから同じような理由で断念する人のために、注意を喚起しておきます。


Googleは独自ドメイン維持費用は自分持ちだが、過度の個人情報は取られないので安心。com/net/orgなら安いランチ一食程度の年間費用なので、「独自ドメイン無料」に惑わされないように。

2007-01-20(土)

[]Gmailのスレッド Gmailのスレッド - それはそれ。これはこれ。 を含むブックマーク Gmailのスレッド - それはそれ。これはこれ。 のブックマークコメント

Gmailのスレッドは、スレッドに新規メールが増えるとスレッドごと浮上するというのはいいと思っていたのだが、ヘルプを見ると、

スレッドからメッセージを切り離すにはどうすればよいですか。

スレッドにまとめられたメッセージを切り離すことはできません。

関連のないメッセージがスレッドにまとめられた場合は、Google までご連絡ください。

ということである。書かれてはいないがスレッドを繋ぐのも駄目と言うことだろう。


スレッドベースにもかかわらず、スレッドを自由に切ったり繋いだりできないと言うのはつらい。Becky!のようにドラッグ&ドロップで切ったり繋いだりできるのがGmailらしいと思うのだが。

2007-01-14(日)

[]さくらインターネットの携帯メールサービス さくらインターネットの携帯メールサービス - それはそれ。これはこれ。 を含むブックマーク さくらインターネットの携帯メールサービス - それはそれ。これはこれ。 のブックマークコメント

さくらインターネットの「ずっと使えるケータイメアド0円」に申し込んでみた。ドメイン名は mym.sg というシンガポールのドメイン。my msg と読んで欲しいわけだ。

PCから見える説明ページではサービス内容が今ひとつわかりにくいが、これは二つの機能を持っている。一つめは携帯から使えるウェブメールサービス。まあ、これは他業者でも同様のサービスがあるだろう。

もう一つは、zenno.com のステルス転送と言うサービスと同じ機能。これは携帯メールの機能を使って、相手には mym.sg ドメインに見せかけると言うサービスだ。mym.sg のサーバーで From と To のアドレスを書き換えて相手には携帯のメールアドレスが見えない仕組みになっている。

例えば、foo@example.ne.jp にメールを送りたいときには、foo@example.ne.jp.t.mym.sg にメールする。メールは mym.sg サーバーに届くがここで、To を foo@example.ne.jp に、From を mym.sg の自分のアドレスに書き換えて転送してくれる。相手は普通に返事すれば、mym.sg の自分のアドレスに届き、そこで From が foo@example.ne.jp から foo@example.ne.jp.t.mym.sg に書き換わり、To が mym.sg のアドレスから携帯メールのアドレスに書き換わって自分の携帯に届く。それにまた普通に返事を書くと、また mym.sg サーバー経由で相手に届くという仕組みだ。アドレス帳登録の時点で相手アドレスに t.mym.sg をつけて登録しておけば面倒も無い。

zenno.com だと100円/月のサービスだったが、こちらは無料ということで、ちょっと変なアドレスではあるが、ユーザーが増えて zenno.com 危うしとなるのであろうか。またさくらインターネットレンタルサーバーのユーザーであれば、mym.sg でなく自分のドメイン名を使える。ますます zenno.com 危うし。zenno.com のフリーメールサービスにはお世話になっているのでがんばって欲しいものだが。といいつつさくらインターネットの宣伝をしてしまった。

2007-01-08(月)

[][][]「空気読め」とは 「空気読め」とは - それはそれ。これはこれ。 を含むブックマーク 「空気読め」とは - それはそれ。これはこれ。 のブックマークコメント

今日のスマスマは、「特別編〜いまいじめている君へ…〜」。個別のいじめ案件はさておき、スタジオに集まった小中学生にアンケートしたり声を聞いたりというコーナーがあった。

「いじめられる方にも問題がある」という質問に、134人中102人つまり3/4が「はい」。「へー、そんなにいるんだ」。この時点での私の想像は、「“いじめてオーラ”のようなのを出している人かなあ」。で、意見を聞くと、「つばを飛ばす人」とか「自己中」、「空気読めない人」がいじめの対象になるという声が。何人かに聞いたうちの二人分しか放送されなかったので、どの程度一般的な意見なのかはわからないが、多分その場の空気を読んだ(笑)スタッフが選んだんだから、極端な意見ではあるまい。これを逆に言うと、「いじめられるのがいやだったら、空気を読んでみんなに同調しろ」という風に思っていることになる。

これって、非常に問題。みんながお互いの顔色を窺いあう練習を小学生からしているわけだ。いやな社会ですね。


これでふと思い出したのが、先日mixiで見た日記。mixiではニュース(マスコミ報道)を引用して日記を書く仕組みがあるのだが、その中のある日記に、「この日記削除したほうがいいよ」というようなコメントが付いていた。これも「空気を読まないと炎上する」、つまり、「炎上が怖かったら空気読め」ということなんだろう。コメントした人は「善意」にあふれた人なんだろう。いや皮肉じゃなく。


炎上といじめが同一構造とは気づかなかった。「炎上するブログのオーナーにも問題がある」とアンケートされたら「はい」と答えてしまいそう。


「空気」の話は結構ブログで取り上げられているようだ。

http://b.hatena.ne.jp/t/%e7%a9%ba%e6%b0%97

http://artifact-jp.com/2006/12/30/opinion_mutual_adjustment/ とか、

http://d.hatena.ne.jp/sivad/20060415#p2 とか。なるほど、「空気読め」は集合知を殺すわけか。

2007-01-01(月)

[]初作業はGoogleの独自ドメイン登録 初作業はGoogleの独自ドメイン登録 - それはそれ。これはこれ。 を含むブックマーク 初作業はGoogleの独自ドメイン登録 - それはそれ。これはこれ。 のブックマークコメント

「そのうちに・・」と思っていた作業に取り掛かる。https://www.google.com/a/ の独自ドメイン登録。去年サービスが始まった当初に一応申し込んでいたのだが、連絡が来ず。何か入力を間違ったのか、当時はまだ狭い道だったのか今となっては不明。そのとき使ったドメインをうっかり失効させてしまった(連絡先をanet.ne.jpにしていて変更を忘れていたので継続案内メールが来なかった)ということもあり、登録しなおし。


登録画面も前回と違い日本語化されている。知人からのすぐ登録できたという情報どおり、すぐに完了連絡が来た。「自動承認」となっている。ふーん。


ドメインのMXレコードを設定することでメール・チャット・カレンダーが使えるようになる。ドメイン取得はさくらインターネットだが、多分、sakura.ne.jp のコントロールパネルでは設定できないと思う。sakura.ad.jp のドメイン管理画面から変更。ただしこれをやると sakura.ne.jp のコントロールパネルでは管理できなくなる模様。必要になればサポートに聞いてみよう。今のところは問題なし。さらにCNAMEの設定でウェブページGoogle内に持つことができるようになる。


独自ドメインということで、ウェブメールアクセスも独自ドメインかと思ったら違う。あくまでサイトは mail.google.com だ。メールアドレスウェブページだけが独自ドメインとなる。ちょっとがっかり。

まあしかし、短いjpドメインでGmailが使えるというのは嬉しいには違いない。50アカウントまで登録可能ということで、家族はもちろん親戚に配っても余裕あり。


ウェブページ作成ツールは、この手のソフトに慣れない事もあり使いにくい。とりあえずスキンを変えてタイトルのみ入力。別途ウェブサーバーを持っている人には意味なしだけど、「メールしかいらないがウェブページもあってもいいかな」という人には広告無しなのでいいかも。

2006-09-10(日)

[]ロングテールが活きる分野は? ロングテールが活きる分野は? - それはそれ。これはこれ。 を含むブックマーク ロングテールが活きる分野は? - それはそれ。これはこれ。 のブックマークコメント

同じロングテールと言っても、Googleのロングテール(Adwords,Adsense)と、Amazonのロングテール(少量多品種で儲ける)とは違うのではないかと思っていたら、そのあたりを明快に書いてくれているページがあった。

no title


また別の観点

Amazonは巨大な倉庫を抱えているとはいえ、在庫に無いものは売ってない。もちろん、自分の在庫に無くてもメーカー在庫があれば売れるわけだが、メーカーにも在庫が無いものは売れない。Amazonで検索して、絶版・廃盤に当たった事の無い人は少ないだろう。マーケットプレイス商品があればまだましだが、プレミアムが付いてたりする。

また、電化製品などもメーカーが作っているものだけだ。「この機種でこの色のものが欲しい」といった消費者のロングテール的ニーズに答えてくれる訳ではない。量販店のほうが、メーカーと連係してオリジナルモデルを出していたりする分、消費者ニーズに答えている面もある。


もちろん、「おすすめ」等によって「埋もれていた名作」を拾い出すことができるというのもAmazonの大きな利点ではあるが、これも消費者ニーズにたまたま合致した商品があればこそ。存在しない商品に対してのニーズには答えることは出来ない。このあたりを脱することが出来れば、また新しいビジネスが開けると思うのだが。

量販店がオリジナルモデルを出せるのは、店頭での消費者の購入相談の声を聞いているからではないか。Amazonは「声」は聞けないが、同レベルの情報を集めることはできるはずである。ただ、それで儲かるかどうかは別。


もう少し別の観点

陳腐化の早い商品はロングテールは無理ではないか。Amazonで1970年代の本は売っていてもNEC PC-8001は売ってない。電子ブロックは復刻したが、「電気回路入門」という意味ではぜんぜん陳腐化していない商品だ(まあ子供が“電気回路に入門する”というニーズはOutOfDateかもしれないが)。


たのみこむ

また別のロングテールとして「たのみこむ」 tanomi.com があるが、状況を見ると商品化(=市場に登場)はなかなか難しそうだ。

t2t2 2006/09/13 09:05 ご存知と思いますが、復刊ドットコムは結構復刊してますね。儲かっているかは別ですが。
http://www.fukkan.com/

otnotn 2006/09/14 19:50 (そう古くない)過去に出版されたことのある書籍と言うのは、向いた分野ですね。DVDも。
amazonの検索結果参照数が自動的に出版社に届けばいいのに。以前、amazonで日本語版発売が決まっていない海外ドラマのDVDに対して「発売が決まったらメールをくれる」という登録が出来たので、同じようなことが全絶版・廃盤商品に対しても出来るといいのに。