ふと、環境変数LESSOPENの値を見ると、"||/usr/bin/lesspipe.sh %s" になっている。
CentOS6.8だと、/etc/profile.d/less.sh でそのように設定されているが、"|/usr/bin/lesspipe.sh %s"が正しいんじゃないのか?
なぜ"|"が2つあるのか謎。
"|||/usr/bin/lesspipe.sh %s" と3つにするとエラー。
Ruby2.4のInteger
Ruby2.4で、FixnumとBignumの区別が無くなったけど、実際にはあると言う話。
def is_fixnum(n) n.equal?(n.to_s.to_i) end p is_fixnum(1000) #=> true p is_fixnum(10000000000000000000000000) #=> false
forfilesコマンドのバグ?
ちょっと信じがたいけど、少なくともWindows7では、forfilesコマンドにバグがある。テストしてないのか?
/c で指定した外部コマンドの第一引数が落ちるようだ。cmd /c を書けば問題なし。
D:\foo>forfiles /c "gecho 1 2 3 @file" 2 3 bar 2 3 baz D:\foo>forfiles /c "cmd /c gecho 1 2 3 @file" 1 2 3 bar 1 2 3 baz D:\foo>
gecho.exe は gnu-echo コマンド。
第一引数が落ちることを前提にダミー文字列を書いた場合、バグが直ると正しく動かなくなるので、対応としては外部コマンドでも必ず cmd /c を書くことか。
MS Exchange/Outlook のカレンダーとGoogle Calendarの同期 (続編)
id:otn:20150901 「MS 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}
ディスク領域不足のバルーンを表示させない
RAMDISKにキャッシュを置いているようなケースだと、使用量をアプリ側で設定できるので、領域不足になることはないのだが、容量一杯まで使おうとすると、頻繁に警告のバルーンが出てくる。
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer NoLowDiskSpaceChecks REG_DWORD 0x1
call無しの他バッチスクリプト呼び出し
バッチスクリプトから他のバッチスクリプトを呼び出すときに、callで呼び出さないと戻ってこない物だと思っていた。
<<foo.bat>> bar.bat echo foo ・・・・・実行されない <<bar.bat>> echo bar
しかし、forだと実行される。
<<foo.bat>> for %%A in (a b c) do bar.bat&echo foo ・・・・・echo fooまで含めてちゃんと3回実行される echo after for ・・・・・これは実行されない <<bar.bat>> echo bar
ifも。
<<foo.bat>> if a==a bar.bat&echo foo ・・・・・echo fooも実行される echo after if ・・・・・これは実行されない <<bar.bat>> echo bar
構文解析の単位で実行が保証されると言うことか。