Quantcast
Channel: 風柳メモ
Viewing all 92 articles
Browse latest View live

【twSearchFirstTweet】Twitterでキーワードを含む最初のツイートを検索するユーザースクリプトを試作

$
0
0

公式ウェブ版Twitter上で、特定のキーワードを含む最初のツイートが検索できれば、パクツイの元ネタ探しなんかのときに楽かな、と思って作ってみた。
ブックマークレット版はこちら

インストール

Firefox + Greasemonkey
  1. 上記のダウンロードリンクをクリックし、指示に従ってインストール。
Google Chrome + Tampermonkey
  1. 上記のダウンロードリンクをクリックし、指示に従ってインストール。
その他ブラウザ

(未確認)

使い方

ウェブ版Twitterを表示すると、上部にある検索フォームの右側に、虫眼鏡アイコンが追加されている。
検索フォーム中にキーワードを入れるか、もしくは、タイムライン中の語句を範囲選択した状態でこのアイコンをクリックすると、別にタブ/ウィンドウが開いて検索を開始。

サンプルに使用したツイートはこちら


サンプルでヒットしたツイートはこちら

経緯など

などとつぶやいていたところ、GM_K3さん(@)に

と教えて頂く。


実際にFirst Tweet - Who Said It First on Twitterを試してみて、おーっ、これは使える、と思っていたところへ、さらに、

という情報が。

なんと、Twitterの since/until 演算子は、

since:2011-03-11_14:46:00_JST until:2011-03-11_14:47:00_JST

のように、日付だけじゃなく、時刻とタイムゾーン(JST・GMT等)も指定できるとか。


「あれ、これ、ユーザースクリプトでもなんとかなるんじゃ」と思ってしまったので、作ってみた次第。

ブックマークレット版

最古ツイート検索 - Hatena::Let

注意

うまく検索にかからないケースもあるようなので(意図的な調整かインデックス漏れなのかは不明)信頼性は高くなく、参考程度にしか使えないかも。

参考サイト

Twitter公式・ユーザーの最初のツイートを検索

Discover your first Tweet

First Tweet - Who Said It First on Twitter

First Tweet - Who Said It First on Twitter
一度検索されたキーワードはサーバー上に残る模様、二度目からは瞬時に表示される。


mountしたWindows7上のPHPファイルが実行できない?

$
0
0

Linux (CentOS 6.6) で、Windows 7 上のフォルダを mount したとき、Linux 上からそのフォルダ下にある PHP ファイルを実行しようとすると、エラーになってしまう……。
同じフォルダに置いた Python や Ruby 等のスクリプトについては、問題なく実行できる。


今のところ原因が全くわからないので、ご存じの方は教えてほしい。



解決編

改めて検索してみたら、解決策があった。

Add 'noserverino' option, and the problem is settled.

windows - PHP crazy behavior on mount - Super User
[user@linuxhost ~]$ sudo mount -t cifs "//win7host/src" /mnt/src -ousername=user,password=pass,uid=500,gid=500,file_mode=0755,dir_mode=0755,noserverino

This doesn't sound like a PHP problem at all. My best guess is that you have a 32/64-bit mismatch here. And PHP doesn't currently support 64-bit inodes.

PHP :: Bug #50150 :: stat() / lstat() does not work on a mounted cifs

使用しているPHPのバージョンが64ビット inode をサポートしていないので、ホスト側(Windows側)が64ビット版の場合にこの問題が起こるらしい。

Inode Numbers

When Unix Extensions are enabled, we use the actual inode number provided by the server in response to the POSIX calls as an inode number.

When Unix Extensions are disabled and "serverino" mount option is enabled there is no way to get the server inode number. The client typically maps the server-assigned "UniqueID" onto an inode number.

Note that the UniqueID is a different value from the server inode number. The UniqueID value is unique over the scope of the entire server and is often greater than 2 power 32. This value often makes programs that are not compiled with LFS (Large File Support), to trigger a glibc EOVERFLOW error as this won't fit in the target structure field. It is strongly recommended to compile your programs with LFS support (i.e. with -D_FILE_OFFSET_BITS=64) to prevent this problem. You can also use "noserverino" mount option to generate inode numbers smaller than 2 power 32 on the client. But you may not be able to detect hardlinks properly.

mount.cifs(8) - Linux man page


なお、64ビット環境のLinuxからmountした場合には、noserverino オプションをつけなくても動作した。



環境

[user@linuxhost ~]$ # === OS バージョン確認[user@linuxhost ~]$ uname -a
Linux linuxhost.localdomain 2.6.32-504.el6.i686 #1 SMP Wed Oct 15 03:02:07 UTC 2014 i686 i686 i386 GNU/Linux[user@linuxhost ~]$ cat /etc/redhat-release
CentOS release 6.6 (Final)[user@linuxhost ~]$ # === PHP バージョン確認[user@linuxhost ~]$ php -v
PHP 5.4.28 (cli)(built: May  2201418:40:44)
Copyright (c)1997-2014 The PHP Group
Zend Engine v2.4.0, Copyright (c)1998-2014 Zend Technologies

不具合発生手順

[user@linuxhost ~]$ # === Windows7 上のフォルダを /mnt/src に mount[user@linuxhost ~]$ sudo mount -t cifs "//win7host/src" /mnt/src -ousername=user,password=pass,uid=500,gid=500,file_mode=0755,dir_mode=0755[user@linuxhost ~]$ # === /mnt/src に移動[user@linuxhost ~]$ cd /mnt/src
[user@linuxhost src]$ # === 簡単なPHPファイル作成[user@linuxhost src]$ echo"<?php echo(\"TEST\n\");"> ./test.php
[user@linuxhost src]$ cat ./test.php
<?php echo("TEST\n");
[user@linuxhost src]$ # === 実行するとエラー[user@linuxhost src]$ php ./test.php
PHP Fatal error:  Unknown: Failed opening required './test.php'(include_path='.:/usr/share/pear:/usr/share/php')in Unknown on line 0[user@linuxhost src]$ # === リントでも Warning とエラー[user@linuxhost src]$ php -l ./test.php
PHP Warning:  Unknown: Failed opening './test.php'for inclusion (include_path='.:/usr/share/pear:/usr/share/php')in Unknown on line 0
Errors parsing ./test.php


なお、上記で作成した /mnt/src/test.php を include() することは出来るので、ますます謎。

[user@linuxhost ~]$ # === mount ディレクトリ以外に移動[user@linuxhost ~]$ cd ~
[user@linuxhost ~]$ # === /mnt/src/test.php を include() するPHPファイル作成[user@linuxhost ~]$ echo"<?php include('/mnt/src/test.php');"> ./call_test.php
[user@linuxhost ~]$ cat ./call_test.php
<?php include('/mnt/src/test.php');
[user@linuxhost ~]$ # === ちゃんと実行される[user@linuxhost ~]$ php ./call_test.php
TEST

脆弱性案件はかわいいGHOSTの夢を見るか?

$
0
0

glibcのgethostbyname系関数にバッファオーバーフローを引き起こす重大な脆弱性(CVE-2015-0235)が発見されたとして騒ぎになっている。

The Laws of Vulnerabilities: The GHOST Vulnerab... | Qualys Community
Qualys Security Advisory CVE-2015-0235
glibc の脆弱性 CVE-2015-0235(通称:GHOST)についてまとめてみた - piyolog
glibcのgethostbyname関数に存在するCVE-2015-0235(GHOST)脆弱性について - ブログ - ワルブリックス株式会社
JVNVU#99234709: glibc ライブラリにバッファオーバーフローの脆弱性
glibc の脆弱性対策について(CVE-2015-0235):IPA 独立行政法人 情報処理推進機構

こちらの記事には、RedHat Enterprise Linux・CentOS・Debian GNU/Linux等の対処方法も書かれている

脆弱性の概要

glibcは libcのGNUバージョンです。libcはアプリケーションではなく、事実上全てのアプリケーションが利用しているライブラリです。OSの中ではカーネルに次いで重要な部分と言えます。Linuxシステムでは例外なく glibcが使われています。


この glibcに含まれる gethostbyname系関数の実装に 2000年頃から存在したバグが今になって発見され、CVE-2015-0235 通称 GHOSTと命名されました。ネットワークで何らかの通信を行うアプリケーションは必ずこの関数を使用します。

glibcのgethostbyname関数に存在するCVE-2015-0235(GHOST)脆弱性について - ブログ - ワルブリックス株式会社

今回発見されたglibcの問題は、攻撃者がリモートから細工されたホスト名文字列を(例えばURLのホスト名部分などに埋め込んで)与えることによって、アプリケーション側のメモリを数バイト上書きできてしまうことです。

実際に、Exim(メールサーバ)に対して攻撃を行い任意コードの実行が出来る実証コードを作成できたそうです。32bit/64bitの両方が攻略可能で、CPUの不正命令実行防止機構(ASLR, PIE, and NX)は役に立たないとのこと。

glibcのgethostbyname関数に存在するCVE-2015-0235(GHOST)脆弱性について - ブログ - ワルブリックス株式会社

ということで、少なくともLinuxを用いている場合には*1早々に確認の上、必要に応じて対応しなければならない。


……のだが。


え、これは……?

「GHOST」という通称(GetHOSTbynameに由来)もさることながら

GHOST vulnerability

The Laws of Vulnerabilities: The GHOST Vulnerab... | Qualys Community

用意されたこのアイコンのせいで、事態の深刻さと比較して、どうにも危機感が薄まってしまうのは否めない。


これは孔明の罠か?……いやいや、惑わされてはならない。きちんと確認の上、対応しなければ。

脆弱性の確認方法

基本的には、

Qualys Security Advisory CVE-2015-0235

中にある、GHOST.cをコンパイル・実行すると、"vulnerable"か"not vulnerable"か(実行したシステムが脆弱か否か)が表示されるので、"vulnerable"だった場合には対応が必要となる。


ただ、自分のような英弱には、"vulnerable"という単語を見て、即座に「危険だ!」と判断することは困難である。
そこで、脆弱性があった場合の結果を目立たせるように簡単なパッチをあててみた。

ghost.c
#include <netdb.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#define CANARY "in_the_coal_mine"struct {
  char buffer[1024];
  char canary[sizeof(CANARY)];
} temp = { "buffer", CANARY };

void ghost(void) {
  int a, b=0, c=10; for (; (a="!nBACAAUBJBPAOANAQALAFBFBCAJAFDDDBCHATBIACAFMGAESFAKCAAHACCEGADBDBAEBLMGCRANCBHBBE"[b++]);) for(;64< a--;) putchar((++c == 42) ? (c-=32) : (32^(b&1)));
  puts("GHOST IN THE SHELL\n");
}

int main(void) {
  struct hostent resbuf;
  struct hostent *result;
  int herrno;
  int retval;

  /*** strlen (name) = size_needed - sizeof (*host_addr) - sizeof (*h_addr_ptrs) - 1; ***/size_t len = sizeof(temp.buffer) - 16*sizeof(unsignedchar) - 2*sizeof(char *) - 1;
  char name[sizeof(temp.buffer)];
  memset(name, '0', len);
  name[len] = '\0';

  retval = gethostbyname_r(name, &resbuf, temp.buffer, sizeof(temp.buffer), &result, &herrno);

  if (strcmp(temp.canary, CANARY) != 0) {
    //puts("vulnerable");
    ghost();
    exit(EXIT_SUCCESS);
  }
  if (retval == ERANGE) {
    puts("not vulnerable");
    exit(EXIT_SUCCESS);
  }
  puts("should not happen");
  exit(EXIT_FAILURE);
}
CVE-2015-0235_GHOST/ghost.c at develop · furyutei/CVE-2015-0235_GHOST · GitHub

これを使用しているシステムでコンパイルして

$ gcc -o ghost ghost.c

実行すると、該当する脆弱性がある場合には、

$ ./ghost

              !! !!! !
           !!          !!
         !               !
        !                 !
       !      !!      !!   !
      !      !!!!    !!!!  !!!
      !                    !!
      !   !      !!!!!!!!!!!!!
     !     !!!!!!!!!!!!!!!!!!!
    !           !!! !        !
 !!!     !!!!!!! !!!!  !!!!  !
   !!            !!!!!!!!!!!!!
     !!!                  !
         !!!  !!!!!!!!  !!     GHOST IN THE SHELL

$ 

このように一目でわかるので、迅速な対応が可能になると思われる。適宜活用されたし。

などと、まじめに対応するつもりでもついついネタに走りたくなってしまうので、脆弱性案件にかわいい通称やアイコンはよくない。

追記:GitHubにも登録

mholzinger/CVE-2015-0235_GHOST · GitHub

をForkさせてもらい、

furyutei/CVE-2015-0235_GHOST at develop · GitHub

上のファイルを読み込んで実行できるようになった。

wget で実行
$ wget -q-O - "https://raw.githubusercontent.com/furyutei/CVE-2015-0235_GHOST/develop/build_aa.sh" | bash
not vulnerable
curl で実行
$ curl -skL"https://raw.githubusercontent.com/furyutei/CVE-2015-0235_GHOST/develop/build_aa.sh" | bash
not vulnerable

*1:GNU glibcの問題なので、Linux以外でも影響する場合はある

萌えるステータスコード 〜 生徒会長編 〜

$
0
0

無味乾燥なHTTPステータスコードに、潤いを。
麗しの生徒会長*1の台詞を通して、理解を深めよう!*2
何番煎じだ、とかいわない。
HTTPステータスコードの本来の意味に対して、台詞の内容に違和感がある(解釈がおかしい)等のコメントを緩募。

1xx Informational 情報

CodeReason Phrase台詞
100Continueええ、そのままで続けて。
101Switching Protocols解ったわ、言われた手順に変えてみるわね。
102Processing (WebDAV)その件なら処理中よ。

2xx Success 成功

CodeReason Phrase台詞
200OKいいわ。はい、これ。
201Createdうん、できたわ。これね。
202Acceptedひとまず、受け取っておくわ。
203Non-Authoritative Information不確かな噂なのだけれど……。
204No Contentバインダーに何も挟まっていないわ。
205Reset Content解ったわ。あ、次の人のために、ホワイトボードは消しておいてね。
206Partial Contentその範囲だと……これだけかしら。
207Multi-Status (WebDAV)いくつか頂いていた案件について、まとめておいたわ。
208Already Reported (WebDAV)その件は、もう報告済みだけれど……ほら、ここに、ね?
226IM Used前回から加筆修正された箇所? そうね、この辺りかしら。

3xx Redirection リダイレクション

CodeReason Phrase台詞
300Multiple Choicesどれかを選んでちょうだい。
301Moved Permanentlyそれなら、あちらの部屋に移したわ。
302Foundあ、あったわ。あちらを見てもらえるかしら。
303See Otherそれはここじゃなくて、他をあたって。紹介状は書かせてもらうわ。
304Not Modified前に伝えた通りよ。
305Use Proxyその件は委員会を通してちょうだい。
306(Unused)(今はまだ、なにも言えない。)
307Temporary Redirectあ、それは今だけ、そちらの棚に移してあるの。
308Permanent Redirectこの書類のままでいいから、あちらに提出しなおしてもらえる?

4xx Client Error クライアントエラー

CodeReason Phrase台詞
400Bad Request不正は許されないわ。
401Unauthorizedあなたに、どんな権限があるというの?
402Payment Requiredそれには、予算の計上が必要なの。
403Forbiddenそれは禁止されているでしょう?
404Not Found変ね、見つからないけれど?
405Method Not Allowedそんな方法は認められません。
406Not Acceptable書類に不備があるから、受領はできないわ。
407Proxy Authentication Requiredその件については、委員会の承認が必要よ。
408Request Timeout時間切れ、ね……。
409Conflictそうじゃないでしょう、矛盾しているわよ。
410Gone困ったわ、どうやら紛失してしまったみたい……。
411Length Requiredその書類、最初に何ページあるかを書いておいてね。
412Precondition Failedそもそもの前提が間違っているわ。
413Request Entity Too Largeごめんなさい、時間もないので、要点だけにしてもらえる?
414Request-URI Too Long枠からはみ出してしまっていて、よくわからないわ。
415Unsupported Media Typeあ……もうそのメディアでは受け付けられないのよ。
416Requested Range Not Satisfiableその期間分のデータは無いのよね……。
417Expectation Failedそ、それは生徒会の管轄外よ。
418I'm a teapot (RFC 2324)私、コーヒーはだめなのよ。紅茶にしてもらえるかしら。
422Unprocessable Entity (WebDAV)確かに書式はあっているのだけれど……この項目、おかしくないかしら?
423Locked (RFC 2324)そこの鍵は預かっていないのよ。
424Failed Dependency (RFC 2324)この前の議題が否決されてしまっているから……ごめんなさい、これも駄目ね。
426Upgrade Required申し訳ないのだけれど、新しい書式に則ってもらえるかしら。
428Precondition Required少し事情が変わってしまったの。悪いのだけれど、こんな感じに調整して再提出お願いできるかしら。
429Too Many Requests同じ人からの相談を続けて受けるというのは問題になってしまうの。日を改めてもらえるかしら。
431Request Header Fields Too Large序章の注釈が多すぎて読みづらくなってしまっているの。もう少し整理してもらえないかしら。

5xx Server Error サーバエラー

CodeReason Phrase台詞
500Internal Server Errorごめんなさい、こちらに落ち度があったようね……。
501Not Implementedその件は、まだ体制が整っていないのよ。
502Bad Gatewayその件だけれど、先方に断られてしまったわ。
503Service Unavailable今は少し手を離せないの、後でまたお願いできるかしら。
504Gateway Timeout出ないわね……ごめんなさい、担当の方がご不在みたい。
505HTTP Version Not Supportedその校則は草案はあるのだけれど、まだ適用されてはいないのよ。
506Variant Also Negotiatesえ、ええ……こちらのミスで、交渉先が判らなくなってしまっているようなの……。
507Insufficient Storage (WebDAV)ごめんなさい、どうやら保管場所が無くなってしまったようなの……。
508Loop Detected (WebDAV)堂々巡りで、結局何も決まらなかったわ……。
509Bandwidth Limit Exceededこの量は、一度に運びきれないわ。
510Not Extended今のままだと、そこまでは認められないわ。こんな感じでやり直してもらえるかしら。
511Network Authentication Required先に、こちらで委員会の登録手続きをすませてもらえる?

*1:イメージは七草真由美@魔法科高校の劣等生(CV:花澤香菜さん)とか、望月真帆@大図書館の羊飼い(CV:中島沙樹さん)とか

*2:いやほんとに、いけないと思いながらも、ついつい手を抜いた実装にしてしまうんですよね……(サーバー・クライアント共に)

究極超人あ〜るネタを調べていたらFreeBSDのカレンダーコマンド(ncal)の不具合に行き当った件

$
0
0

ちょっと、2月のカレンダーと「14日の土曜日」ネタがらみで、

のようなことをつぶやきたいな、と思って、念のため調べていたら、いつの間にかFreeBSDのncalコマンドバグなのかも?と思われるものを見つけてしまった、という話。
いや、我ながら何を言っているのかわかりませんが…。

■ 経緯

◇ 13日の金曜日よりも14日の土曜日が重要なクラスタより
  • タイムライン上に「そういえば13日の金曜日」のようなツイートがちらちら
  • すると「14日は土曜日ではないか!」と反応しはじめる、偏った人々(ゆうきまさみフォロワーの方ね)
◇ 2月で「14日の土曜日」だった年を調べたところ…

『あ〜るのバレンタイン話は、確か1987年だったよなぁ』

$ cal 2198721987日 月 火 水 木 金 土
 12345678910111213141516171819202122232425262728

『うんうん。えーと、今年はそれから何回目?ついでに西暦1年から調べてみるか』

$ python
>>> import calendar
>>> all, counter =0, 0>>>for year in range(1, 1+2015):
...   if calendar.weekday(year, 2, 14)==5:
...     all +=1
...     if 1987< year: counter +=1
...     print year
...
4915:(中略)17501756:(中略)198119871998200420092015>>>print all, counter2884>>>

『ほぉ、西暦4年もそうだったのか』

$ cal 2424日 月 火 水 木 金 土
                1234567891011121314151617181920212223242526272829

『あ、あれれ……?』

(中略)

$ cal 2175021750日 月 火 水 木 金 土
             12345678910111213141516171819202122232425262728

『んん…?』


― 間 ―

$ cal 2175621756日 月 火 水 木 金 土
 1234567891011121314151617181920212223242526272829

『あ、これはちゃんと14日の土曜日になってるな。このあたりが境目、か……?』

◇ 原因は?
$ man cal
CAL(1)                  FreeBSD General Commands Manual                 CAL(1)

NAME
     cal, ncal ― displays a calendar and the date of Easter

(中略)

     -s country_code
             Assume the switch from Julian to Gregorian Calendar at the date
             associated with the country_code.  If not specified, ncal tries
             to guess the switch date from the local environment or falls back
             to September 2, 1752.  This was when Great Britain and her
             colonies switched to the Gregorian Calendar.

なる程、デフォルトだと、イギリスがグレゴリオ暦を採用した1752年9月14日以降がグレゴリオ暦表示で、それ以前はユリウス暦表示なのね。

$ cal 9175291752日 月 火 水 木 金 土
       121415161718192021222324252627282930

ほうほう。グレゴリオ暦での1752年9月13日はユリウス暦1752年9月2日なので、こうなるのね。

◇ 国名コードを指定するとどうなる?

これ、他の国だとどうなるんだろう?

略号一覧

ISO 3166-1 - Wikipedia

コマンドの -s オプションで指定できる国名コード(country_code)は二字のもの、ただし、網羅されているわけではない。


そもそも、イタリア(1582年10月15日グレゴリオ暦制定)だと?

《参考資料》ユリウス暦からグレゴリオ暦への切り替え
・1582年にローマ法王グレゴリオ13世がユリウス暦からグレゴリオ暦への転換を宣言したことにより、この時期にユリウス暦からグレゴリオ暦への切り替えが行われた国があります。
・カトリック国のイタリア、スペインなどでは1582年10月に切り替えが行われ、1582年10月4日の翌日が10月15日になり、1582年10月5日から10月14日までは存在しません。

みんなの知識【ちょっと便利帳】 - その曜日は何日? 各年・各月の曜日を調べる - 西暦と月を設定し、各曜日の日付を一覧表示
$ cal -s IT 101582
Usage: cal [general options][-hjy][[month] year]
       cal [general options][-hj][-m month][year]
       ncal [general options][-hJjpwy][-s country_code][[month] year]
       ncal [general options][-hJeo][year]
General options: [-NC3][-A months][-B months]
For debug the highlighting: [-H yyyy-mm-dd][-d yyyy-mm]

あ、-s オプションは ncal だけか。

$ ncal -s IT 10158210158211825219263202742128152229162330172431

うん、確かに10/15を境に切り替わっているな。
じゃあ、日本だとどうなの?

・1873年1月1日に当たる明治5年12月3日(旧暦)を明治6年1月1日(新暦)とする太陽暦への改暦(明治改暦)。

グレゴリオ暦 - Wikipedia
$ ncal -s JP -A1121872121872118734111825181522295121926291623306132027310172431714212841118251815222951219262916233061320273101724317142128

ん?日付は連続しているし……

$ ncal -s IT -A1121872121872118732916233061320273101724317142128411182518152229512192629162330613202731017243171421284111825181522295121926

イタリアの暦とも違っている、ということは、このあたりはまだユリウス暦で表示されている、ということ?

◇ ncalでは、日本はいつグレゴリオ暦に切り替えたことになっているのか?
$ ncal -s JP -A11219181219181191931017613202741118714212851218152229613291623307143101724311815411182529165121926

は、はい……?
1919年1月1日から切り替えたことになっているのか……なぜ???

結論(暫定)

結局、自分が調べた範囲では理由がわからず、単純なプログラム上の登録ミスではないか? と考えている。
実は深い理由があるのかも……ご存知の方、教えてください。


FreeBSDのncalコマンドソースコード中で、

[base] Contents of /head/usr.bin/ncal/ncal.c

69/* The switches from Julian to Gregorian in some countries */70staticstruct djswitch {
71constchar *cc; /* Country code according to ISO 3166 */72constchar *nm; /* Name of country */73	        date dt;        /* Last day of Julian calendar */74	} switches[] = {
75	        {"AL", "Albania",       {1912, 11, 30}},
76	        {"AT", "Austria",       {1583, 10,  5}},

のように、ISO 3166の国名コード(2文字)毎にユリウス暦→グレゴリオ暦に移り変わった日付の定義がなされているが、そのうち、日本(JP)用の定義が違っているのではないか、と。

$ diff -c ncal.c.r241737 ./ncal.c
*** ncal.c.r241737      2015-02-13 02:24:25.000000000 +0900--- ./ncal.c    2015-02-13 02:26:03.000000000 +0900****************** 91,97 ****
        {"HU", "Hungary",       {1587, 10, 21}},
        {"IS", "Iceland",       {1700, 11, 16}},
        {"IT", "Italy",         {1582, 10,  4}},
!       {"JP", "Japan",         {1918, 12, 18}},
        {"LI", "Lithuania",     {1918,  2,  1}},
        {"LN", "Latin",         {9999, 05, 31}},
        {"LU", "Luxembourg",    {1582, 12, 14}},
--- 91,97 ----
        {"HU", "Hungary",       {1587, 10, 21}},
        {"IS", "Iceland",       {1700, 11, 16}},
        {"IT", "Italy",         {1582, 10,  4}},
!       {"JP", "Japan",         {1872, 12, 19}},
        {"LI", "Lithuania",     {1918,  2,  1}},
        {"LN", "Latin",         {9999, 05, 31}},
        {"LU", "Luxembourg",    {1582, 12, 14}},
$ # 改修版の実行結果
$ ./ncal -s JP -A1121872121872118734111861320275121971421286131815222971429162330181531017243129164111825310175121926
◇ 注釈

そもそも日本の場合、べつにグレゴリオ暦の前にユリウス暦を使っていたわけではないので、定義するのはナンセンス、という話はある。
その上で、元のソースコード中で「グレゴリオ暦1919年1月1日」(厳密にはその前日に当たるユリウス暦1918年12月18日)が登録されている根拠もよくわからず、まだこれよりは、明治改暦が実施された「グレゴリオ暦1873年1月1日」(同1872年12月19日)を登録した方がもっともらしいのではないか、と考える次第。

■ 補足等

◇ ncal のバグについて

そもそもncal中の国別のユリウス暦→グレゴリオ暦切替日定義は、日本以外に関しても信頼できるかどうかは怪しい、のかも。
ncal(1)

BUGS
The assignment of Julian--Gregorian switching dates to country codes is
historically naive for many countries.

https://www.freebsd.org/cgi/man.cgi?query=ncal&sektion=1&manpath=FreeBSD+6.0-RELEASE
$ ncal -p
 AL Albania        1912-11-30      IT Italy          1582-10-04
 AT Austria        1583-10-05     *JP Japan          1918-12-18
 AU Australia      1752-09-02      LI Lithuania      1918-02-01
 BE Belgium        1582-12-14      LN Latin          9999-05-31
 BG Bulgaria       1916-03-18      LU Luxembourg     1582-12-14
 CA Canada         1752-09-02      LV Latvia         1918-02-01
 CH Switzerland    1655-02-28      NL Netherlands    1582-12-14
 CN China          1911-12-18      NO Norway         1700-02-18
 CZ Czech Republic 1584-01-06      PL Poland         1582-10-04
 DE Germany        1700-02-18      PT Portugal       1582-10-04
 DK Denmark        1700-02-18      RO Romania        1919-03-31
 ES Spain          1582-10-04      RU Russia         1918-01-31
 FI Finland        1753-02-17      SI Slovenia       1919-03-04
 FR France         1582-12-09      SW Sweden         1753-02-17
 GB United Kingdom 1752-09-02      TR Turkey         1926-12-18
 GR Greece         1924-03-09      US United States  1752-09-02
 HU Hungary        1587-10-21      YU Yugoslavia     1919-03-04
 IS Iceland        1700-11-16

※ラテン世界の9999年

$ ncal -s LN 999999991234月
月   1815222951219265121926291623302916233061320276132027310172431017243171421287142128411182541118251815221815222951219265121926291623291623306132027613202731017243101724317142128714212841118254111825181522295678月
月      71421281623301815222917243129162330182531017243119264111825132027512192614212861320271522299101112月
月      6132027411182518152229613202771421285121926291623307142128181522296132027310172418152229291623307142128411182529162330310172418152229512192631017243141118252916233061320274111825512192631017243171421285121926
◇ 覚書
  • FreeBSD の cal コマンドは ncal コマンドのエイリアス
    バイナリレベルで同一。コマンド名で判別し、ncalの -C オプション相当の表示をしている模様。
◇ 愚痴

というかそもそも、「とある年月を境にしてユリウス暦とグレゴリオ暦が切り替えられ、かつ、一見して(表示結果では)それとわからない」なんて仕様のカレンダー自体、やめて欲しいと思うのは自分だけ?
「デフォルトでグレゴリオ暦換算のカレンダーを表示、オプションでユリウス暦換算でも表示可能だよ」でええやん…。

正常系・異常系共通の後処理を行うための手法検討と、「途中return禁止」「goto禁止」等の“一律禁止”問題

$
0
0

たいたい竹流さん @ガード節に関するツイートについて、

のようにリプライしたところ、

のようにコメント頂いた。


これに端を発した議論が有意義に思えたので、自分用の覚書として要点をまとめておく。

■ ガード節について

ガード節そのものについては、自分は最初から積極的に賛同している立場であるため、この記事では特記しない。


ガード節の有効性については、下記記事の引用部分に集約されているように思う。


これは、「ガード節による入れ子条件記述の置き換え」と呼ばれるもので、リファクタリング本では次のように説明されている。


「ガード節による入れ子条件記述の置き換え」のキーポイントを強調しておきましょう。if-then-else 構造が使われる時は、if 部にも else 部にも同じウエイトが置かれています。これは、プログラムの読み手に対して両方共等しく起こり得ること、等しく重要であることを伝えます。逆に、ガード節は『めったに起きないが、起きた時には、何もしないで出ていく』ことを伝えます。


リファクタリング - 第九章 条件記述の単純化 p.251
小野和俊のブログ:ガード節を用いた if-then-else 文の置き換え

■ 自分の発言の趣旨

上記であげた自分のリプライについてだが、もともと、複数のreturnを設けたり、Wrapper関数化するのに消極的だったのは、主にデバッグ上の要求から。

  • 複数 return があると、そのすべてにブレイクポイントやログ出力処理などを設ける必要が出てくるので、出口は一つにしたい
  • Wrapper化により異常系/正常系処理と共通の後処理とを切り離してしまうと、後処理内で異常系/正常系のローカル変数を参照できない
  • 後処理を共通化するためだけの単純なWrapperを設けるのは、余分にコールスタックが増えるということであり、デバッグ時にコールスタックを表示させた際、ソースコードにおいてネストが深くなるのと同等の見通しの悪さが生じる
  • Wrapperのために関数名が増えるのは面倒(苦笑)(言うまでもなく、これは副次的な理由)


なお、「ルールだから」という理由で途中 return を設けないわけではなく、デバッグ上の理由で消極的なだけなので、「必ず共通の後処理が実行される」保証があれば、途中で return することについては特に忌避感はない。

■ try-catch-finally で万全

実は、Java 等の try-catch-finally 相当の構文が使用できる言語であれば、次のように記述することで満足できる。

try {
    result = ABNORMAL;
    // [I] 共通の前処理(スコープ内で使用するローカル変数設定等)if ( /* 異常系判定条件 */ ) { // ガード節// [A] 異常系処理return result;
    }
    // ※状況に応じて複数のガード節を記述// [N] 正常系処理
    result = NORMAL;
    return result;
}
catch (Throwable errorObject) {
    // [E] 想定外の異常系(例外)処理throw errorObject;
}
finally {
    // [F] 共通の後処理// ※デバッグ用に、この部分にローカル変数を参照するログ出力処理等を入れたり//   条件付きブレイクポイントを設定したりできる
}

try-catch-finallyは、try節中等に return があっても必ず finally 節が実行されるため、ブレイクポイントやログ出力処理などもここにまとめることができ、Wrapperを用意する必要もなくなり、上記の要求は全て満たされる。


■ try-catch-finally の類が使えない場合の代替手段

問題は、try-catch-finally のような「途中の経過に関わりなく後処理が実行される」という機能を持たない言語の場合。
たいたい竹流さんが募集して下さった意見などを元に、いくつかの代替手段とその問題点等をあげる。

◇ 一度のみ実行するループを用いた方法
result = ABNORMAL
// [I] 共通の前処理(スコープ内で使用するローカル変数設定等)<ループ> {
    if ( /* 異常系判定条件 */ ) {
        // [A] 異常系処理break
    }
    
    // [N] 正常系処理
    result = NORMAL
    break
}
// [F] 共通の後処理return result

for(;;){…} や while(true){…}、do{…}while(false)を使う手法。


問題点

  • 初見の人には意図が判り辛い(do{…}while(false)であれば多少まし、ただし、言語によっては定数falseを使うことによる警告も)*1
  • 一度しか実行されないループ→ループとして機能していない→構造化構文の誤用
◇ goto を用いた方法
result = ABNORMAL
// [I] 共通の前処理(スコープ内で使用するローカル変数設定等)if ( /* 異常系判定条件 */ ) {
    // [A] 異常系処理goto finally
}
    
// [N] 正常系処理
result = NORMAL

finally:
// [F] 共通の後処理return result 


問題点

◇ 関数内関数を用いた方法
result = ABNORMAL
// [I] 共通の前処理(スコープ内で使用するローカル変数設定等)

(<関数>(){if ( /* 異常系判定条件 */ ) {// [A] 異常系処理return;
    }// [N] 正常系処理
    result = NORMAL
    return;
})()

// [F] 共通の後処理return result


問題点

  • 一見してあえて関数内関数を使う意図が判り辛い
  • 本来スコープ内に閉じ込めるべきローカル変数を外出ししている(必要な変数をすべて引数として渡す、という方法もあるが、それならば最初から外部関数なりにするのと変わらず、内部関数にするメリットがない)
◇ classのデストラクタを利用した方法
<クラス定義> {
    result = ABNORMAL
    // [I] 共通の前処理(スコープ内で使用するローカル変数設定等)<メイン処理>(…) {
        if ( /* 異常系判定条件 */ ) {
            // [A] 異常系処理return result
        }
    
        // [N] 正常系処理
        result = NORMAL
        return result
    }

    <デストラクタ>(…) {
        // [F] 共通の後処理
    }
}


問題点

■ コーディングルールにおける「一律禁止」問題

上記の議論に付随して、「コーディングルールにおける、思考を停止した『一律禁止』は問題である」という話も出た。
知らず知らずのうちに思考停止に陥っていることが多いので、自戒を込めてまとめる。


ルールには、もちろんそれが制定された意味はある(場合がほとんどだ)けれども、盲目的に従うのではなく、歴史的な経緯を把握した上で、現状と照らし合わせてきちんと考えようということだと思う。
とはいえ、クライアントに要求されたルールに従わざるを得ない等、なかなか理想通りには行かないことも多いのだけれど……せめて吟味し批判する姿勢は保ちたいもの。


等々。

◇「途中return禁止」ルール

もともとのガード節に関するツイートに対し、「出口が複数あって却って見づらい」旨の否定的な意見受けて

ここで注意すべきなのは、構造化プログラミングの文脈では、「1つの入り口と1つの出口を持つ、順次・選択・反復の3つの論理構造の組み合わせ」というスタイルはプログラム実行時のフローをソースコードから追いやすくするために用いられている、という点だ。

MISRA-Cにおける「関数の末尾以外の return 禁止」の真意 - 新・日々録 by TRASH BOX@Eel

関数内での途中returnは、大抵がネストを浅くする――つまり静的構造自体が複雑化することを避ける目的で使用されることが多いはずだ。構造化プログラミングでは考慮されていない部分なのだ。

こうなってくると、基本的には「1つの入り口と1つの出口を持つ、順次・選択・反復の3つの論理構造の組み合わせ」というスタイルをとりつつも必要に応じてルールを破る、というスタイルに落ち着く。

MISRA-Cにおける「関数の末尾以外の return 禁止」の真意 - 新・日々録 by TRASH BOX@Eel
◇「goto禁止」ルール

上述した「一度のみ実行するループを用いた方法」に関して、そういった(自分でも自覚しているような)トリッキーな方法を使うのではなく、gotoを使うべき、という意見

タイムリーな記事もあった。

200万近いC言語のファイルと1万1千件を超えるプロジェクトからランダムに抽出した統計的に有効なサンプルを質的および量的に分析したところ、開発者はほとんどの場合gotoの使用を適切に制限しており、Dijkstra氏が懸念したような無制限な使用は行われていないことが判明した。これらのことから、実際にはgotoは有害でないものと考えられる。

C言語の開発者によるgoto文の使い方を対象とした実証研究の結果、「goto文は無害だと考えられる」 - エキサイトニュース

「goto一律禁止」のルールで作られているものはそもそもgoto文が現れないので抽出されないだろうし、そうでない場合は思考停止すること無くよく考えて使う開発者の割合が高くなるような気もするので、この結果を鵜呑みにして実際に解禁したら無制限な使用が増える、という可能性も否定できない気はするけれど。

*1:自分の場合は最初見た例がdo{…}while(false)だったために割とすんなり理解できたし、その土台があったため、警告対策でfor(;;){…}に切り替えた際も特に違和感を感じなかったという経緯がある

Google App Engineのデプロイ時に認証エラーがでる場合の対策

$
0
0

久しぶりに GAE のアプリケーションをいじった後で、デプロイしようとすると、

Password for username: Use an application-specific password instead of your regular account password.
See http://www.google.com/support/accounts/bin/answer.py?answer=185833
However, now the recommended way to log in is using OAuth2. See
https://developers.google.com/appengine/docs/python/tools/uploadinganapp#Python_Password-less_login_with_OAuth2
2015-03-14 09:00:00,000 ERROR appcfg.py:2448 An error occurred processing file '': HTTP Error 401: Unauthorized. Aborting. 
Error 401: --- begin server output ---
Must authenticate first.
--- end server output ---

のようなエラーが出てしまった。


どうやら、アプリケーションパスワードを取得するか、OAuth2 認証を使用しろ、ということらしい(推奨はOAuth2)。


アプリケーションパスワードを取得して使用する場合には Google App Engine Launcher でもそのまま使えるが、OAuth2 認証の方だと Launcher で使用する方法が見つからなかった。コマンド プロンプトから appcfg.py を使用するしかないのかも。

アプリケーションパスワードを取得して使用する場合

エラーメッセージ内で指示されているSign in using App Passwords - Accounts Helpに書かれている通り、アプリ パスワードのページに行き、必要に応じてアプリケーションで使用しているGoogleアカウントでログイン後、アプリ パスワード(16文字)を生成する。
『端末を選択』の項目は使用している端末を選択または入力(『Windows パソコン』等)、『アプリを選択』はその他『(名前を入力)』を選んで適当な名前(『Google App Engine』など)を付ければよい。

表示されたアプリ パスワード(スペースは含まない16文字)は、他人に知られないように覚えるかメモしておく。
「このパスワードを覚えておく必要はないので……」とか書かれているが、覚えておく必要、あるよ……。


取得したアプリ パスワードは、これまで使っていたユーザーパスワードの代わりに、デプロイ時に指定する(emailはそのまま使用する)。

OAuth2 認証を使用する場合

エラーメッセージ内で指示されているPassword-less Login with OAuth2に従って、コマンド プロンプトより、

appcfg.py --oauth2 update myapp/

とする。
myapp/ は、自分のアプリケーションのフォルダを指定。
設定によっては、appcfg.py だけだと実行できないかもしれない。その場合は「python "C:\Program Files (x86)\Google\google_appengine\appcfg.py"」のようにフルパス指定して実行する。
すると、ブラウザで認証画面が開くので、画面の指示に従って認証すれば、デプロイすることが出来る。


いちいち認証手順を行いたくない場合、2回目以降は、

appcfg.py --oauth2_refresh_token=<token> update myapp/

のように token を指定して実行すればよい。


この token は、ユーザーフォルダ(%UserProfile%)にある .appcfg_oauth2_tokens に記述されているので、これをコピーして使う。

type %UserProfile%\.appcfg_oauth2_tokens

として、表示されたデータ(JSON形式)のうち、

...  "refresh_token": "<token>", ... 

のようになっている refresh_token を使用する。

さくらのレンタルサーバ・共有SSLで .htaccess によりSSLのみのアクセス許可を設定する方法

$
0
0

さくらのレンタルサーバで共有SSLを使用する際に、SSLのみのアクセス許可を設定(SSLアクセス強制のため、http://〜 は https://〜 へリダイレクト)するための .htaccess の記述方法を調べてみた。



設定する .htaccess の内容

<IfModule mod_rewrite.c>RewriteEngineOn# --- SSLアクセスでない場合(${ENV:HTTPS} が 'on'でなく、且つ、%{HTTP:X-Sakura-Forwarded-For} が未設定の場合)には#     https://%{SERVER_NAME}%{REQUEST_URI} へリダイレクトRewriteCond %{ENV:HTTPS} !^on$
RewriteCond %{HTTP:X-Sakura-Forwarded-For} ^$
RewriteRule . https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
</IfModule>


なお、WordPress を設置している場合(例として /wordpress/ 下)

<IfModule mod_rewrite.c>RewriteEngineOnRewriteBase /wordpress/

# --- SSLアクセスでない場合(%{ENV:HTTPS} が 'on'でなく、且つ、%{HTTP:X-Sakura-Forwarded-For} が未設定の場合)には#     https://%{SERVER_NAME}%{REQUEST_URI} へリダイレクトRewriteCond %{ENV:HTTPS} !^on$
RewriteCond %{HTTP:X-Sakura-Forwarded-For} ^$
RewriteRule . https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]

RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /wordpress/index.php [L]

</IfModule>

のようにすればよいと思われる。
WordPress の元の .htaccess の RewriteBase 行と最初のRewriteCond 行の間に、SSLアクセス強制用の RewriteCond・RewriteRule を挟み込む。 /wordpress/(二か所)は環境にあわせて書き換えること。


また、wp-config.php の「/* That's all, stop editing! Happy blogging. */(/* 編集が必要なのはここまでです ! WordPress でブログをお楽しみください。 */)」直前に、

if ( isset($_SERVER['HTTP_X_SAKURA_FORWARDED_FOR']) ) {
    $_SERVER['HTTPS'] = 'on';
    $_ENV['HTTPS'] = 'on';
}

/* That's all, stop editing! Happy blogging. */

という記述を追加しておく。

解説(覚え書き)

さくらのレンタルサーバで共有SSLを使用する場合、以下の点に留意する必要がある。

.htaccess からの参照時
  • %{SERVER_PORT} には、SSLかそうでないかによらず '80'が設定される。
    このため、%{SERVER_PORT}ではSSL接続かどうかの判別はできない。
    「RewriteCond %{SERVER_PORT} ^80$」や「RewriteCond %{SERVER_PORT} !^443$」は常に真となるために、リダイレクトループが発生してしまう。
  • SSLアクセス時には通常、 %{ENV:HTTPS} には 'on'が、%{HTTP:X-Sakura-Forwarded-For} にはクライアント(リクエスト元)のIPアドレスが設定される。*1
    ただし、SSLアクセスした場合であっても、mod_rewrite.c の RewriteRule によりリライトされるケースでは、リライト後には %{ENV:HTTPS} が未設定となってしまう。
    RewriteRuleの[R]フラグによりhttps://〜にリダイレクトされた場合には 'on'が設定される。


上記の .htaccess では、リダイレクトするかどうかの判別に、

RewriteCond %{ENV:HTTPS} !^on$

だけでなく、

RewriteCond %{HTTP:X-Sakura-Forwarded-For} ^$

のような条件(%{HTTP:X-Sakura-Forwarded-For}が未設定)を設定している。


これをせずに %{ENV:HTTPS} のみで判定してしまうと、例えば WordPress を設置したサイト上の http://〜/wordpress/year/month/day/ というページ(URL)にアクセスした場合、

URL%{REQUEST_URI}%{ENV:HTTPS}%{HTTP:X-Sakura-Forwarded-For}mod_rewrite.cで実行されるルール結果
1http://〜/wordpress/year/month/day//wordpress/year/month/day/(未設定)(未設定)RewriteRule . https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L][A] リダイレクト
2https://〜/wordpress/year/month/day//wordpress/year/month/day/'on'RewriteRule . /wordpress/index.php [L][B] リライト
3https://〜/wordpress/year/month/day//wordpress/index.php(未設定)RewriteRule . https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L][C] リダイレクト
4https://〜/wordpress/index.php/wordpress/index.php'on'RewriteRule ^index\.php$ - [L][D](このまま)

のように、意図しないURLの PATH の書き換えが発生してしまう。
このため、[C] (3→4)のリダイレクトを発生させないように、条件を追加している。
むしろ「RewriteCond %{ENV:HTTPS} !^on$」の方は無くても現状では動作する。

PHP からの参照時
  • SSLアクセス時には、$_SERVER['HTTP_X_SAKURA_FORWARDED_FOR'] および $_ENV['HTTP_X_SAKURA_FORWARDED_FOR'] にはクライアント(リクエスト元)のIPアドレスが設定される。
  • SSLアクセスした場合であっても、mod_rewrite.c の RewriteRule によりリライトされるケースでは、$_SERVER['HTTPS'] と $_ENV['HTTPS'] が設定されない。
    RewriteRuleの[R]フラグによりhttps://〜にリダイレクトされた場合には 'on'が設定される。


WordPress 等では、SSL 接続かどうかを $_SERVER['HTTPS'] もしくは $_ENV['HTTPS'] の状態で判別している。
このため、上記のように $_SERVER['HTTP_X_SAKURA_FORWARDED_FOR'] が設定されているかどうかで SSL かどうかを判別し、SSL の場合には $_SERVER['HTTPS'] および $_ENV['HTTPS'] に 'on'を設定するような処理を追加してやる必要がある。

*1:将来的にさくら側で仕様変更が行われると、%{HTTP:X-Sakura-Forwarded-For}による判別が出来なくなる可能性はある。


歌詞検索サービスの歌詞(テキスト)コピー禁止手法について調べてみた

$
0
0

動画投稿(共有)サイトやブログ等への歌詞掲載が実施しやすくなりつつある一方で、歌詞検索サービス等ではまだ歌詞(テキスト)のコピー禁止措置が取られているところが大半の模様。
このコピー禁止のための手法について、幾つかの歌詞検索サービスで調べてみた(対象はPC向けサービスのみ)。
おまけで、解除用のブックマークレットも試作してみた
その後、ユーザースクリプト化してみた



JASRAC による個人ブログ等における歌詞掲載利用許諾の概要

恥ずかしながら知らなかったのだが、個人ブログ等への歌詞掲載について、JASRAC では2012年末より、サービス運営事業者が JASRAC と許諾契約を締結することで、ユーザーが個別に許諾を得ることなく歌詞の掲載が出来るようになっている模様。

そこで、動画投稿(共有)サービスにおいてユーザーがJASRAC管理楽曲をアップロードする行為をサービス運営事業者に許諾することで動画投稿(共有)サービスにおけるJASRAC管理楽曲の適正な利用を推進している事例にならって、ユーザーが開設するブログ等でJASRAC管理楽曲の歌詞を掲載利用することにつき、ユーザーに替わってサービス運営事業者に許諾する際の条件を定めた次第です。なお今回の措置は非商用配信における歌詞掲載利用を対象としたものであり、大量の歌詞を掲載する歌詞閲覧サービスや広告料収入を得るなどの目的で行う配信利用は除かれます

ブログサービス等の運営事業者に対し、個人ブログ等における歌詞掲載利用を許諾することについて

太字は引用者修正。

JASRAC と利用許諾契約を締結しているUGC(User-Generated Contents)サービス(動画投稿(共有)サイト・ブログサイト等)のリストも公表されている。

動画投稿(共有)サイトやブログサービス等のUGC(User-Generated Contents)サービスでJASRAC管理楽曲を利用されることについて、一般ユーザーの皆さまからのお問い合わせが多いことから皆さまの利便性を考慮し、JASRACと利用許諾契約を締結しているUGCサービスのリストを公表します。


JASRACと利用許諾契約を締結している以下のサービスでは、一般ユーザーの皆さまが個別にJASRACへ利用許諾手続きを行なわなくともJASRAC管理楽曲を利用したUGC(動画・歌詞)をアップロードすることが可能です。

利用許諾契約を締結しているUGCサービスリストの公表について

つまり、アメーバやSeesaa、Yahoo!、ライブドア等のブログを使っている人は、個別に許諾を得ることなく、自分のブログに歌詞をアップロードできるということ(大量掲載・広告料収入目的等の利用は不可)。
あれ、はてな は……?


歌詞検索サービスのコピー禁止状況

とりあえず、『歌詞 検索』で検索をかけてみて、現時点で表示されるもののうち、上から5つのサービスについて調べてみた。


歌詞(テキスト)のコピー禁止手法としては、以下のようなものが使用されている模様。

  • テキスト選択無効化
  • コンテキストメニュー無効化(いわゆる右クリック禁止)
  • 歌詞部分の非テキスト化(FlashやCanvasによる表示、画像化など)

各サービス毎のコピー禁止手法一覧

サービス名テキスト選択無効化コンテキストメニュー無効化FlashCanvas画像備考
歌詞検索サービス 歌ネット画像はSVG形式
うたまっぷ 歌詞を無料で検索表示IE11等ではFlash使用
歌詞検索サービス 歌詞GET
歌詞ナビ 無料歌詞検索サービス
歌詞検索J-Lyric.net

コピー解禁用ユーザースクリプト(Greasemonkey / Tampermonkey)[2015/07/07追記]

下記のブックマークレットを集約してユーザースクリプト化・対象サービスも追加。

【歌詞解禁(KashiKaikin)】 歌詞検索サービスの歌詞テキストコピーを可能に

Greasemonkey / Tampermonkey が入っていれば ↑ をクリックすることでインストール可。
furyutei/KashiKaikin: 【歌詞解禁】 歌詞検索サービスの歌詞テキストコピーを可能に

コピー解禁用ブックマークレット(Hatena::Let

コピー禁止手法を調べたついでに、解除方法についても検討し、ブックマークレットを試作。
今のところ、上記のいずれのサービスでも、ユーザー側でブックマークレットを実行すれば、歌詞テキストのコピーが可能になる。

■ 集約版(2015.07.08 追記: 下の各々のブックマークレットの機能をひとつに集約したもの・ユーザースクリプト版と同等)

歌詞解禁(KashiKaikin) - Hatena::Let




※以下は旧バージョン。特に理由がないかぎり、↑の集約版の使用を推奨。

コピィ・ライター(CopieWriter) - はてなコピィもどきのバナーを作成可能なサービスを作ってみた

$
0
0

はてなコピィのように、テキストを配置してバナーを作成でき、途中で保存/再開も可能なサービスを作ってみました。

http://furyu.nazo.cc/CopieWriter/

CopieWriter: コピィ・ライター

GitHub のリポジトリはこちら
サービスと言いつつ、ZIPをダウンロード・解凍したフォルダの index.html を開けば、ローカルでも動作します。

画面サンプル

http://furyu.nazo.cc/CopieWriter/?setting=samples/%E3%81%AF%E3%81%A6%E3%81%AA%E3%82%B3%E3%83%94%E3%82%A3%E3%82%82%E3%81%A9%E3%81%8D.json

特徴

長所
  • JavaScript だけで動作している(クライアントサイドだけの処理で、サーバーとの通信は行わない)ため、比較的さくさく動作する。
  • フレーズ数の上限は設けていない(ただし、多すぎると重くなる)。
  • 途中保存して中断(設定をダウンロード)や再開(設定の読み込み)が可能。
  • 設定ファイル(JSON形式)内の値を編集すれば、バナーの大きさやフォントも変更可能。
短所
  • サーバーサイドの処理は一切ないため、はてなコピィのような一覧ページやリンクページといったものは自動では作れない。
  • はてなコピィとのデータ上の互換性はない。
  • 同じく、操作性も異なるので、慣れるまで若干とまどうかも。
  • ブラウザによって出力結果が異なったり、うまく動作しない可能性あり。
    基本、PC版のブラウザのみ対応。IE11・Chrome・Firefox・Operaの最新版であれば多分動作する。ただしSafariでは多分うまく動作しない。

経緯

はてなコピィはテキストを自由に配置してバナーを作れるということで、お気に入りのサービスです。
最近はごぶさたしているものの、これまでも結構な数のコピィを作成しています


ですが、作成途中の保存は出来なかったりフレーズ数の制限によって、しばしば涙を飲みました。*1


以前から、いつの日かこれらを解消できたらなぁ……と思っていましたが、昨日ふと
「『テキストを配置してバナーをつくり保存する』くらいの機能なら、モダンブラウザ*2なら canvas なりを使えば、クライアントサイドのみで実現できるのではないか?」
と思い立ち、そのまま勢いで作ってみたものです。

*1:「いや、そもそもアドバンスモードでお絵かきするのは、本来の使い方じゃないんんじゃ?」という意見は聞きません

*2:そろそろ死語?

SVGでテキストの縦位置(baseline)を調整する方法を調べてみた

$
0
0

SVGで、テキストの縦位置(baseline)を揃える処理を書こうとしてはまったので、覚え書き。

経緯

コピィ・ライターを作成していてふと、
「あれ? 基本的にテキストを配置してバナーを作るものだし、SVGと相性良いんじゃ? 設定ファイルを JSON で書き出しているところをちょっといじれば、SVG で書き出すこともできるようになるかも?」
と思い立ったので、処理を追加してみたところ、テキストの baseline を揃えるところで苦労したというもの。
そもそも、SVGをいじるのはこれが初めてなので、誤解をしているところはあるかも……変なところがあればご指摘願いたい。

どこではまったか? 「え……またIEかよっ!」

HTML5 Canvas の場合、textBaseline プロパティを指定すればテキストの baseline が指定できていた。
同じようなものが SVG でも無いか探してみると、text 要素等で指定できる dominant-baseline プロパティがこれに相当するようだ。

HTML5 Canvas と SVG のテキストの baseline の対応(今回対象としたもののみ)
baseline(基底線)Canvas
(textBaselineプロパティ)
SVG
(dominant-baselineプロパティ)
The top of the em squaretoptext-before-edge
The middle of the em squaremiddlecentral
The bottom of the em squarebottomtext-after-edge

em square=文字の構造的な大きさを表す四角形、EM box・em quad 等とも。

■参考

textBaseline プロパティ - Canvasリファレンス - HTML5.JP
svg要素の基本的な使い方まとめ


それで、実際やってみたところ……

のように、IE では効いていないように思われた。


それで調べてみると、確かにサポートされていないようだ。

IE9 Mode, IE10 Mode, IE11 Mode, and EdgeHTML Mode (All
Versions)

The dominant-baseline attribute is not supported.

[MS-SVG]: [SVG11] Section 10.9.2, Baseline alignment properties

ではどうするか?

とりあえず、IE でなんとかする方法を探してみたところ、

The specification defines central like that:


central


This identifies a computed baseline
that is at the center of the EM box.

We can take an EM box of known font size and measure its bounding box to compute the center.

internet explorer 9 - How to center SVG text vertically in IE9 - Stack Overflow

とあり、具体的なソースコードが書かれている。


どうやら、SVG中の script 要素にて、EM box の座標と大きさを元に central 相当の位置を決めて、transform 属性にて位置を調整する、ということらしい。

  • SVG 中の text 要素に指定した座標を (Tx, Ty)
  • 実際に描画された当該 text 要素の EM box(外枠) の左上の座標を (Rx, Ry)、高さを Rh


とすると、

text-before-edge 相当位置Ry + (Ty - Ry)
central 相当位置Ry + ( (Ty - Ry) - (Rh / 2) )
text-after-edge 相当位置Ry + ( (Ty - Ry) - Rh )

になると思われる。


transform 属性には、

translate(<tx> [<ty>])
tx, tyによる 並進を指定する。
<ty>が与えられていない場合、 0 とみなされる。
座標系, 変換, 単位 – SVG 1.1 (第2版)

のような変換定義を指定してやればテキストの移動が可能なので、例えば central の場合には
tx = 0, ty = (Ty - Ry) - (Rh / 2)
を指定してやればよい。
tx, tyは、EM box左上端からの相対位置なので注意。


コピィ・ライターでは、具体的には、以下のようなスクリプトを SVG 内に挿入した。

var useragent = window.navigator.userAgent.toLowerCase();
if (useragent.indexOf('msie') < 0 && useragent.indexOf('trident') < 0) {return; // IE 以外は何もしない}window.onload = function() {var elm_text_list = document.getElementsByTagName('text');
    for (var ci=0, len = elm_text_list.length; ci < len; ci++) {var elm_text = elm_text_list[ci]
        ,   text_y = parseInt(elm_text.getAttribute('y'))
        ,   rect = elm_text.getBBox()
        ,   rect_y = rect.y
        ,   rect_height = rect.height
        ,   offset_y = (text_y - rect_y) - (rect_height / 2); // central の場合
        
        elm_text.setAttribute('transform', 'translate(0, ' + offset_y + ')');
    }};


なお、IE 以外の場合には、別途 SVG の text 要素に対して dominant-baseline プロパティを設定してあるため、スクリプトでは処理を行わない。

結果

実際に上記手法を適用して作成したSVG画像が、Chrome と IE でどう見えるかを示す。
赤線は基線(SVGのテキスト要素で指定したY座標)、テキストの周囲の四角はEM box(スクリプトで描写)

Google Chrome (バージョン 43.0.2357.132 m)


Windows 7 上で確認した限りでは、Firefox や Opera の最新版でもほぼ同様に見えた。

IE11

注意点

  • SVG ファイルを HTML中に貼り付ける際、IMG要素 を使用すると、SVG内のスクリプトも実行されないため、上記の小細工が適用されない。
    これはCSSのbackground-image等で指定する場合でも同様。
  • OBJECT要素や IFRAME要素で指定してやれば、意図通りに表示される。
    ただし、IFRAMEだと扱いが比較的面倒であるため(CSSで拡大縮小しづらい等)、OBJECT要素を使用するのがベター。

HTML5・A要素(リンク)のdownload属性に関する覚え書き

$
0
0

これもコピィ・ライター作成時に、

  • 動的に生成した画像をボタンをクリックしてダウンロード

する機能を実現する過程で、HTML5・A要素(リンク)の download 属性について調べたことに関する覚え書き。



HTML5・A要素(リンク)の download 属性とは


downloadHTML5


この属性は、ユーザがリンクをクリックするとリソースをローカルファイルとして保存することを促されるように、リソースをダウンロードするために使用されるハイパーリンクであることをページ作者が意図して記述します。属性に値が指定された場合、ユーザがリンクをクリックしたときに開く保存プロンプトの、デフォルトのファイル名として解釈します (もちろん、ユーザは実際にファイルを保存する前にファイル名を変更できます)。使用可能な値に制限はありません (ただし /および \はアンダースコアに変換して、特定のパスヒントを防ぎます) が、多くのファイルシステムには、ファイル名に使用できない文字があることを考慮する必要があります。ブラウザがファイル名を調整するかもしれません。

補足:

  • この属性は、ユーザが簡単に JavaScript を使用するプログラムで生成されたコンテンツ (例えばオンラインのお絵かき Web アプリを使用して描いた画像) をダウンロードするため、blob: URLおよび data: URL とともに使用できます。
  • この属性で指定したものと異なるファイル名を Content-Disposition: HTTP ヘッダで与えている場合は、この属性より HTTP ヘッダが優先します。
  • この属性を指定するとともに Content-Disposition:inlineを指定している場合、Firefox はファイル名と同様に Content-Dispositionを優先しますが、Chrome は download属性を優先します。
  • Firefox 20では、この属性は同一生成元のリソースへのリンクにのみ受け入れられます。
a 要素 - HTML | MDN

とりあえず、Can I use... Support tables for HTML5, CSS3, etcで調べてみると、最新のFirefox・Chrome・Operaはサポートしている模様。
またIEは無いのか……と思ったが、代替手段(window.navigator.msSaveOrOpenBlob())でなんとかなりそうではあった。
Safari? えっと、知らない子ですね……。

実験とブラウザ毎の結果

  • [A] 画像ファイルを Data URL に変換したもの
  • [B] 画像ファイル(サイト内)へのリンク
  • [C] 画像ファイル(外部サイト)へのリンク

三種類の A(リンク)要素を用意し、それぞれに download 属性でファイル名を指定した場合のテストを行った。
IE用には別途、スクリプトで window.navigator.msSaveOrOpenBlob() を使った細工をしてある。

それぞれのリンクをクリック(タップ)した結果、以下のようになった。

Google Chrome
43.0.2357.134 m
Firefox
39.0
Opera
30.0.1835.125
IE11Chrome for Android
43.0.2357.93
[A]
[B]×
[C]××
  • ○:download属性で指定したファイル名でダウンロード
  • △:download属性は無視され、href属性を元にしたファイル名でダウンロード
  • ▲:download属性で指定したファイル名でダウンロード
    IE用に、リンクに onclick トリガを設定し、window.navigator.msSaveOrOpenBlob() を使った細工を入れている
  • ※:別窓(タブ)で画像が開く
    IE用に、リンクに onclick トリガを設定し、XMLHttpRequest で画像を取得させ、エラーが発生したら別窓(タブ)で開く細工を入れている
  • ×:hrefで指定された先にページ遷移

外部サイト上のファイルの場合の動作はセキュリティがらみの制限なのだろうと推測されるが、Chrome for Android でサイト内ファイルへのリンクまでページ遷移してしまうのは謎。なぜ PC 版と動作を変える必要があったのか?

関連する処理など

canvas 要素の Data URL への変換

参考:toDataURL() メソッド - Canvasリファレンス - HTML5.JP

var dataURL = canvas.toDataURL(type); // canvas は HTML5 Canvas の DOM要素、typeは画像の種別('image/png', 'image/jpeg'等)
データの Blob オブジェクトへの変換

参考:Blob - Web API インターフェイス | MDN

var blobObject = new Blob([data], {'type' : mimeType}); // data は元データ、mimeType は元データの MIMEタイプ('image/svg+xml'等)
Data URL の Blob オブジェクトへの変換

参考:Canvas に描いた画像を png などの形式の Blob に変換する方法: Tender Surrender

function make_blob_from_dataurl(dataurl) {if (!dataurl.match(/^data:(.*?);base64,(.*)$/)) {returnnull;
    }var type = RegExp.$1, base64 = RegExp.$2;
    
    var bin = atob(base64), bin_length = bin.length;
    var buffer = new Uint8Array(bin_length);
    for (var ci=0; ci < bin_length; ci++) {
        buffer[ci] = bin.charCodeAt(ci);
    }var blobObject = new Blob([buffer.buffer], {type: type});
    
    return blobObject;
}
ファイルを Blob オブジェクトとして取得

参考:バイナリデータの送信と受信 - XMLHttpRequest | MDN

var xhrObject = new XMLHttpRequest();
xhrObject.open('GET', url, true);
xhrObject.responseType = 'blob';
xhrObject.onload = function(event) {var blobObject = xhrObject.response;
    // ◆ 以下、blobObject を用いた処理を記述};
xhrObject.onerror = function(event) {//※(許可されていない)外部サイトのファイルを取得しようとすると以下のようなエラーが発生(IEの例)//  SEC7118: (取得しようとしたURL) の XMLHttpRequest には Cross Origin Resource Sharing (CORS) が必要です。//  ファイル: (元ファイル)//  SEC7120: 元の http://(元ドメイン) が Access-Control-Allow-Origin ヘッダーに見つかりません。//  ファイル: (元ファイル)//  SCRIPT7002: XMLHttpRequest: ネットワーク エラー 0x80070005, アクセスが拒否されました。window.open(url);   // 次善の策として、例えばポップアップで開く};
xhrObject.send();
Blob オブジェクトの Blob URL への変換

参考:window.URL.createObjectURL - Web API インターフェイス | MDN

var blobURL = (window.URL || window.webkitURL).createObjectURL(blobObject);
Blob オブジェクトをファイルとして保存したり開いたりするイベントの発生(IE10+)

参考:msSaveOrOpenBlob method (Internet Explorer)

window.navigator.msSaveOrOpenBlob(blobObject, filename);

その他気付いたことなど

  • A要素(リンク)の場合、jQuery によってクリックイベントを発生( .click() や .trigger('click'))させても、ダウンロードやページ遷移は行われない。
    これらを発生させたい場合には、MouseEvent を作成するか、DOM の .click() をコールする。

BIGLOBE光ネクスト(大阪)の通信速度調査

$
0
0

今更ながら、「うちはBIGLOBE光ネクスト ファミリー・スーパーハイスピードタイプ隼(NTT西日本エリア・最大1Gbps)の割に、通信(ダウンロード)速度がめっちゃ遅いなぁ……」と気になった。

とりあえず、通信速度を測定してみたり、BIGLOBEサポートに問い合わせてみたりしていたが、

furyu.hatenablog.com

結論から言えば、

ということが判明した。
ISP(BIGLOBE)のバックボーンが利用者に対して十分な帯域が確保できていないということだろう。


「実際にどのくらい遅いのか、また特に通信速度が低下する時間帯はどのあたりか」などをより具体的に知るために、一週間の間、定期的にダウンロード通信速度を計測してみた。その結果を次に示す。
大阪でプロバイダ(ISP)をこれから選択する人・乗り換えを検討している人などの参考になれば幸い。

測定結果(2015/08/05~08/11)

条件

f:id:furyu-tei:20150812015409p:plain
f:id:furyu-tei:20150812015414p:plain

注意事項
  • さくらのレンタルサーバにおける帯域制限の影響は考慮していない。
    ただし傾向としては、04時~08時頃の測定時には頭打ちになっているように思えることから、これはさくら側の帯域制限の影響だと推測している(1TCPセッションにつき、40~50Mbpsあたり、とか?)。
  • ISPは現状BIGLOBEしか契約していないため、他のISPとの定性的な比較はできていない。

今頃になって はてなダイアリーから はてなブログに移行してみたらハマった件

$
0
0

↓のツイートを見て、いいかげん潮時かなぁ、と思い、愛着のある はてなダイアリー から はてなブログ へと移行することにした。


移行自体はhelp.hatenablog.com
を参考にして、特に問題なくできた……と思ったのだが、思わぬ落とし穴が。

  1. ダイアリー→ブログに移行
  2. はてなブログProに加入
  3. 設定→詳細設定→キーワードリンクにて、☑記事にキーワードリンクを付与しないにチェック


の順番でやってしまったため、過去の記事にすべてキーワードリンクが付いた状態になってしまった、という……。
ちなみに、はてなダイアリーPlus にはもともと加入しており、ダイアリー側でキーワードリンクをしないように設定していたが、これは無視される(?)模様。
また、記事を保存しなおせばリンクは消えるらしいが、数百ある記事ひとつひとつ操作するなんてやってられない。


しかたがないので、いったんインポートの取り消しを行い、再度移行手順を踏んだところ、今度はめでたくキーワードリンクが無くなった模様。


というわけで、移行時の正しい順番は、

  1. はてなブログProに加入
  2. 設定→詳細設定→キーワードリンクにて、☑記事にキーワードリンクを付与しないにチェック
  3. ダイアリー→ブログに移行

ということだと思われる。

「ベストエフォートなので、そんなもんです」(要約)……BIGLOBE光ネクスト(大阪)の通信速度問題をサポートに問い合わせた結果

$
0
0

「自宅で利用している、BIGLOBE光ネクスト ファミリー・スーパーハイスピードタイプ隼(NTT西日本エリア・最大1Gbps)が遅い!」ということを具体的に示すため、実際に一週間測定を行った結果をfuryu.hatenablog.com
のような記事にまとめたわけだが、そこに至るきっかけとなった、BIGLOBEサポートとのやりとりを記録しておく。

まぁ、結論から言えば

速度についてはベストエフォート型サービスとなるためお客様のご利用環境、回線の混雑状況などにより通信速度が変化する場合があります。

という、木で鼻をくくったような回答だったわけだが。

この「ベストエフォート」という言葉、プロバイダ(ISP)は便利に使い過ぎだろう。「最善の努力」しているの、ほんとに?

通信事業者のインターネット回線品質がベストエフォート型を標榜する場合、網の能力を超えたトラフィックが入力された場合に超過分が捨てられる仕組みを意味することが多いが、それは同時に同料金を支払っている契約者の中で大きく異なるサービスが提供される結果になるため、契約履行の公平性を失ったサービス提供が消費者トラブルの要因となることがある。いわゆるブロードバンド接続などに関連して、プロバイダー事業者などが無責任範囲を恣意的に拡大解釈し、「通信事業者がいかなる意味でも品質に関する義務を負わないこと」と解して顧客に対して回線品質の劣化や提供サービスの上げ底化を弁護する行為が典型である。

ベストエフォート - Wikipedia

まさにこの通りで、“最大1Gbps”をうたい文句にしている通信サービスが、「その数百分の一程度しか出ない時間帯が恒常的に存在する」状態というのは、そう簡単に納得してもらえるとは思えないのだけれども。

弊社としても速度が出にくい時があることは確認しており、解消できるよう努めてまいります

という言が本当であることを願う。


BIGLOBEサポートとのやりとり(要約)

サポートへ問い合わせ(2015/08/03)

フレッツ(NTN)網内回線速度と、BIGLOBE(ISP)経由の速度の乖離が大きいが、

  • 原因としてはなにが考えられるか?
  • 改善する方法はあるか?

■フレッツ測定サイト

シングル計測90~120Mbps程度
マルチ計測300Mbps~400Mbps程度

■BIGLOBEサイト上の測定ツール
あなたの回線の速度を計測してみよう:BIGLOBE会員サポート

実効速度10~26Mbps程度

NTT回線の場合は、フレッツ・スクウェアでも回線速度を計測できます。
一般に、上の通信速度測定は、フレッツ・スクウェアとは計測方法が異なるため、フレッツ・スクウェアで計測した速度より20~30%低くなります。

http://support.biglobe.ne.jp/faq/speed/sokutei.html

とあるが、20~30%の低下に収まらない。

サポートからの情報提送付依頼(2015/08/03)

BIGLOBE網に問題がないか確認するので、下記情報を返信して欲しい。

<1> tracert/ipconfig/allの実施


<2> 通信速度の測定/IPアドレスの確認
◆通信速度測定サイトでの測定netspeed.studio-radish.com
◆NTTでの測定結果
◆IPアドレスの確認(ルータ・グローバル側)


<3> ご利用環境の確認
◆パソコン環境
◆問題発生時の詳細

なお、当方の質問に対する具体的な回答はなし。

サポートへ情報の送付(2015/08/04)

依頼された情報に、私見も添えて回答。

<1> tracert/ipconfig/allの実施
◆ tracert

> tracert -4 /d www.biglobe.ne.jp

を、時間帯を変えて五回測定した結果を送付。
[私見]
いずれも13ホップで同一のルート・RTTは時間帯によるバラつき(12~21ms)も許容範囲と思う。

◆ ipconfig/all
ipconfig /all の結果、および、ルータ上の接続情報も付記。


<2> 通信速度の測定/IPアドレスの確認
通信速度測定サイトでの測定
※測定サーバー:大阪-新町

時刻19:1021:1823:0625:0530:10
下り回線速度10.47Mbps5.494Mbps2.588Mbps11.52Mbps23.25Mbps

※測定サーバー:東京-WebARENA

時刻19:1221:2023:1125:0430:12
下り回線速度37.31Mbps5.360Mbps2.379Mbps25.93Mbps43.49Mbps

[私見]

  • 大阪<東京の傾向あり(理由不明)。
  • 19時台・25時(1時)台・30時(6時)台と、21時台・23時台とを比較すると後者の速度が大阪・東京共に大幅に落ち込んでいる。輻輳か?
  • 最も安定した(測定品質の高い)データは30時(6時)台のものだが、それでも
    大阪:~23Mbps・東京:~44Mbps
    程度であり、後述のNTTの同時間帯(シングル計測)
    IPv4:~126Mbps・IPv6:~120Mbps
    と比較すると、20~30%程しか出ておらず、サイト上の情報(20~30%程度の低下)とは大きく乖離している。

NTTでの測定結果
フレッツ速度測定 (IPv4) サイト

時刻18:5121:1723:1525:0830:15
シングル123.60Mbps121.90Mbps121.69Mbps125.45Mbps125.80Mbps
マルチ503.19Mbps423.14Mbps392.34Mbps455.11Mbps426.67Mbps

フレッツ速度測定サイト(IPv6・大阪)

時刻18:5521:1523:1625:0630:13
シングル118.31Mbps116.10Mbps119.98Mbps92.00Mbps119.98Mbps
マルチ348.30Mbps415.42Mbps357.42Mbps327.16Mbps395.37Mbps

[私見]

  • 通信速度測定サイトの結果と比較して、数倍~10倍以上速いという結果になっていることから、BIGLOBE(ISP)網側に問題があるのではないか、という見解。
  • 時間帯による差異は、通信速度測定サイトの測定結果ほどには、大きくない。フレッツ(NTN)網内は比較的安定していると思われる。

◆IPアドレスの確認(ルータ・グローバル側)
※先方から指定されたURLにアクセスし、取得したIPアドレスを送付。


<3> ご利用環境の確認
◆パソコン環境
※自分のPC環境(Windows7)の詳細な情報を送付。

◆問題発生時の詳細
※開通時から一般の測定サイトの結果は通常時10~40Mbps 遅延時2~15Mbps程度の速度であった、今回NTTフレッツ測定結果とも大きな乖離があることが判明した旨付記。

サポートからの回答(2015/08/06)

  • BIGLOBE網内を確認し、該当回線で遅延の要因となりうる工事/障害等はなし。
  • 時間帯によっては利用者(トラフィック)増加による速度が出にくい状態を確認。
  • ベストエフォート型サービスのため、回線の混雑状況により通信速度が変化する場合がある。
  • 回線を切断→再接続により、変化する場合があるので試してほしい。

サポートへの質問(2015/08/06)

[1] NTT の回線との速度乖離について
そもそもの質問は、
「NTTの速度結果と御社ISPでの測定結果の乖離が酷いが、どうしてか?」
というもの(前回送った測定結果でもこれが裏付けられている)。
これに関して納得のいく説明をして欲しい。

[2] 再接続しての測定結果
再接続を試みたが、改善されない(むしろ測定結果は悪くなった)。

[3] 通信速度の変化について

  • ベストエフォート型といえど、時間帯によっては ~3Mbps と、光回線とは思えない速度になってしまうのは納得しがたいので、将来的に改善されていくことを期待。
  • 独自に定期的に取得した測定結果をサイトに掲載する予定なので了承願う。

サポートからの回答(2015/08/10)

[1] NTT の回線との速度乖離について
フレッツの速度測定サイトでは、

  • インターネット上の測定サイトとは異なり、インターネット上に出ておらず、フレッツ網内のみの測定。
  • 回線の混雑状態含め、通常の測定サイトと比べて影響を受けにくい。

このため、良い結果が出る。

また、フレッツの速度測定サイトとインターネット上の速度測定サイトで計測した数値が離れていたとしても、先日回答したようにベストエフォート型のサービスとなるため、そのようなことはありうる。

[2] 再接続しての測定結果
改善される可能性があったため、案内した。

[3] 通信速度の変化について
WEBページ上への掲載・公開は、BIGLOBEとして止めることはできない。

サポートへの質問と要望(2015/08/10)

[1] NTT の回線との速度乖離について
ご回答いただいた内容(フレッツの測定サイトとインターネット上の測定サイトの環境の違い等)については理解している。
繰り返すが、あなたの回線の速度を計測してみよう:BIGLOBE会員サポートで、

一般に、上の通信速度測定は、フレッツ・スクウェアとは計測方法が異なるため、フレッツ・スクウェアで計測した速度より20~30%低くなります。

となっている、この「20~30%低くなる」というのは

  • ISP(インターネット・バックボーン)を経由することによる影響を受けることを前提にした上で(考慮に入れたうえで)、その程度の差が出る

という記述だと解釈していたが、違うのか。
「20~30%低くなる」という数値は、具体的にどのような環境で測定されることを想定しているのか教えて欲しい。

[3] 通信速度の変化について
それでは、データ取得が完了したら、サイト上にアップする。

いくら「ベストエフォート」という言葉で説明されても、満足のいく速度とはとても言えないため、特に夜間の極端な速度低下が解消されるよう願う。

また、ISP契約前に確認できるよう、お試し期間を設けるか、地域・時間帯毎の典型的な実効通信速度を参照できるようなページが必要ではないか。ご検討願う。

サポートからの回答(2015/08/11)

[1] NTT の回線との速度乖離について
20%~30%という数値は、ISPを経由しインターネットへ接続することにより影響を受けることを考慮したうえでの目安。
時間帯やご利用者数、トラフィックの混雑状況により速度は変化するため、想定していた以上に数値が悪くなることはある。

BIGLOBEとしても速度が出にくい時があることは確認しており、解消できるよう努めていくが、現時点では案内できる情報は持ち合わせていないので、ご了承願いたい。

[3] 通信速度の変化について
速度の確認ページについては、現時点において該当するページは用意しておらず予定もない。いち意見として担当へ報告した。


ワイモバイル(Y!mobile)のサポートは、ほんとに使えないな(嘆息)

$
0
0

自社のサイトで案内している最新ソフトウェアwww.ymobile.jp
が、具体的にどういうものなのかも、把握していないらしい。

経緯

Stagefright 脆弱性が話題になっていたので

自分の所持しているワイモバイルの Nexus 5 (EM01L) は SMS/MMS 対応だったこともあり、ワイモバイルのサポートに 2015/07/30 に問い合わせを行った。

OSにAndroidを採用しているスマートフォンにおいて、深刻な脆弱性が存在する、という記事を見かけました。
http://japanese.engadget.com/2015/07/27/android-95-mms/
・動画再生エンジンの脆弱性であるため、メディアファイル読み込みの時点で、リモートからのアプリ権限での任意コード実行が可能となる。
・経路の一つとして、MMSをGoogleハングアウトで受信した場合は受信した瞬間にコードが実行されうる。
ということのようで、特にMMSをサポートしている御社のAndroid端末においては危険性が高いものだと思われます。

この脆弱性について、
1. 現時点で、対策等はなされていますでしょうか?
2. ユーザー側での暫定的な対処方法などはありますでしょうか?
3. 今後の対策スケジュール等はどのようになっていますでしょうか?
お手数ではありますが、ご回答いただけますよう、お願いいたします。

すると、まず 7/30 に返信があり、

  • 現在確認中のため、詳細についてわかりかねる
  • 現時点において対処方法などの情報はない
  • メーカーへ確認し、回答が出次第連絡する

という内容。

さらに、8/1にそれぞれ違う方から返信があったのだが、これも似たようなもので(内部で連携していない?)

  • Androidの脆弱性につきましては、現在詳細を確認中
  • 端末メーカーへの確認したところ、現時点においては各社ともセキュリティリスクが発生する脆弱性である認識がある旨の回答
  • セキュリティパッチの提供時期等に関しては明確な回答は得られていない
  • 現在、メーカーと協力し、順次対策を講じる準備を進めており、対策が準備出来たら、ソフトウェア更新などの形でお客さまへお知らせ
  • ユーザサイドでの暫定的な対処についても、具体的、断定的な対処が出来かねる状況

という回答。

結局、連絡待ちだと認識したので、とりあえずハングアウトでMMSを自動的には開かないように設定して待つことにした。

そうこうしているうちに、案内が

2015/08/06付で、ワイモバイルのサイト上にwww.ymobile.jp
のようなお知らせが掲載された。
ただし、サポートからの連絡はない。

更新内容 セキュリティおよび動作安定性の向上

Nexus 5 (EM01L)をご利用のお客さまへ ~最新ソフトウェア配信のお知らせ~ | ワイモバイル(Y!mobile)

となっていたため、おそらくStagefrightがらみだろうと、ビルド番号「LMY48I」をキーに調べてみると、

LMY48I08/05/2015Patch for critical security vulnerability ('Stagefright')
Find and update the software version on your Google Nexus 5

ということなので、間違いなさそう。配信を待つことに。

配信されてきたところで、再度問い合わせを投げてみたところ……

2015/08/12 の早朝に、うちの Nexus 5 にも LMY48I が配信されてきたので、この機会に再度ワイモバイルに問い合わせをしてみた(抜粋)。

先日、Android の深刻な脆弱性(Stagefright)に関して質問させていただきました。
その後、カスタマーセンター ○○様、△△様からご回答があり、セキュリティパッチ等の対処方法が判明次第ご連絡をいただける、とのことでしたが、その後どうなりましたでしょうか。

http://www.ymobile.jp/info/2015/15080602.html
には、2015年8月6日付で、「セキュリティおよび動作安定性の向上」のソフトウェア配信のご案内があり、また、今朝方当方の Nexus 5 にも同ソフトウェア(ビルド番号「LMY48I」)が配信されたようですが、これで上記の脆弱性についても対応されたものという認識で宜しいでしょうか。


なお、もし上記ソフトウェア配信で解消されているにせよ、当方の最初の問い合わせから2週間弱・サイト上へのご案内の掲載時(8/6)からでも6日も経つ段階で当方になんのご連絡も頂いていないというのは、御社のサポート体制としては疑問に感じてしまいますので、できれば改善していただきたいと思います。

すると、こういう返事が……(抜粋)

弊社ホームページにて、ご案内しております最新ソフトウェア更新内容といたしましては、「セキュリティおよび動作安定性の向上」となります。
こちらはGoogleからの直接提供となりますので、詳細の内容はわかりかねます。
お手数をおかけいたしますが、ご確認ご希望の際は、
Googleサポートチームへご相談くださいますようお願いいたします。

◇Googleサポートチーム 
 0120?950?065(通話料無料) 
 9:00?18:00 (無休)

××さまからのご指摘・ご意見は真摯に受け止め、貴重なご意見として承り、
担当部署に上申させていただき、今後同様のトラブルが起こりませんようサービス向上に努めてまいります。
ご迷惑をおかけいたしましたことを重ねてお詫び申し上げます。

「なにが配信されるかよく知らないけれど、とりあえず案内だけしとくね。詳細知りたかったら自分で Google に確認してね!」
ってことだよなぁ、どう読んでみても……雑すぎないか?

というか、問い合わせがあった段階で、サポート側で Google に確認するなりの対応すら、しないということだろうか?
前にも機種変更時に関して問い合わせてみたら要領を得なかったりNexus5 のコンパス機能についてワイモバイルに問い合わせたら Google に丸投げされた経験があるのだけれど、お客さま窓口として機能していないよなぁ、これ……呆れてしまう。
一方、Google の窓口の対応は感じがよくて丁寧なので、相対的に評価が上がるのだけれど。

Radish Network Speed Testing の通信速度測定結果を用いて、プロバイダごとの傾向を調べてみた

$
0
0

BIGLOBEからの乗り換えを検討するにあたり、現時点での通信速度に関して、プロバイダ(ISP)毎のおおまかな傾向などがわかるかと、netspeed.studio-radish.com
蓄積されている測定結果をあたってみた。

集計方法

みんなの測定結果 - Radish Network Speed Testing -より、各絞り込み条件における三ヶ月間(2015/05/14~08/13)の測定データを取得し(1頁表示件数は100件固定)、時間帯での傾向を捉えやすいように、測定時刻毎の下り通信速度をプロットした。
これらのデータは株式会社Studio Radish様によりクリエイティブ・コモンズ「表示-継承ライセンス」として公開されており、これをもとに集計した下記のグラフについてもに準ずるものとする。
データの取得には、後述のブックマークレットを使用した。

グラフの縦軸は、均等にすると値の差が大きくなりすぎて判り難いため、対数目盛にしてある(下限1Mbps・上限1Gbpsとみなし、実測1Mbps未満は1Mbps、1Gbps以上は1Gbpsとしてプロット)。

プロバイダごとの傾向

測定サーバ評価回線種別測定地
すべてすべて光ファイバ(FTTH)・NTTフレッツ・100M超指定なし

の条件で、プロバイダのみ変更して測定。

データの数が多いものから順に、以下に示す。

ブロードバンド回線事業者の加入件数調査(2015年3月末時点) - 株式会社 MM総研を見ると、2015年3月末時点でのFTTH契約数シェアは
OCN>Yahoo!BB>BIGLOBE>So-net>plala>eo>au one net>@nifty
となっており、当然ながら加入者が多いところは測定データも多い傾向がある。

■ OCN

service.ocn.ne.jp
f:id:furyu-tei:20150814191140p:plain

■ Yahoo! BB

bbpromo.yahoo.co.jp
f:id:furyu-tei:20150814191150p:plain

■ ぷらら

www.plala.or.jp
f:id:furyu-tei:20150814191154p:plain

■ @nifty

setsuzoku.nifty.com
f:id:furyu-tei:20150814191205p:plain

■ BB.excite

bb.excite.co.jp
f:id:furyu-tei:20150814191209p:plain

傾向
  • いずれの場合にも(ベストエフォートであるためやむを得ないとはいえ)通信速度のばらつきが非常に大きい。
    個人レベルでの「○○は速いよ(遅いよ)」という話は参考程度にとどめておく方が無難かも知れない。自分の地域で快適かどうかは運次第か、と感じる。
  • 一般的な傾向として、21~25時の時間帯は特に(利用者が集中することによる輻輳を反映してか)低速を示すデータ数が増加している。
  • 輻輳の発生する時間帯であっても、十分高速に通信できている方も一定数存在する(全国のデータなので同じ地域・時間帯であっても差が極端に出ているのかどうかはこれだけではわからないが)。
  • @niftyとASAHIネットは、輻輳時間帯でも低速を示すデータの割合が少なく、比較的余裕があるように思える。
    取得できたサンプル数が十分とは言えないため、断言できるものではないが。

本来なら、測定地でフィルタをかけて自分の地域の傾向を知りたいところだが、そうなると現状では十分なサンプル数が取れない。
例えば、上記のOCNのデータに「神奈川県」でフィルタをかけると、
f:id:furyu-tei:20150816005316p:plain
のような分布になるため、
OCN 光ネクスト(神奈川)の速度問題について
で述べられている拡張工事による品質改善が功を奏している、という結論に短絡したくなるが、サンプル数が少なく、輻輳時間帯のデータがあまり無いこともあり、確かなことは言えない。


回線種別(通信事業者)の違いによる傾向

通信網の違いも気になってきたので、ついでに調べてみる。
住んでいるところの関係で、事実上変更できないのだが。

測定サーバ評価回線種別プロバイダ測定地
すべてすべて光ファイバ(FTTH)・100M超指定なし指定なし

の条件で、回線種別のキャリアのみを変えて測定。

データ数の多い物から順に、以下に示す。

■ NTT フレッツ

flets.com
flets-w.com
f:id:furyu-tei:20150814195716p:plain

■ au ひかり

www.au.kddi.com
f:id:furyu-tei:20150814195810p:plain

■ K-OPTI.com eo光ネット

eonet.jp
f:id:furyu-tei:20150814195822p:plain

■ So-net NURO光

www.nuro.jp
f:id:furyu-tei:20150814195826p:plain

傾向
  • NTT フレッツ以外のサービスは全般的に比較的中~高速域のデータが多いし、夜間の輻輳も今のところは目立ったものではなさそうなので(NURO光は若干多い?)、通信速度のみに着目する場合、自宅が対応しているのであれば乗り換えを検討する価値はありそう。
  • NTT フレッツは(当然ながら)上記のプロバイダの結果をそのまま重ね合わせた傾向となっている。加入者が圧倒的に多く、その分輻輳も発生しやすいということか。
    自分の経験や知人の話、ネット上の口コミ等をみても、往々にして(プロバイダを介さない)フレッツ網自体の速度は十分、という場合が多いようだし、プロバイダにがんばってもらうしかない……。

付録:Radish Network Speed Testingの測定データを CSV 形式でダウンロードするブックマークレット

みんなの測定結果 - Radish Network Speed Testing -のデータ取得には、以下のブックマークレットを使用。

bookmarklet:Radish Network Speed Testing の測定結果をダウンロード

Radish Network Speed Testing の測定結果をダウンロード - Hatena::Let
使用方法

  1. みんなの測定結果 - Radish Network Speed Testing -で、1頁表示件数を設定(推奨:100・後述)。
  2. 絞り込み条件を設定し、検索。
  3. ブックマークレットを実行(取得データ数がカウントされていく)。
  4. データが取得し終わると、CSVファイルがダウンロード可能となるリンクができ、自動的にダウンロード開始。
    ただし、HTML5・A要素(リンク)のdownload属性がサポートされているブラウザとIE10以降のみ。Safari等はNG。


[2015/08/17] [検索]ボタンを押す手順および1頁表示件数を設定する手順を省略(取得時の1頁表示件数は100固定に)。

  1. みんなの測定結果 - Radish Network Speed Testing -で、絞り込み条件を設定([検索]ボタンを押す必要はない)。
  2. ブックマークレットを実行し、基準日と期間を入力(データの取得が開始され、取得データ数がカウントされていく)。
  3. データが取得し終わると、CSVファイルがダウンロード可能となるリンクができ、自動的にダウンロード開始。
    ただし、HTML5・A要素(リンク)のdownload属性がサポートされているブラウザとIE10以降のみ。Safari等はNG。

CSVファイルはBOM付のUTF-8形式になっている。
【参考】

ブラウザだけで Excel 向け日本語 CSV ファイルを作る方法 - do_akiの徒然想記

Windows版Excelだと文字化けせずに開けるはず。Mac版はNGらしい。

みんなの測定結果 - Radish Network Speed Testing -では1頁表示件数により得られるデータ数が異なる

例えば、1頁表示件数を 100 にした場合のデータ数は、1 にしてさかのぼって取得したデータと比較すると、かなり少なくなる。
この件を株式会社Studio Radish様に問い合わせたところ、

  • 同一のユーザーによるデータは、1ページの中で最初のデータのみを代表として表示(グループ化)。
    当該ユーザーのその他のデータには、"この人の測定履歴(件数)"で表示可能)。
    非常にアクティブな(測定登録回数の多い)ユーザーがいると、多様な環境での結果を比較する上で妨げとなるため。
  • グループ化は 1ページ内でのみ実施され、ページが変わると再度最初のデータのみが表示される。
    時系列での比較のため。

という仕様になっているためとのこと。

今回の記事でも、なるべく多様な環境でのデータを取得したかったため、グループ化が最大の効果を得られるように、1頁表示件数を 100 にして取得している。
また、1頁表示件数が少ないとその分取得ページ数が多くなり、サーバーに負荷をかけてしまう、という理由もある。

BIGLOBE光ネクスト(大阪)の通信速度調査 (2015/08/12~18)

$
0
0

承前。furyu.hatenablog.com

測定結果(2015/08/12~08/18)

f:id:furyu-tei:20150819204144p:plain
前回

  • さくらのレンタルサーバにおける帯域制限の影響は考慮していない。
    ただし傾向としては、04時~08時頃の測定時には頭打ちになっているように思えることから、これはさくら側の帯域制限の影響だと推測している(1TCPセッションにつき、40~50Mbpsあたり、とか?)。

ということで、比較として、

  • Google App Engine(GAE) 上に、同様に20MBのファイルを設置
  • GAE→さくらレンタルサーバ、GAE→自宅のそれぞれの転送速度も、10分毎に記録

してみた。

これを見ると、

  • ISPによる制限がないGAE→さくらでは、大体50~70Mbpsくらいで推移しており、一日の間で大きな変化はない(一週間の中間値は59Mbpsくらい*1)。
  • 同じ GAE からダウンロードしていても、GAE→自宅はGAE→さくらと比較して一部時間帯を除いて速度が明確に遅いことから、ISPがボトルネックとなっているのは明らか。
  • GAE→自宅、さくら→自宅はだいたい同じような傾向を示している。
  • 02時~09時頃は GAE→自宅がさくら→自宅を明確に上回っていることから、さくらのレンタルサーバ側の速度制限(上限:40~50Mbps)はやはり存在する模様。
  • ↑以外の、さくら→自宅が頭打ちになっていない時間帯では、GAE→自宅(RTT~40ms)よりもさくら→自宅(RTT~20ms)の方が多少転送速度が高い傾向にある。

*1:少し不思議なのは、Quotas - App Engine — Google Cloud Platformによると Free Limit だと1GB/日まで・最大56MB/分、となっているところ。(20MB×24×6)×2~5.3GBで、一日分も転送レートも上回っているのだけれども、静的ファイルだからか?

【覚書】Google Fusion Tables を使えるようにする手順

$
0
0

データベースと地図とのお手軽な連携方法を調べていて、Google Fusion Tables と Google Maps の組み合わせが使えないかなあ、と思ったので、試してみることに。
……が、実は前提となる Google Drive 自体をほぼ使ったことが無かったこともあって、とりあえずテーブルを作成する状態まで持ってくるのにも少々とまどったため、忘れないうちにメモ。

Google ドライブに Google Fusion Tables のアプリを追加(接続)(初回のみ)

Googleドライブのマイドライブから、
[新規] → その他 → +アプリを追加
とたどって、
f:id:furyu-tei:20150819211106p:plain
By Google から
f:id:furyu-tei:20150819211111p:plain
Fusion Tables を探し出し、
f:id:furyu-tei:20150819211114p:plain
接続する。
f:id:furyu-tei:20150819211118p:plain
この手順は一度実施するだけで良い。


テーブルの作成

Googleドライブのマイドライブから、
[新規] → その他 → Google Fusion Tables
を選択し、
f:id:furyu-tei:20150819211122p:plain

のいずれかを選択して[Next]を押すと、
f:id:furyu-tei:20150819211125p:plain
テーブルが作成される。
f:id:furyu-tei:20150819211130p:plain

【付記】Two column location の設定方法

Edit → Change columns
にて、カラムを追加・削除したり、名前や型(Type)等を編集したりできる。
f:id:furyu-tei:20150819211134p:plain

カラムの Type で "Location"を選んだ場合には、地名や住所、緯度・経度の組み合わせ(カンマ区切り)などを入れることができる(これは Map の方にも反映される)。
このとき、緯度・経度しか使用しない場合には、「□ Two column location」にチェックを入れて、緯度(Latitude)、経度(Longitude)として使用するカラム名をそれぞれ指定すればよいのだが、最初これを行おうと、Latitude カラムを追加してみると、
f:id:furyu-tei:20150819211139p:plain
Type を Location に変更しても、「□ Two column location」が選択できない(灰色表示)。

いろいろ試してみたところ、先に Longitude に該当するカラムを Type = Number で作成してから、
f:id:furyu-tei:20150819211149p:plain
一旦[Save]し、再び、Edit → Change columns から開くと、
f:id:furyu-tei:20150819211154p:plain
今度は選択できるようになっているので、チェックし、Latitude/Longitudeにそれぞれ対応するカラム名を選択して(ついでに、不要になったLocationカラムは削除して)、再度[Save]する。


このようにカラムを設定してから、実際に緯度・経度を指定したデータ(行)を作成してみると、
f:id:furyu-tei:20150819211158p:plain
"Map of Location"タブで、当該データがプロットされているのを確認できる。
f:id:furyu-tei:20150819211203p:plain


【覚書】Google Fusion Tables に Google Apps Script でアクセスする手順

$
0
0

ひとまず Google Fusion Tables が使えるようになったが、何らかのプログラムからアクセスする方法を調べないと……ということで、Google Apps Scriptなるもの(実はこれも初めていじる)で試してみる。

Google ドライブに Google Fusion Tables のアプリを追加(接続)(初回のみ)

Googleドライブのマイドライブから、
[新規] → その他 → +アプリを追加
とたどって、
f:id:furyu-tei:20150819211106p:plain
By Google から
f:id:furyu-tei:20150819211111p:plain
Google Apps Script を探し出し、
f:id:furyu-tei:20150819211607p:plain
f:id:furyu-tei:20150819211616p:plain
接続する。
f:id:furyu-tei:20150819211619p:plain
この手順は一度実施するだけで良い。


Google Apps Scriptのスクリプトを作成し、Fusion Tables にアクセスできるよう設定

Googleドライブのマイドライブから、
[新規] → その他 → Google Apps Script
と選択し、
f:id:furyu-tei:20150819211624p:plain
「空のプロジェクト」を選んで[閉じる]を押すと、
f:id:furyu-tei:20150819211629p:plain
プロジェクトが作成される。

ここで、メニューの
リソース → Google の拡張サービス...
を選ぶと、
f:id:furyu-tei:20150819211640p:plain
プロジェクト名を決めていないときはここで尋ねられるので、適当に名前をつけて[OK]を押す。
f:id:furyu-tei:20150819211645p:plain
Google の拡張サービスの中から、Fusion Tables を探して、
f:id:furyu-tei:20150819211649p:plain
右側の□をクリックし、ON(緑)の状態にする。
f:id:furyu-tei:20150819211653p:plain
ここで、[OK]はまだ押さずに、続けて

これらのサービスは Google デベロッパー コンソールでも有効になっている必要があります。

のリンクをクリックし、Google Developers Consoleを開く。
すると、APIと認証 → API の API ライブラリが開いているはずなので、「Fusion Tables API」を探し、
f:id:furyu-tei:20150819211658p:plain
「Fusion Tables API」をクリックした画面で、[APIを有効にする]ボタンを押す。
f:id:furyu-tei:20150819211702p:plain
その後、Google Apps Scriptの画面に戻ると、そのスクリプトでは Fusion Tables API が使用できるようになる。

簡単なスクリプトの実行

Googleドキュメント上の Fusion Tables のテーブルにアクセスして、行内容を表示するだけのサンプルスクリプト。

var tableId = 'your-table-id';

function getRows(request) {var sql = 'SELECT * FROM ' + tableId + ' LIMIT 10';
  
  var result = FusionTables.Query.sqlGet(sql);
  for (var row_number=0; row_number < result.rows.length; row_number++) {var columns = [];
    for (var column_number=0; column_number < result.columns.length; column_number++) {
      columns.push(result.columns[column_number] + '=' + result.rows[row_number][column_number]);
    }
    Logger.log(columns.join(', '));
  }}

ここで、"your-table-id"の部分には、自分で作成した Fusion Tables のテーブルの画面右上にある[Share]ボタンを押して表示される共有リンク
f:id:furyu-tei:20150819211724p:plain
の、"……?docid=~"の~部分をコピーして貼り付ける。

これを実行すると、
f:id:furyu-tei:20150819211707p:plain
承認を求められるので、[続行]を押し、
f:id:furyu-tei:20150819211712p:plain
許可のリクエスト画面にて、[承認]を押す。
f:id:furyu-tei:20150819211717p:plain
実行が終わり、メニューから
表示 → ログ
を選んで、
f:id:furyu-tei:20150819211720p:plain
実行結果が表示されていれば、無事 Fusion Tables のテーブルへのアクセスが成功している。
f:id:furyu-tei:20150819211728p:plain

Viewing all 92 articles
Browse latest View live