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

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

$
0
0

Google Fusion Tables の更新は、実際には、自前のLinuxサーバー等から自動的に行うことを考えているため、まずは Linux 端末上から Fusion Tables にアクセスできる方法を調べる必要がある。
この場合、Linux 端末側は、OAuth 2.0 クライアントとして Fusion Tables API を使用することになるらしい。developers.google.com
で公開されている各プログラミング言語用のライブラリを用いることで、アクセスできるのだと思われる。
とりあえず、ある程度使い慣れている Python 2.7 によるアクセスを行うことを試みた。
いろいろと調べつつ、手探りで試してとりあえずアクセスは出来たが、これが正しい方法なのかどうかは自信がない。もっとスマートなやり方がありそうな気がするが……。

OAuth 2.0 クライアントID&シークレットの取得

Google Developers Consoleを開き、Fusion Tables へのアクセス用に、新しいプロジェクトを作成する。
f:id:furyu-tei:20150819212036p:plain
f:id:furyu-tei:20150819212043p:plain
f:id:furyu-tei:20150819212048p:plain


作成したプロジェクトを開き、
f:id:furyu-tei:20150819212051p:plain
左のメニューの
APIと認証 → API
から、Fusion Table API を選んで
f:id:furyu-tei:20150819212054p:plain
[APIを有効にする]を押す。
f:id:furyu-tei:20150819212100p:plain


次に、同じく
APIと認証 → 認証情報
から、
[認証情報を追加] → OAuth 2.0 クライアント ID
を選択し、
f:id:furyu-tei:20150819212111p:plain
[同意画面を設定]ボタンを押して
f:id:furyu-tei:20150819212117p:plain
サービス名を適当につけて入力し、[保存]を押す。
f:id:furyu-tei:20150819212123p:plain


「アプリケーションの種類」は「○ その他」を選択し、[作成]ボタンを押すと、
f:id:furyu-tei:20150819212128p:plain
OAuth 2.0 のクライアントID及びクライアントシークレットが発行されるので、[OK]を押す。
これは後からでも確認できるため、特にコピーしておく必要などはない。
f:id:furyu-tei:20150819212142p:plain

OAuth 2.0 クライアントID情報は、右側にあるダウンロードボタンにて、JSON形式でダウンロードできる。
f:id:furyu-tei:20150819212153p:plain


Linux 端末(OAuth 2.0 クライアント)側の準備

Installation  |  API Client Library for Python  |  Google Developers
に従い、

sudo pip install--upgrade google-api-python-client

のようにして、google-api-python-client をインストールしておく。


Python で Fusion Tables にアクセスするサンプルコード(sample_fusiontables.py)

上記でダウンロードしたJSON(OAuth 2.0 クライアントID情報)ファイルを、
client_secrets.json
という名前にして同じディレクトリに配置した状態で実行すると、アクセス可能な Fusion Tables の最初のテーブルIDを取得し、当該テーブルの行列を表示するサンプル。

# -*- coding: utf-8 -*-# OAuth 2.0 for Devices (sample code)# https://github.com/google/oauth2client/blob/master/samples/oauth2_for_devices.py# Using OAuth 2.0 for Devices# https://developers.google.com/accounts/docs/OAuth2ForDevices# Fusion Tables REST API# https://developers.google.com/fusiontables/docs/v2/reference/from __future__ import print_function

import sys
import json
import time
import datetime
import httplib2
import traceback
from pprint import pprint
from oauth2client import client
from googleapiclient.discovery import build

defget_credentials(scopes, client_secret_file = None, credential_file_in = None, credential_file_out = None): #{defload_credential_file(credential_file_in):
    ifnot credential_file_in:
      returnNonetry:
      fp = open(credential_file_in, 'rb')
      credentials = client.OAuth2Credentials.new_from_json(fp.read())
      fp.close()
      if credential_file_in != credential_file_out:
        save_credential_file(credential_file_out, credentials)
      return credentials
    exceptException, error:
      #print(traceback.format_exc())passreturnNonedefsave_credential_file(credential_file_out, credentials):
    ifnot credential_file_out:
      return
    fp = open(credential_file_out, 'wb')
    fp.write(credentials.to_json())
    fp.close()
  
  credentials = load_credential_file(credential_file_in)
  if credentials:
    return credentials
  
  client_secrets = json.load(open(client_secret_file, 'rb'))
  client_id = client_secrets['installed']['client_id']
  client_secret = client_secrets['installed']['client_secret']
  
  whilenot credentials:
    flow = client.OAuth2WebServerFlow(client_id, client_secret, ''.join(scopes))
    
    # Step 1: get user code and verification URL# https://developers.google.com/accounts/docs/OAuth2ForDevices#obtainingacode
    flow_info = flow.step1_get_device_and_user_codes()
    
    print('Verification URL: {0}'.format(flow_info.verification_url));
    print('User code: {0}'.format(flow_info.user_code));
    
    user_code_expiry = flow_info.user_code_expiry
    interval = flow_info.interval
    
    while datetime.datetime.now() < user_code_expiry:
      print('\r{0:>4} seconds remaining'.format( (user_code_expiry - datetime.datetime.now()).seconds ), end = '')
      sys.stdout.flush()
      # Step 2: get credentials# https://developers.google.com/accounts/docs/OAuth2ForDevices#obtainingatokentry:
        credentials = flow.step2_exchange(device_flow_info = flow_info)
        if credentials:
          breakexceptException, error:
        #print(traceback.format_exc())
        credentials = None
      time.sleep(interval)
    print('')
  
  save_credential_file(credential_file_out, credentials)
  
  return credentials
#} // end of get_credentials()if __name__ == '__main__': #{# https://console.developers.google.com/project/<project name>/apiui/credential (Download JSON)
  CLIENT_SECRET_FILE = 'client_secrets.json'# Allowed scopes# https://developers.google.com/identity/protocols/OAuth2ForDevices#allowedscopes
  SCOPES = ('https://www.googleapis.com/auth/fusiontables',)
  
  CREDENTIAL_FILE = 'credentials.json'
  
  credentials = get_credentials(
    client_secret_file = CLIENT_SECRET_FILE,
    scopes = SCOPES,
    credential_file_in = CREDENTIAL_FILE,
    credential_file_out = CREDENTIAL_FILE,
  )
  
  print('Access token: {0}'.format(credentials.access_token))
  print('Refresh token: {0}'.format(credentials.refresh_token))
  
  # Get Fusion Tables service# https://developers.google.com/accounts/docs/OAuth2ForDevices#callinganapi
  fusiontables = build(
    serviceName = 'fusiontables',
    version = 'v2',
    http = credentials.authorize( httplib2.Http() ),
  )
  
  # Fusion Tables REST API# https://developers.google.com/fusiontables/docs/v2/reference/# https://developers.google.com/fusiontables/docs/v2/reference/#Table
  Table = fusiontables.table()
  
  # https://developers.google.com/fusiontables/docs/v2/reference/#Column
  Column = fusiontables.column()
  
  # https://developers.google.com/fusiontables/docs/v2/reference/#Template
  Template = fusiontables.template()
  
  # https://developers.google.com/fusiontables/docs/v2/reference/#Style
  Style = fusiontables.style()
  
  # https://developers.google.com/fusiontables/docs/v2/reference/#Query
  Query = fusiontables.query()
  
  # https://developers.google.com/fusiontables/docs/v2/reference/#Task
  Task = fusiontables.task()
  
  # ===== Samplesprint('***** Tables')
  table_list = Table.list().execute()
  pprint(table_list)
  tableId = table_list['items'][0]['tableId']
  
  print('***** Columns & Rows')
  rows = Query.sql(
    sql = 'SELECT * FROM {0}'.format(tableId)
  ).execute()
  pprint(rows)

Shell 上から、

$ ls
client_secrets.json  sample_fusiontables.py
$ python ./sample_fusiontables.py

のように実行すると、初回には、標準出力上に

Verification URL: https://www.google.com/device
User Code: XXXX-XXXX
xxxx seconds remaining

のように表示されて待ち状態に入る。

手動で「Verification URL」に示された URL にブラウザでアクセスすると、(場合によってはアカウント選択・ログイン画面の後で)端末に表示されるコードの入力を促されるため、「User Code」で示されたコードを入力し、[続行]を押す。
f:id:furyu-tei:20150819212158p:plain
Fusion Tables の管理の許可を求められるため、[承認する]を押す。
f:id:furyu-tei:20150819212207p:plain


すると、しばらくしてサンプルプログラム側が承認を認識し(Access token・Refresh tokenを取得し)、結果が表示される。


なお、Access token・Refresh tokenを含む情報は、カレントディレクトリ上の
credentials.json
というファイルに書き込まれ、

$ ls
client_secrets.json  credentials.json  sample_fusiontables.py

次回実行時にはこれを読み込んで使用するため、基本的には、上記のブラウザによる手動の承認手順は初回のみでよい。
この動作の詳細は、上記ソースコード中の get_credentials() 関数の定義及び呼び出し箇所を参照のこと。


Google ChromeにてDOMノード追加に異様に時間がかかる現象が発生して悩む→拡張機能が原因だった

$
0
0

JavaScriptでページ遷移用のナビゲーションを作っていたのだが、リンクと半角スペース(テキストノード)とを交互に挿入するような実装にしていると、なぜか異様に時間がかかってしまう(数百個程度のノード挿入に、数秒要する)。
どうやら、ナビゲーションのノードがDOMツリー上にあるとこうなるようで、いったんDOMツリーから切り離した状態で作成し、最後にDOMツリーに戻すようにすると、ほとんど時間はかからない。でもなぜ……?


さんざん悩んだが、結局はとある拡張機能が原因だった、というオチ(今回の場合ははちまバスター)。
もっと早くに、シークレットウィンドウで調べておくべきだった……。
【追記】なお、はちまバスターは早々に改修された

テスト

function test_add_nodes( options ) {if ( ! options ) {
        options = {}}var parent_node = ( options.parent_node ) ? options.parent_node : document.body,
        before_processing = !! ( options.before_processing ),
        node_number = ( 0 < options.node_number ) ? options.node_number : 300,
        exclude_link = !! ( options.exclude_link ),
        exclude_text = !! ( options.exclude_text );
    
    var container = document.createElement('div'),
        link_node_template = document.createElement('a');
        text_node_template = document.createTextNode('');
        before_time = newDate().getTime();
    
    if ( parent_node && before_processing ) {
        parent_node.insertBefore( container, parent_node.firstChild );
    }for ( var ci=0; ci < node_number; ci++ ) {if ( ! exclude_link ) {var link_node = link_node_template.cloneNode( true );
            link_node.href = '#';
            link_node.innerHTML = ci;
            container.appendChild( link_node );
        }if ( ! exclude_text ) {var text_node = text_node_template.cloneNode( true );
            text_node.textContent = '*';
            container.appendChild( text_node );
        }}if ( parent_node && ( ! before_processing ) ) {
        parent_node.insertBefore( container, parent_node.firstChild );
    }var after_time = newDate().getTime(),
        elapsed_time = ( after_time - before_time );
    
    return elapsed_time;
}function log_result( test_name, elapsed_time ) {
	console.log( test_name + ' : ' + ( elapsed_time / 1000.0) + ' sec' );
}// DIV要素にリンクやテキストノードを一通り追加してから、DOMツリーに挿入
log_result( 'after , text only', test_add_nodes( { before_processing : false, exclude_link : true, exclude_text : false} ) );
log_result( 'after , link only', test_add_nodes( { before_processing : false, exclude_link : false, exclude_text : true} ) );
log_result( 'after , both     ', test_add_nodes( { before_processing : false, exclude_link : false, exclude_text : false} ) );

// DIV要素をDOMツリーに予め挿入してから、リンクやテキストノードを追加
log_result( 'before, text only', test_add_nodes( { before_processing : true, exclude_link : true, exclude_text : false} ) );
log_result( 'before, link only', test_add_nodes( { before_processing : true, exclude_link : false, exclude_text : true} ) );
log_result( 'before, both     ', test_add_nodes( { before_processing : true, exclude_link : false, exclude_text : false} ) );
拡張機能有効時
after , text only : 0.003 sec
after , link only : 0.057 sec
after , both      : 0.054 sec
before, text only : 0.04 sec
before, link only : 0.04 sec
before, both      : 6.856 sec // これは酷い
拡張機能無効時
after , text only : 0.002 sec
after , link only : 0.005 sec
after , both      : 0.01 sec
before, text only : 0.027 sec
before, link only : 0.045 sec
before, both      : 0.05 sec

気が付いたら jQuery 用の highlight プラグインを書いていた

$
0
0

先日、自分のココログを全文検索するブログパーツ: 暴想の改修を行っていたのだが、furyu.tea-nifty.com
元のスクリプトのハイライト処理だと、TEXTAREA 内まで置換されてしまうのが難点だったため、せっかくなので jQuery を用いて実装してみた。github.com

$.setHighlightColor('yellow'); // .highlight要素に付けるハイライト(背景)色を指定(引数を指定しない場合、デフォルト(#ffcc33)になる)

$('p').highlight('キーワード'); // 全 p 要素内で、"キーワード" というテキストをハイライトする(引数として配列を指定することで、複数のキーワード指定も可能)

$('p').unhighlight(); // 全 p 要素内のハイライトを取り消す

style・script・textarea・iframe・frame 要素内は避けてハイライトするようになっている。
highlight()のオプションはjQuery Highlight Plugin | bartaz @ GitHub互換っぽくなっているはず。

裏話

最初はjq-cocolog_ajax_search.js内にベタ書きしていたのだが、せっかく jQuery 化したことだし、プラグインとして独立させることに。

例によって、ひととおり実装したところで、ふと検索してみると、
highlight: JavaScript text higlighting jQuery plugin
とか、
jQuery Highlight Plugin | bartaz @ GitHub
といったプラグインが見つかったので、オプションは後者のものと互換っぽくしておいた。
すなおに最初から調べて使っておけ、という話。

【覚書】はてなブログのレスポンシブWebデザイン対応

$
0
0

ほんとうに今更ながら、はてなブログはテーマ(テンプレート)によってはレスポンシブWebデザインに対応していることに気付く。
スマートフォンでアクセスする際に「PCのときとURLが変わってしまうのは不便だなー」と思っていたことだし、本ブログも対応してみることに。

手順1:レスポンシブ対応のテーマをインストール

テーマ ストアでレスポンシブ対応のテーマを探してインストール。
なお現状、レスポンシブ対応のテーマを探す機能などはないので、自力で探すしかない。

自分は、たまたま目についたシンプルな

Simple Gray - テーマ ストア - はてなブログ

をインストールしてベースにさせていただいた。


今気が付いたが、レスポンシブ対応テーマを探すには、

はてなブログのレスポンシブデザイン対応のテーマ集24個【随時更新】(スマホでもPCとほぼ同じ表示になるテンプレート) - 広汎性発達障害の女が毒を吐くブログ

の記事が便利そう。

手順2:CSS等の調整

デザイン設定で、CSSを適当に(好みに合わせて)調整。
自分の場合、はてなダイアリーのときに使用していたテーマの色合いが気に入っていたので、それに近い感じにしてみた。

また、ヘッダの下に検索フォームを設置し、画面の横幅が 1150px 以下のときには表示されるようにしておいた。
サイドバーが下に落ちて、検索フォームにアクセスしづらくなったときの代用。

手順3:レスポンシブ(スマートフォン)対応設定

デザインCSS先頭に、

/*  Responsive: yes */

のようなコメントを追加したのち、スマートフォン→詳細設定にて、☑ レスポンシブデザインにチェックを入れる。

参考

レスポンシブデザインのテーマを作成する際の注意点

デザインCSSに Responsive: yes のコメントを入れるのは、忘れやすいので注意。

ZIPファイルに日本語ファイル名が含まれる場合の文字化け予防方法(Windows7, CentOS 6)

$
0
0

他のシステムで作成されたZIPファイルを解凍した際に日本語ファイル名が文字化けする不具合への対処法をいくつか。



Windows7 の場合

標準の状態だと、Shift-JIS(CP932)以外でエンコードされていると、文字化けする。

これまでは

無料圧縮・解凍フリーソフト CubeICE - CubeSoft

などを使うことで対処していたが、日本語ファイル名が UTF-8 でエンコードされているものについては、Windows7・Windows Server 2008 R2 用 Hotfixを適用すれば解消される模様。

File names are corrupted after you decompress a .zip file in Windows 7 or in Windows Server 2008 R2

CentOS 6 の場合(unzip)

CentOS 6 系で yum を使ってインストールできる unzip (CentOS 6.6では現在 unzip-6.0-2.el6_6.x86_64) では、日本語ファイル名には未対応のため、エンコードに関わりなく文字化けしてしまう。

【UTF-8 エンコード時】

$ /usr/bin/unzip -l ./AmazonMusicDownload.zip
Archive:  ./AmazonMusicDownload.zip
  Length      Date    Time    Name
---------  -------------------838181510-11-201501:53   ?????????????(???????????????)/Cherish you/01 - Cherish you.mp3
  909938810-11-201501:53   ?????????????+?????????????????/?????????????+????????????????? ??????????????+??+????????+???????????????/01
- Blooming Lily.mp3
  844741510-11-201501:54   ?????????????+?????????????????/?????????????+????????????????? ??????????????+??+????????+???????????????/03
- ???????????????????????????.mp3
---------                     -------259286183 files

【Shift-JIS エンコード時】

$ /usr/bin/unzip -l ./sjis-sample.zip
Archive:  ./sjis-sample.zip
  Length      Date    Time    Name
---------  -------------------010-11-201510:59   ?????+???????????-????/?????+???????????-???? ?L?????N?^?[?C???[?W?\???O?W/
  909938810-11-201501:53   ?????+???????????-????/?????+???????????-???? ?L?????N?^?[?C???[?W?\???O?W/01 - Blooming Lily.mp3
  844741510-11-201501:54   ?????+???????????-????/?????+???????????-???? ?L?????N?^?[?C???[?W?\???O?W/03 - ?`???X?L?????_???X.mp3010-11-201510:59   ?X?????q??(???????F??)/Cherish you/838181510-11-201501:53   ?X?????q??(???????F??)/Cherish you/01 - Cherish you.mp3---------                     -------259286185 files


そこで、unzip 6.0 Shift-JIS対応版をインストールすることで対応してみることに。

unzip 6.0 Shift-JIS対応版のインストール方法
$ git clone https://github.com/ted-n/unzip.git
$ cd unzip/unzip60
$ make -f unix/Makefile LOCAL_UNZIP="-D_FILE_OFFSET_BITS=64 -DNO_LCHMOD -D_MBCS -DNO_WORKING_ISPRINT" generic_gcc
$ sudo make -f unix/Makefile install

これで、/usr/local/bin 下にパッチの当たった unzip がインストールされる。
一行目を修正("git clone git@github.com:ted-n/unzip.git"としていたが、これは予めSSH Keyの設定が必要なため)

【UTF-8 エンコード時】

$ /usr/local/bin/unzip -l ./AmazonMusicDownload.zip
Archive:  ./AmazonMusicDownload.zip
  Length      Date    Time    Name
---------  -------------------838181510-11-201501:53氷堂美智留(矢作紗友里)/Cherish you/01 - Cherish you.mp3
  909938810-11-201501:53冴えない彼女の育てかた/冴えない彼女の育てかた キャラクターイメージソング集/01 - Blooming Lily.mp3
  844741510-11-201501:54冴えない彼女の育てかた/冴えない彼女の育てかた キャラクターイメージソング集/03 - 饒舌スキャンダラス.mp3
---------                     -------259286183 files

【Shift-JIS エンコード時】

$ /usr/local/bin/unzip -l ./sjis-sample.zip
Archive:  ./sjis-sample.zip
  Length      Date    Time    Name
---------  -------------------010-11-201510:59冴えない彼女の育てかた/冴えない彼女の育てかた キャラクターイメージソング集/
  909938810-11-201501:53冴えない彼女の育てかた/冴えない彼女の育てかた キャラクターイメージソング集/01 - Blooming Lily.mp3
  844741510-11-201501:54冴えない彼女の育てかた/冴えない彼女の育てかた キャラクターイメージソング集/03 - 饒舌スキャンダラス.mp3
        010-11-201510:59氷堂美智留(矢作紗友里)/Cherish you/
  838181510-11-201501:53氷堂美智留(矢作紗友里)/Cherish you/01 - Cherish you.mp3
---------                     -------259286185 files
Python で Shift-JIS エンコードしたファイル名で圧縮する場合の注意

自分はこれまで、Linux(CentOS) 上の Python で日本語ファイル名を含んだ ZIP ファイルを作成する場合でも、Windows で扱いやすくするために Shift-JIS(CP932) でエンコードしたファイル名で圧縮していたのだが、こうして作成したファイルを上記のパッチ済みの unzip で表示すると、なぜか文字化けしてしまった。

【オリジナルの unzip 6.0 使用時】

$ /usr/bin/unzip -l ./test.zip
Archive:  ./test.zip
  Length      Date    Time    Name
---------  -------------------40010-11-201515:57   ???{????f?B???N?g??/???{???t?@?C????.txt
---------                     -------
      4001 file

【パッチ済みの unzip 使用時】

$ /usr/local/bin/unzip -l ./test.zip
Archive:  ./test.zip
  Length      Date    Time    Name
---------  -------------------40010-11-201515:57傔
                                ・fB
                                    Ng
                                      /傔
                                         黎@C
                                             シ.txt
---------                     -------4001 file

調べてみると、どうも ZIP ファイルヘッダの version(ZipInfo.create_system) が 3 (Unix) になっているとこの現象が発生するようなので、これを考慮して Python スクリプトを作成する必要がある模様。
zipfile.py の class ZipInfo の定義を見てみると、sys.platform が 'win32'のときは self.create_system に 0 が、それ以外は 3 がデフォルトで設定されている。

【例】

import czipfile as zipfile
import datetime

zip = zipfile.ZipFile( 'test.zip', 'w' )
timestamp = datetime.datetime.now()
dir_filename = u'日本語のディレクトリ/日本語ファイル名.txt'
content = 'test' * 100

zipinfo = zipfile.ZipInfo(
  filename = dir_filename.encode( 'cp932', 'replace' ),
  date_time = ( timestamp.year, timestamp.month, timestamp.day, timestamp.hour, timestamp.minute, timestamp.second )
)
zipinfo.compress_type = zipfile.ZIP_DEFLATED
zipinfo.create_system = 0# 0 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems), 3 - UNIX (https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT)zip.writestr( zipinfo, content )
zip.close()
$ /usr/local/bin/unzip -l ./test.zip
Archive:  ./test.zip
  Length      Date    Time    Name
---------  -------------------40010-11-201515:59日本語のディレクトリ/日本語ファイル名.txt
---------                     -------4001 file

追記(2015/10/26)

Twitter 原寸びゅー:Twitterの原寸画像を開くGoogle Chrome拡張機能&ユーザースクリプト公開

$
0
0

Web 版公式 Twitter上で、画像を含むツイートの画像を、原寸で開いたり保存したりすることが出来るようになるスクリプトです。
Chrome 拡張機能版(Google Chrome/Opera対応)とユーザースクリプト版(Google Chrome/Firefox/Opera対応)があります。
また、ブックマークレット版なら、Internet Explorer 11でも動作します。
Windows 7 Professional SP1上で、2016/01/16時点にて動作確認。
ソースコードはGitHub上にて公開しています。



動作イメージ

www.youtube.com
デモは Chrome 拡張機能版 0.1.3.200 のものです。
コンテキストメニュー(右クリック)からの保存は、拡張機能版でのみ動作します。

インストール

Chrome 拡張機能版(Google Chrome/Opera対応)

chrome.google.com
より追加。
Operaの場合、あらかじめ
拡張機能「 Download Chrome Extension」 - Opera アドオンを導入しておけば、同様にインストール可能。

ユーザースクリプト(Greasemonkey / Tampermonkey)版(Google Chrome/Firefox/Opera対応)

Firefox+Gresemonkey、Google Chrome+Tampermonkey、あるいは Opera+Tampermonkeyの環境で、

Twitter 原寸びゅー・ユーザースクリプト版(twOpenOriginalImage.user.js)

GitHub - furyutei/twOpenOriginalImage: Twitter 原寸びゅー

をクリックし、指示に従ってインストール。

必要であれば、

Twitter 画像ダウンロードヘルパー(twImageDownloadHelper.user)

GitHub - furyutei/twOpenOriginalImage: Twitter 原寸びゅー

も同様にインストール。
バージョン 0.1.3.0 以降、画像ダウンロードヘルパーの機能は原寸びゅーに吸収したため、画像ダウンロードヘルパーのインストールは必要なくなりました。

ブックマークレット版(Google Chrome/Firefox/Opera/IE11対応)

Twitter 原寸びゅー

Twitter 原寸びゅー - Hatena::Let

使い方

基本的な使用方法

インストール後には、Web 版公式 Twitter上で、画像を含むツイートに対し、[原寸画像]ボタンが追加されるようになります。
ブックマークレット版の場合は、Twitterのタイムラインが表示された状態で、実行(ブックマークレットをクリック)してください。
f:id:furyu-tei:20160115235139j:plain

このボタンをクリックすることで、原寸の画像(URLの後ろに「:orig」がついたもの)を開くことができます。
タイムライン上であれば、[j][k]キーで移動後、[v]キーを押すことで、当該のツイートの画像を開くこともできます*1
デフォルトでは、

  • クリック → ひとつのページにまとめて開く
  • [Alt]+クリック → 複数画像がある場合、各画像毎にページが開く(twitter原寸ボタン互換動作)

となります。
動作を逆にしたい場合、拡張機能版ではオプション設定で変更可能です。
ユーザースクリプト版の場合は、インストール後にソースコードの一部変更が必要になります(「■ パラメータ」のところにある、「DISPLAY_ALL_IN_ONE_PAGE : true」の、true を false に書き換えます)。

f:id:furyu-tei:20160115235144j:plain

また、画像ダウンロードヘルパーが有効な場合*2、[ダウンロード]リンクが付きます。これを押すと、当該画像がダウンロードできます。
この際、ダウンロードするファイル名は、URLが例えば「…….jpg:orig」の場合には、「……-orig.jpg」に変換するようにしています……これまで、ダウンロード後に手動で拡張子を修正するのがわずらわしかったので…。
f:id:furyu-tei:20160116042359p:plain

Chrome 拡張機能版のみの機能

拡張機能版の場合、オプションでデフォルト動作やボタンのテキスト等を変更できます。
f:id:furyu-tei:20160116042345p:plain

また、画像を右クリックしてコンテキストメニューを開くと、直接「原寸画像を保存」もできます*3
この場合も、ダウンロードされるファイル名の拡張子は「…….jpg-orig」→「……-orig.jpg」のように書き換わります。
f:id:furyu-tei:20160202210128j:plain

注意書き

Chrome 拡張機能版で無効化される場合

バージョン:0.1.2.0以降、Twitter 画像ダウンロードヘルパーの機能を追加したため、対象となるドメインが増えています。
以前は twitter.com のみだったものに、pbs.twimg.com を追加。
f:id:furyu-tei:20160116213146p:plain
このため、それより前のバージョンで使用していて自動アップデートされた場合など、要求される権限の変更により、一時的に Google Chrome 側で無効化されてしまう(ツールバーからアイコンが消える)ことがあるようです。

この場合も、拡張機能の画面 chrome://extensions/ (「≡」(右上のハンバーガーメニュー)→「その他のツール(L)」→「拡張機能(E)」)を開き、「Twitter 原寸びゅー」を探して、「□ 有効にする」のチェックボックスにチェックを入れることで、再度有効にすることができます。

[ダウンロード]ボタンが同じ画像に二つ表示されてしまう

Twitter 画像ダウンロードヘルパー(twImageDownloadHelper.user)をインストールしていませんか?
インストールしている場合には、これを削除しておいてください。
バージョン:0.1.3.0以降、拡張機能版・ユーザースクリプト版共に、Twitter 画像ダウンロードヘルパー(twImageDownloadHelper.user)の機能は Twitter 原寸びゅー側に吸収されたため、このスクリプトは不要となりました。

[ダウンロード]ボタンを押すと、タブが閉じられてしまう

リンクの target 属性を無効化する(target="_blank"等となっていても構わずに同一のタブに表示する)ような設定や拡張機能を入れている場合に、[ダウンロード]ボタンを押すと、画像がダウンロードされるとともに、そのタブが閉じてしまうといった現象が発生するようです。

当方の環境では、Firefox 43.0.4 にて、Tab Mix Plus 0.4.2.0 を入れている場合に発生しました。
この場合には、アドオンの設定画面 about:addons(「≡」(右上のハンバーガーメニュー)→「アドオン」)で、
「拡張機能」→(Tab Mix Plusの)[設定]→「リンク」タブ→「☑ ファイルをダウンロードするときに空白タブが開かないようにする」
のチェックを外して[適用]してやれば、タブが閉じられる現象は発生しなくなりました。
その代わりに他の動作で不都合があるかもしれませんが……。

経緯

Twitterの画像は、縮小やトリミングがされていたりサムネイル状態だったりで、見難いことも多いです。
画像のURLの後ろに「:orig」と付けてやれば原寸画像を開くことはできますが、いちいちやるのは面倒で……と思っていたら、便利な拡張機能が公開されていることを知りました。

hogashi 氏(id:hogashi/@)の、
hogashi.hatenablog.com
というものです。

大変便利でしたが、ひとつのツイートに複数の画像がある場合には複数のタブが開いてしまい、ちょっとわずらわしかったため、とりあえずブックマークレット
let.hatelabo.jp
などを作ったりしている内に、興が乗ってしまい、いちから実装してしまった次第です。
なお、ひととおり作って満足してしまったため、今後の更新を行うかどうか怪しいです(汗)。不安な方は
twitter原寸ボタンの方をインストールすることをお勧めします。


*1:2016/02/01・0.1.3.1以降

*2:拡張機能版は0.1.2.0以降・ユーザースクリプト版は0.1.3.0以降。なお、ブックマークレット版では、画像ダウンロードヘルパー機能は未サポート。

*3:2016/02/02・0.1.3.101以降

Google Chromeで、スクリプトが拡張機能として動作しているかどうかを判別するには?

$
0
0

furyu.hatenablog.com
等では、単体でユーザースクリプト(Greasemonkey/Tampermonkey)としても動作するスクリプトを、Google Chrome 拡張機能用として転用している。

このとき、

  • ユーザースクリプトとして動作する際には、スクリプト内で定義したデフォルト値を使用
  • 拡張機能として動作する際には、ユーザーが設定可能なオプション値を優先的に使用

という条件を満たさねばならず、そうすると、スクリプト自身が「今、自分はどちらとして動作しているか」を判別する必要が出てくる。

これをお手軽に知る方法はないか、検索をかけてみたのだけれど、探し方が悪いのか、なかなかしっくりくる方法が見つからない。
そこで、苦肉の策として以下のような方法を用いているのだが、もし読者の方でより簡便な方法をご存知の方がおられれば、ご教授願いたい。

1. manifest.jsonにて、初期化用スクリプトとメインスクリプトを、別々のタイミングで起動

"content_scripts" : [{"matches" : ["https://twitter.com/*"],
        "js" : ["js/init.js"],
        "run_at" : "document_start"},
    {"matches" : ["https://twitter.com/*"],
        "js" : ["js/main.js"],
        "run_at" : "document_end"}],
"background" : {"scripts" : ["js/background.js"]}

例の中の init.js が初期化用(document_start: DOM構築開始時に起動)で、main.js がユーザースクリプトを兼ねたメインスクリプト(document_end: DOM構築完了時に起動)。

なおバックグラウンドスクリプト(background.js)では、chrome.runtime.onMessage.addListener()で設定したリスナーにより、localStorageから取り出したユーザーオプション値を返す処理を定義しておく。

2. 初期化用スクリプト(init.js)内にて、ユーザーが設定したオプション値を取得する関数を定義

window.init_extension = function( callback ) {/* 任意の前処理 */
    chrome.runtime.sendMessage( {/* background.js で規定の処理を呼び出すためのパラメータ */}, function ( response ) {var user_options;
        /* response を解析して、ユーザーオプションを取得する処理 */
        callback( user_options );
    } );
};

background.js に対してchrome.runtime.sendMessage()にてメッセージを送信し、必要なユーザーオプションを取得した上で、コールバック関数に渡してやる関数を定義しておく。

3. メインスクリプト(main.js)内にて、2. の関数が定義されているかどうかで、処理を振り分け

if ( typeofwindow.init_extension == 'function' ) {// 拡張機能として動作window.init_extension( function( user_options ) {
        main( user_options ); // ユーザーオプションを設定} );
}else{// ユーザースクリプトとして動作
    main(); // オプション未指定→デフォルト値を使用}

2. で定義する関数が存在するかどうかにより、

  • 存在する場合: 拡張機能として動作しているとみなして当該関数を呼び出し、ユーザーオプションを取得して使用
  • 存在しない場合: ユーザースクリプトとして動作しているとみなし、デフォルト値を使用

【覚書】クロスドメインな画像を任意のファイル名でダウンロードするためのユーザースクリプトの記述方法

$
0
0

Twitter の原寸画像は、例えば「https://pbs.twimg.com/media/CYhLLnfU0AAbHun.jpg:orig」のようなURLとなっており、これを Windows のブラウザでダウンロードしようとすると、「CYhLLnfU0AAbHun.jpg-orig」のようなおかしな拡張子に変換されて保存されてしまうことがある*1

いちいち拡張子を修正するのが面倒だったため、
furyu.hatenablog.com
では、リンク(A)要素の download 属性で、ちゃんとした拡張子のファイル名(例えば、「CYhLLnfU0AAbHun-orig.jpg」)を指定してやり、リネームの手間を省こうとしたのだが……。
以前、
furyu.hatenablog.com
でも書いたように、クロスドメイン(クロスサイト)に於いては、download属性で指定したファイル名は無視されてしまう。

■例

<ahref="https://pbs.twimg.com/media/CYhLLnfU0AAbHun.jpg:orig" download="<任意のファイル名>.jpg"id="download_link_sample_a">ダウンロードリンク-A</a>

これを何とかするための苦肉の策が以下のもの。
例によって、もっとスマートなやり方があればコメント願う。

ユーザースクリプトのサンプル

Cross-Domainなサイトの画像を任意のファイル名でダウンロードするユーザースクリプトのサンプル

このユーザースクリプトを Greasemonkey や Tampermonkey でインストールしてから、このページをリロードすると、↑の例のところに「ダウンロードリンク-B」というリンクが新たに表示されるはず。
これをクリックすると、「<任意のファイル名>.jpg」なるファイル名で画像がダウンロードできる……はず。
何をやっているかは、下記のソースコードを参照。また、このテスト以外には意味はないスクリプトなので、確認が終わったら削除しておくことを推奨。

// ==UserScript==// @name            sample_download_link// @namespace       http://furyu.hatenablog.com/// @author          furyu// @version         0.1.0.0// @include         http://furyu.hatenablog.com/*// @include         https://pbs.twimg.com/media/*// @description     Cross-Domainなサイトの画像を任意のファイル名でダウンロードするユーザースクリプトのサンプル// ==/UserScript==

( function () {'use strict';

var SCRIPT_NAME = 'SAMPLE_DOWNLOAD_LINK',
    IFRAME_NAME = SCRIPT_NAME + '_download_frame',
    filename = '<任意のファイル名>.jpg',
    current_url = window.location.href;

if ( window !== window.parent ) {if ( window.name != IFRAME_NAME ) {return;
    }// 親 window から呼び出された画像用 IFRAME の処理var image_url = current_url,
        link = document.createElement( 'a' );
    
    link.href = image_url;
    link.download = filename;
    
    document.documentElement.appendChild( link );
    link.click(); // ダウンロード開始return;
}// 親 window の処理var source_image_link = document.querySelector( 'div#download_sample_image_container a#download_link_sample_a' );

if ( ! source_image_link ) {return;
}var download_link = document.createElement( 'a' ),
    image_url = source_image_link.href;

download_link.href = image_url;
download_link.download = filename;
download_link.appendChild( document.createTextNode( 'ダウンロードリンク-B' ) );

download_link.addEventListener( 'click', function ( event ) {// リンクがクリックされたら、name を指定した隠し IFRAME を呼び出すevent.stopPropagation();
    event.preventDefault();
    
    var iframe = document.createElement( 'iframe' ),
        iframe_style = iframe.style;
    
    iframe_style.width = '0';
    iframe_style.height = '0';
    iframe_style.visibility = 'hidden';
    
    iframe.src = image_url;
    iframe.name = IFRAME_NAME;
    
    document.documentElement.appendChild( iframe );
    
    returnfalse;
}, false );

source_image_link.parentNode.appendChild( download_link );

} )()

注意

Google Chrome の拡張機能で上記の手法を使用するためには、manifest.json にて、

"content_scripts" : [{"matches" : ["http://furyu.hatenablog.com/*", "https://pbs.twimg.com/media/*"],
        "js" : ["js/main.js"],
        "run_at" : "document_end",
        "all_frames" : true}]

のように、「 "all_frames" : true 」を指定して、IFRAME 内に対してもスクリプトが動作するように設定しておく必要がある。

*1:Firefoxだと、「CYhLLnfU0AAbHun.jpg orig.jpg」のようになるので、一応 JPEG としては解釈される


【覚書】Chrome拡張機能にて、オプション画面の変更を即座に反映させたい場合

$
0
0

Google Chrome の拡張機能で、オプション画面で変更した内容を即座に反映させたい場合には、何らかの方法でオプション画面(options_page)からスクリプト(content_scripts)が動作しているタブ(tabs)に変更を通知してやる必要があるが、そのやり方の一例。

概要

タブ(tabs)上で動作している contents_script は、オプションが格納される(extension 用の) localStorage を直接参照することはできないため、オプションを取得するためにはbackground スクリプトを介在させる必要がある。

このため、典型的には、

  1. background は、あらかじめメッセージ待ち受け状態にしておく(chrome.runtime.onMessage.addListener())。
  2. contents_script がオプションを取得したいタイミングで、background へメッセージを送信(chrome.runtime.sendMessage())。
  3. background は、contents_script よりメッセージを受信すると、localStorage よりオプション値を読み出して適宜変換後*1、contents_script に返す。

のような作りとなる。

また、オプション画面(options_page)の典型的な作りは、

  1. 開いたタイミングで、localStorage よりオプション値を読み出し、ユーザーにわかりやすい形で表示。
  2. ユーザーの入力に応じて、localStorage にオプション値を書き出し。

のようになっている。

ここに新たに

  1. contents_script 側であらかじめメッセージを受け付けられる状態にしておく(chrome.runtime.onMessage.addListener())。
  2. options_page にて、localStorage にオプション値を書き出したタイミングで、contents_scriptの動作しているタブ(tabs)に対して、メッセージを送信(chrome.tabs.sendMessage())。
  3. contents_script は、options_page よりメッセージを受信すると、background よりオプションを取得する。

のような手順を追加してやることで、オプション画面からの変更が即座にタブ側(contents_script)もに反映されるようになる。
なお、options_page→contents_scriptへメッセージを送信するときに変更したオプション内容も一緒に送信してやれば、backgroundへのオプション問い合わせは省略できる。ただしその場合、options_page側でもオプション値の翻訳(ユーザーの入力値から、contents_scriptで用いる値への変換)を実装する必要があり、やや煩雑になる可能性がある。

サンプル

具体的な実装例は、

github.com

を参照のこと。

注意
  • タブに対するメッセージ送信のために、manifest.json に
    "permissions" : [ "tabs" ]の記述が必要。

経緯

GoogleChrome拡張機能「twitter画像原寸ボタン」ver. 2.0公開 - hogashi.*を入れていると、ときどき、Originalボタンが表示されなくなってしまう現象があり、調べていた
現時点の最新版である、2.0.4でも発生。

状況としては、

  • しばらく(一晩とか)放置しておいたタイムラインにて、新しいツイートを表示すると、[Original]ボタンが表示されなくなっていることがある。
  • 現象発生時、DOM ツリーに変化があるたびにコールされるようになっている関数(main.js 内の start())までは呼び出されているが、オプション設定を読み込むために発行したchrome.runtime.sendMessage()のコールバック関数が呼び出されていないように見える。
  • background.js 側のchrome.runtime.onMessage.addListener()で設定した関数も呼び出されていない(ただし、他タブでタイムラインを表示したところ、正しく呼び出される)。

ということで、sendMessage() コール後のメッセージ送受信処理のどこかで滞ってしまっている可能性が高い。

もし上記推測通りとすると、Chrome の不具合の可能性が高くなってくるため、ユーザー(拡張機能開発者)側で抜本的な対策を取るのは難しいかもしれない。

回避策としては、現状イベント発生(DOMツリー更新や[Enter]キー押下時)のたびにオプション取得(background.js とのメッセージ送受信)処理を実施しているのをやめ、なるべく頻度を減らす、という方向性はどうか?

  1. main.js が起動した直後の一回だけにする(結果として、オプション変更内容の反映はタブのリロード時に行われることとなるので、リアルタイムではなくなる)。
  2. 起動時とオプション画面からの変更時にのみ、実施する。

自作のスクリプト(原寸びゅー等)では手を抜いて基本、1. の方針にしているが、本来は 2. にすべきだろう……では、オプション変更時にどうやって各タブに通知すればよいのか?

という経緯と思考過程があって、記事にまとめてみた次第。

*1:localStorage には文字列しか格納できないため、contents_script が利用しやすい形(連想配列など)に変換してやる必要がある

【覚書】 Twitter の画像サイズの変換など(PNG・JPEG)

$
0
0

Twitter に画像(PNG・JPEG)をアップロードした場合、
https://pbs.twimg.com/media/~.<拡張子>[:サイズ種別]
のように、URLの末尾によってそれぞれ異なるサイズの画像が得られる。

:サイズ種別最大サイズ(*)
:thumb150px×150px
:small680px×680px
(なし)1200px×1200px
:large2048px×2048px
:orig(制限なしか?)

(*) このサイズ内の画像は原寸で取得できるが、それ以上のものは矩形に収まるよう縮小される(:thumbはついては、短辺に合わせてトリミング&リサイズされているものと思われる)。
なお、各種別毎の最大サイズは2016/02/24時点。これまでも何度か変更されている模様。

また、試した範囲では、:orig を除く種別については、アップロードした画像の種別(PNG/JPEG)に関わらず、二種類(PNGおよびJPEG)の画像がそれぞれ作成される模様。
これはURL中の拡張子の部分を、pngにしたものjpgにしたものとをダウンロードして調べた。なお、拡張子をgifにしたものもダウンロードできるが、中身はPNG形式のものと同一の模様。

:orig については、2016/02/24時点で、表示(ダウンロード)できるのは PNG もしくは JPEG のどちらかに限られる(それ以外は 404 not found となる)。

アップロード種別PNG(.png:orig)を表示JPEG(.jpg:orig)を表示
JPEG×
PNG(24bpp)PNG(透明ピクセル無し、もしくは約3MBを超えるもの)×
PNG(32bpp)PNG(透明ピクセル有り、かつ約3MB以下のもの)×

となっている。

24bpp(アルファチャンネル無し)透明ピクセル無しのPNG画像はJPEGに変換されてしまうため、PNG形式のままで表示(ダウンロード)させたい場合は、32bpp(アルファチャンネル有り)に変換透明ピクセルを追加した後にアップロードするのが今のところ解決方法となる。
ただし、32bpp のPNG 画像が :orig を付けて原寸でダウンロードできた場合も、元画像そのものがダウンロードできるわけではなく、Twitter側で変換されたものになる(アップロードしたものとはファイルサイズ等が異なっている)。

既存の画像については、例えばPNG 32bpp変換 | しぇ庫を使って簡単に24bppから32bppへ変換できる(2016/02/27現在、Twitterの仕様変更により、透明ピクセル追加の対応検討中とのこと→2016/02/28に改訂版がリリースされた)。

一般キヨシ関数

$
0
0

完全に乗り遅れてしまい、いまさらそのまま書いても……と思ったけれど、より一般的な問題にしてみたらどうか、と思ってやってみた。

キヨシ関数(ズンドコキヨシ、#kiyoshi関数)とは?

qiita.com

一般キヨシ関数とは?

void general_kiyoshi( phrase_pattern, last_phrase )
第一引数
phrase_pattern
文字列の配列
例:[ "ズン", "ズン", "ズン", "ズン", "ドコ" ]
第二引数
last_phrase
最後に表示する文字列
例:"キ・ヨ・シ!"
戻り値無し
  1. phrase_pattern に含まれる文字列を、ランダムに出力し続ける。
    文字列の出現確率は等しくなるようにする。重複する文字列がある場合、それらは同一とみなす(上記の例の場合、"ズン"が複数個含まれるが、これらは同一とみなし、"ズン"と"ドコ"が同じ確率で出現するようにする)。
  2. phrase_pattern で指定したパターンが現れたら、last_phrase を出力し、終了する。

実装例

Python

GitHub - furyutei/general_kiyoshi: general_kiyoshi(): 一般キヨシ関数

import random
import collections

defgeneral_kiyoshi( phrase_pattern, last_phrase ):
  phrase_pattern = collections.deque( phrase_pattern )
  phrases = list( set( phrase_pattern ) )
  current_phrase_pattern = collections.deque( [], len( phrase_pattern ) )
  
  defrandom_phrase_generator():
    iflen( phrases ) <= 0:
      returnwhileTrue:
      yield random.choice( phrases )
  
  defcheck_phrase_pattern():
    return ( current_phrase_pattern == phrase_pattern )
  
  for phrase in random_phrase_generator():
    print( phrase )
    
    current_phrase_pattern.append( phrase )
    
    if check_phrase_pattern():
      breakprint( last_phrase )


defkiyoshi():
  general_kiyoshi( [ 'ズン', 'ズン', 'ズン', 'ズン', 'ドコ' ], 'キ・ヨ・シ!' )

defcockrobin():
  general_kiyoshi( [ 'パパンがパン', '誰が殺した', 'クックロビン', '誰が殺した', 'クックロビン' ], 'スズメが弓と矢でもって、クックロビンを殺したの' )


kiyoshi()
# :#ズン#ズン#ドコ#ズン#ズン#ズン#ズン#ドコ#キ・ヨ・シ!

cockrobin()
# :#パパンがパン#クックロビン#誰が殺した#誰が殺した#誰が殺した#誰が殺した#パパンがパン#パパンがパン#クックロビン#誰が殺した#誰が殺した#パパンがパン#誰が殺した#クックロビン#誰が殺した#クックロビン#スズメが弓と矢でもって、クックロビンを殺したの
JavaScript
'use strict';

function print() {
    console.log.apply( console, arguments );
}function general_kiyoshi( phrase_pattern, last_phrase ) {var phrases = phrase_pattern.filter( function ( value, index, self ) {return ( self.indexOf( value ) === index );
        } ),
        current_phrase_pattern = newArray( phrase_pattern.length );
    
    function get_random_phrase() {return phrases[ Math.floor( Math.random() * phrases.length ) ];
    }function check_phrase_pattern() {return phrase_pattern.every( function ( value, index, self ) {return ( current_phrase_pattern[ index ] === value );
        } );
    }while ( ! check_phrase_pattern() ) {var phrase = get_random_phrase();
        
        print( phrase );
        
        current_phrase_pattern.shift();
        current_phrase_pattern.push( phrase );
        
    }
    
    print( last_phrase );
}function kiyoshi() {
    general_kiyoshi( ['ズン', 'ズン', 'ズン', 'ズン', 'ドコ'], 'キ・ヨ・シ!' );
}function cockrobin() {
    general_kiyoshi( ['パパンがパン', '誰が殺した', 'クックロビン', '誰が殺した', 'クックロビン'], 'スズメが弓と矢でもって、クックロビンを殺したの' );
}

kiyoshi();
cockrobin();

独り言など

Twitterで、マウスカーソル下のツイートを選択するユーザースクリプト

$
0
0

PCブラウザ版Twitterで、タイムラインを最初はマウスホイールで見ていて、途中からキー操作での移動に変えたいと思った場合、単に[j]キーとか押してしまうと、タイムラインの先頭(一番上・最新のツイート)まで戻されてしまう*1

そこで、現在位置(マウスカーソルのある位置)のツイートを起点に、移動開始出来たら便利かな、と思ったので、そのようなユーザースクリプトを作成してみた。
2016/03/21現在、Google Chrome(Tampermonkey)・Firefox(Greasemonkey)・Opera(Tampermonkey)の最新版にて動作確認済み。

インストール

Firefox+Gresemonkey、Google Chrome+Tampermonkey、あるいは Opera+Tampermonkeyの環境で、

twChangeSelection.user.js

furyutei/twChangeSelection: Twitterで、マウスカーソル下のツイートを選択するユーザースクリプト

をクリックし、指示に従ってインストール。

使い方

タイムライン上の目的のツイートをクリックしてポップアップ表示後に[Esc]で閉じるか、もしくは、[Ctrl]キーを押しながら目的のツイート上にマウスカーソルを動かすと、当該ツイートに(キー操作用の)カーソルが移る(ツイートの枠線に色が付く)ので、あとはそこを起点として [j]キー/[k]キー 等で移動ができるようになる。

独り言など

PCブラウザ版Twitterは、ショートカットキーに対応はしているものの([?]キーを押すと、一覧が表示される)、そもそもあまり需要がないためなのか、結構難があったり、対応がおざなりだったりする気がする。

  • ↑みたいな小細工しなくても、標準の機能で起点を選択できるようになっていて欲しい。
  • 「開いたすべてのツイートを閉じる」([c]キー)は、ツイートがポップアップ表示になってから、意味がなくなっているのではないか?
  • ポップアップ表示時に、[j]/[k]による移動がうまくいかない(返信をうまく辿れない等)。
  • 非表示になっているツイート(プロモーション等)の上にもカーソルが移動してしまう&その後ときどきうまく移動できなくなる。

*1:2016/03/21現在

【覚書】 z-index により手前に来ている透明要素が原因でイベントが発火しないときには、 pointer-events をうまく使う

$
0
0

原寸びゅーで、画像クリック時に原寸画像を開くようにしようとして、ギャラリー表示時にはうまくクリックイベントが発火しないことに気が付いた。

原因は(z-index 指定により)画像の手前に透明な要素が存在したため*1
pointer-eventsの設定を行うことで対処できそうということが分かったので、メモ書き。
なお、pointer-events は IE では IE11 以上でサポート(IE10 以下は未サポート)となる。

サンプル




(A)




(B)




(C)


画像(BUTTON)や枠の部分をクリックしたときの動作に違いがある。

覚え書き

目的として、透明要素(枠の部分・"z-index: 1"が指定されている)のクリックイベントは残しつつ、画像をクリックしたときには別のイベントを発火させたい。

  1. 最初は、単に画像にクリックイベントを設定するだけにしていた(A)。
    ところが、実際には手前に来る透明要素(枠)のイベントしか発火しない(なお、サンプルでは、画像(BUTTON)の CSS に "cursor: pointer"を設定してあるが、これも効いていないのが判る)。
  2. 手前に来る要素の CSS に "pointer-events: none"を設定(B)。
    これで、画像をクリックしたときのイベントは発火するようになったが、逆に手前の透明要素(枠)のイベントが発火しなくなってしまう。
  3. 画像を含む要素の z-index 値を、透明要素(枠)のものより大きくし、かつ、CSS に "pointer-events: none"を設定。また、このままだと、画像のイベントも発火しなくなるため、画像の方には "pointer-events: auto"を設定(C)。
    これで、画像と枠それぞれのイベントが発火するようになった。
HTMLソースコード
<div><divstyle="width: 120px; height: 120px; position: relative; float: left; margin: 5px; background: pink;"><divstyle="width: 100%; height: 100%; position: absolute; top: 0; left: 0; background: rgba( 0, 0, 0, 0 )"><buttonstyle="display: block; width: 50%; height: 50%; position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; font-size: 12px; cursor: pointer;"onclick="alert('画像をクリック')">画像</button></div><divstyle="width: 100%; height: 100%; position: absolute; top: 0; left: 0; background: rgba( 0, 0, 0, 0 ); z-index: 1;"onclick="alert('枠をクリック')">(A)</div></div><divstyle="width: 120px; height: 120px; position: relative; float: left; margin: 5px; background: limegreen;"><divstyle="width: 100%; height: 100%; position: absolute; top: 0; left: 0; background: rgba( 0, 0, 0, 0 )"><buttonstyle="display: block; width: 50%; height: 50%; position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; font-size: 12px; cursor: pointer;"onclick="alert('画像をクリック')">画像</button></div><divstyle="width: 100%; height: 100%; position: absolute; top: 0; left: 0; background: rgba( 0, 0, 0, 0 ); z-index: 1; pointer-events: none;"onclick="alert('枠をクリック')">(B)</div></div><divstyle="width: 120px; height: 120px; position: relative; float: left; margin: 5px; background: lightblue;"><divstyle="width: 100%; height: 100%; position: absolute; top: 0; left: 0; background: rgba( 0, 0, 0, 0 ); z-index: 2; pointer-events: none;"><buttonstyle="display: block; width: 50%; height: 50%; position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; font-size: 12px; cursor: pointer; pointer-events: auto;"onclick="alert('画像をクリック')">画像</button></div><divstyle="width: 100%; height: 100%; position: absolute; top: 0; left: 0; background: rgba( 0, 0, 0, 0 ); z-index: 1;"onclick="alert('枠をクリック')">(C)</div></div><brstyle="clear:both;"></div>

*1:前後移動用のナビで、こちらもクリックイベントが設定されている

TABLE の TD 要素内全てをチェックボックス化したいが……

$
0
0

HTMLのチェックボックス要素(input[type="checkbox"])で表示される□は、閲覧環境によっては小さく表示されてしまい、チェックを入れたり外したりしにくい場合がある。

その場合の対処法として、

  1. チェックボックスそのものをCSSで拡大する(参考:チェックボックスやラジオボタンを大きくする方法: 小粋空間チェックボックスを大きくしたい - Qiita
  2. LABEL 要素を用いて、有効な範囲を拡大する
  3. チェックボックスの代替として、画像+JavaScript 等でなんとかする

といった方法があると思われる。

で、2. の手法でやろうとしたのだが、条件を

  • チェックボックスを、TABLE 内の TD 要素下に置く
  • TD の高さや横幅は不定
  • TD 内部全体を有効範囲としたい
  • チェックボックスそのものは、TD要素の上下左右中央に表示

のように定めたところ、どうやって CSS を書けばよいのかわからなくて、悩んでしまった。




td{position: relative;
    }label{display: block;
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        background: lime;
    }input[type="checkbox"]{display: block; /* 無くてもよい模様 */position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        margin: auto;
    }

どうにも、冗長な書き方をしている気がしてならない。

もっとシンプルな記述方法を知りたい……ご存知の方はご教授いただきたい。

【覚書】 Twitterのタイムラインなどで、表示位置(スクロール位置)を固定したまま、ポップアップ表示させる方法

$
0
0

Twitter 原寸びゅーで、原寸画像をオーバーレイ(ポップアップ)表示させる際、タイムラインのスクロール位置はそのままにするためにはまっていたので、覚え書き。
つくづく、CSS は苦手やわぁ……。

ヘッダ及び表示範囲に相当する要素を、position: fixed を指定することで固定する、ところまではすぐ思いついたのだが、原寸画像が表示範囲よりも大きい場合にどうすればよいのかが当初は思い付かなかった。

苦肉の策として、オーバーレイ表示時には、

  • 表示範囲を、position: absolute で BODY の上端に合わせる
  • タイムラインについては、ネガティブマージンを設定して、見かけ上、オーバーレイ表示したときと同じ位置のものが表示されるようにする

のようにして対処していた(0.1.5.500まで)

しかし、どうしても無理があったので、パフォーマンスが悪く(反応がにぶく)なってしまった。

その後、

  • 表示範囲は、position: fixed; top: 0; top: 0; right: 0; bottom: 0; left: 0; overflow-y: auto; を指定
  • BODY には、overflow-y: hidden; を指定

のようにしておけば、原寸画像を表示している範囲だけをスクロールさせることが出来ることに気付き、対応。

パフォーマンスについても改善されたように思われる。

なお、このようにした場合、表示範囲の操作(スクロール)に関しては(ブラウザでBODY(HTML)の標準的なキー操作として用意されている)[Space][Home][End]等のキーによる移動は効かなくなるので、自前で用意する必要があった。


【覚書】 Windows 7 → 10 アップグレード時に引っかかったところなど(EPSON NJ5700E)

$
0
0

勢いで、メインPCである EPSON NJ5700E を Windows 7 から Windows 10 へとアップグレードしてしまった。
(いくつか問題はあるものの)ひとまず Windows 7 のときとほぼ遜色なく使えるようにはなってきたが、そこに至るまでに引っかかったりつまづいたりした箇所について、覚え書き。



■ アップグレード前

アップグレード抑制のために使っていたアプリケーション

Windows10へ勝手にアップグレードさせないツール「GWX Control Panel」の使い方経由で知った、GWX Control Panelというものを使用していた。
アップグレードするためには、基本、抑制時と逆の操作をして(Informationの"No."を"Yes."になるようにして)、おなじみの Windows 10 アップグレードアイコンを出してやればよい。
なお、これは Windows 10 にアップグレードした際には不要なものであるが、Windows 10 上でも律儀にタスクトレイに常駐してくれるので、アンインストールしておくことを推奨。
Windows 10 上からでもアンインストールは可能だった。

■ アップグレード中

C: ドライブの空き容量に注意

NJ5700E の場合

<Cドライブの残容量が10GBよりも少ない場合>
USBフラッシュメモリーなどのドライブとして認識のできるUSB外付けメディア(16GB以上)が必要です。事前にCドライブの残容量をご確認ください。

[FAQ番号:023135]NJ5700E : Windows 10アップグレード技術情報|FAQ Search|エプソンダイレクト

という注意書きがあった。

結構空き容量がギリギリだったのだが、なんとかやり繰りして約15GB程の空きを確保。

なお、C: ドライブの空き容量不足でも、
少ない空き領域のハード ディスク/ストレージ のパソコンやタブレットを Windows 10 にアップグレードする方法 - Windows - Microsoft
にあるように、大きめの外部ドライブ等があれば、そちらを利用してインストールできる模様。

ただ、むしろ

  • アップグレードで使用した外部ストレージには以前の Windows に戻すために必要なファイルの一部または全部が保存されます。
少ない空き領域のハード ディスク/ストレージ のパソコンやタブレットを Windows 10 にアップグレードする方法 - Windows - Microsoft

ということだったら、空き容量が足りる場合であっても、外部ストレージにこれらの(前の Windows に戻すのに必要な)ファイルを保存したいところなのだが、そういう選択肢が出るかと思っていたら、特に何もなくインストールが進められてしまった。
現在 C: ドライブに、前の Windows に戻さなければ不要なファイルが 24GB 強ほど居座っているので……むしろ、わざと空き容量を確保せずに外部に押し出したほうがよかったのかも……?

プライバシー設定に注意

アップグレード自体、基本的には指示に従っていけばよいのだが、


のように、プライバシー設定に関して気になる方は、インストール途中で「詳細のカスタマイズ」から機能をOFFにしておいたほうがよいかも。
インストール後でも、設定→プライバシー画面から選択可能ではある。

■ アップグレード後に発生したが、解決した問題

アップグレード(Windows 10 のインストール)自体は、特に大きな問題もなく終了した。

ここでは、アップグレード後に各種設定やアプリケーションの動作を確認して行く中で、ひっかかったところなどを書いておく。

なにはともあれ、Caps Lock → Ctrl

自宅だけに限れば Realforce91UDK-G を使っているから切り替えスイッチ使えばいい話なのだけれど、ノートPCを単独で使う場合も多いので、Caps Lock → Ctrl 切り替えは必須。
これは、
Windows 10 にちょっとだけ触れてみました。そして[CAPS]キーを[CTRL]キーにするレジストリについて。 | 株式会社バンブーゲートのホームページ
を参考にして、レジストリの編集をするだけで大丈夫だった。

動作しないプログラムが通知された→アンインストールできない……?

Windows 7 のときに WIDCOMM® Bluetooth Windows® Software が入っていたのだが(Bluetoothアダプタ・たぶんLBT-UAN03C2BK8用)、互換性の問題なのか使用できない旨の通知が出ていたので、(占有サイズも大きいことだし)アンインストールしようとしたところ……

このアプリは保護のためにブロックされました。

のようなダイアログが表示され、アンインストールすることができない。

試行錯誤の結果、Administrator でログインすることで、ようやくアンインストールできた。
なお、Administrator アカウントの有効/無効切り替えは、ローカル セキュリティ ポリシーで設定できる(セキュリティの設定→ローカル ポリシー→セキュリティ オプション→アカウント: Administrator アカウントの状態)。

localhost:80 にアクセスできない(404エラー)

PuTTY の SSH トンネル設定にて localhost のポートフォワーディングを設定をしているのだが、他のポートは大丈夫なのに、なぜか 80 番(http://localhost)だけが正常にアクセスできない(404エラーになる)。

これもいろいろ当たってみると、どうやら IIS が干渉していたらしい。
コントロールパネル→プログラムと機能→Windows の機能の有効化または無効化
で確認すると、

■ インターネット インフォメーション サービス
  ■ World Wide Web サービス
    ■ アプリケーション開発機能
      ■ .NET 拡張機能 4.6
    ■ セキュリティ
      ■ 要求のフィルタリング

にチェックが入っていたので、これを外してから試してみると、無事 80 番もアクセス可能となった。

スタートメニューが使いづらい……

自分の場合、Windows 7 ではスタートメニューのアプリケーションをカテゴリごとにフォルダを作って整理することでアクセスしやすくしていたのだが、Windows 10 になると、これがまぁ使いづらいこと……特に、すべてのアプリが頭文字でソートされているのは、アプリを探しづらくて、非常に不便。
名前でソートされても、アプリの名前なんていちいち覚えてないんだってばさ……。

どうにか Windows 7 と同様のスタイルにできないか……と探すと、
weekly.ascii.jp
経由で知ったClassic Shell - Start menu and other Windows enhancementsがよさそうだったので、とりあえず Classic Start Menu のみインストール。
うん、いい感じ。
スタートボタンの[Shift]+左クリック/右クリックで標準の動作も可能なので、使い分けも効く。右クリックで出てくるメニューのほうは、Windows 10 のものが便利そうだし。

なお、同記事で紹介されていたHomepage M. Hoefs - Softwareも入れて、テーマを Aero 7にしたかったのだが、
f:id:furyu-tei:20160522143859p:plain
のようなエラーが出て、インストールできない。Windows 10 の最新のリビジョンには未対応なのか……残念。
どうでもいいけれど、Windows 10 のアイコンとかフラットデザイン(?)、全般にダサいよね……

Open Hardware Monitor がスタートアップ起動できない

以前、突然電源が落ちてしまう謎の現象が頻発したとき(その後、原因は熱暴走だと判明)に懲りたのもあり、Windows 7 のときはOpen Hardware Monitor - Core temp, fan speed and voltages in a free software gadgetを常駐させてCPU温度を監視していた。
ところが、Windows 10 になってから、スタートアップ時に起動しなくなっていた(手動で起動することは可能)。
Options → Run On Windows Startup で自動起動を設定しようとしても、エラー終了してしまう。
起動に管理者権限が必要なので、単純にスタートアップに入れるというわけにもいかない。

そこで、
pc-karuma.net
を参考に、タスク スケジューラで起動するよう、設定しておくことにした。
セキュリティ オプションで、「☑ 最上位の特権で実行する」にチェックを入れるのを忘れないこと。

その他、NJ5700E 用ツール等の再インストール

faq.epsondirect.co.jp
を参考に、「インスタントキーユーティリティー + 電源管理」の Windows 8/8.1版をダウンロードして、再インストール。

また、
faq.epsondirect.co.jp
を参考に、「Endeavor 電源プラン設定ツール」の Windows 10 対応版をダウンロードして、再インストール。

■ 【助言求む!!】アップグレード後に発生した、未解決問題

空き容量の謎



Windows 10 インストール用&Windows 7 復旧用のファイル分、ディスク容量が減ってしまうことを覚悟していたら、なぜか Windows 7 の時よりも空き容量が増えていた、という……なぜ?
Windows10 バックアップと復元 (Windows 7) でエラー

これが今、一番の問題。

バックアップと復元 (Windows 7) を使って、定期的に C: ・ D: 丸ごとのバックアップを取得したかったのだが、

バックアップの設定(S)→バックアップを次に保存(B)
↓
SeagateGoFlex (P:) [推奨] 空き領域 417.03GB 合計サイズ 1.82TB を選択
↓
●自動選択 (推奨)
↓
[設定を保存してバックアップを実行(S)]

とすると、すぐに
f:id:furyu-tei:20160522150705p:plain
というダイアログが表示されてしまい、バックアップの実行ができない現象。

同様の事例が無いか検索してみると、

  • (0x80070002)指定されたファイルが見つかりません

ユーザーフォルダがおかしかったのが原因でした。
Windows7でマイドキュメントなどの場所を別のディレクトリに指定していたのですが、
そのためかWindows10にアップグレード後、見た目マイドキュメントなどのフォルダが2つ存在していました。Σ⊂(>∀< )なんでやねん!
新しく作られてしまったフォルダの方を削除し1つだけある形にしたところ解決しました。

Windows10でバックアップ時にエラーが出たので仲間にした - みなものブログ

という記事が見つかった。
確かに自分も場所を C: → D: に変更していた関係上、ユーザーディレクトリ下にフォルダが2つずつできていたので、重複しているもの(中身が空のもの)を削除してから試してみたが、やはりダメ。

次に、イベント ビューアーで Application ログを調べてみると、

暗号化サービスで、システム ライター オブジェクトで OnIdentity() の呼び出しを処理中にエラーが発生しました。

Details:
AddLegacyDriverFiles: Unable to back up image of binary Microsoft Link-Layer Discovery Protocol.

System Error:
アクセスが拒否されました。
。

というエラー(ソース: CAPI2、イベント ID: 513)が出ていることに気付いたので、再び対処方法を検索。

Error source CAPI2 id 513 - Cryptographic Services failed while processing the OnIdentity() call in the System Writer Object
等を参考にしつつ、

> sc sdset MSLLDP D:(D;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BG)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;CCDCLCSWRPDTLOCRSDRCWDWO;;;BA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SO)(A;;LCRPWP;;;S-1-5-80-3141615172-2057878085-1754447212-2405740020-3916490453)(A;;CCLCSWLOCRRC;;;SU)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)

を試してみると、確かにイベントログのエラーの方は消えることがわかった。

しかし、バックアップを実行しようとした直後のエラーダイアログは変わらず表示され、バックアップができない状況は改善されない……困った。
バックアップする対象を手動で色々変えてみたりもしたが、結果は同じ。
なお、「システム イメージの作成」からのフルバックアップについては特に問題なく取得でき、システム修復ディスクも作成できている。

◆ その他の確認等

やむを得ず、現在は代替として、
www.forest.impress.co.jp
を試用中。

GIMP 2 で wacom のペンタブレットが認識されたりされなかったり

これも謎。

wacom の Intuos (CTL-490/W0)なのだけれど、GIMP2を起動するたびに、
f:id:furyu-tei:20160522155905p:plain
認識されていなかったり(グレーアウト)
f:id:furyu-tei:20160522155915p:plain
問題なく認識されていたり。

いまひとつ、条件がつかめない……。
一度認識されると、その後はログアウトするまでは認識された状態になっているようだが……。
[2016.05.22 追記]うーん、マウスではなく、ペンタブレットを使って GIMP2 を起動した場合には、認識されている確率が高い……?

「タスクバーを自動的に隠す」設定が効かないことがある……?

ときどき、どうやってもタスクバーが出っぱなしになってしまい、隠れないことがある。
タスクバーが自動的に隠れない - マイクロソフト コミュニティ
うーん、通知も無いし、アクティブになりたがっている(通知しようとしている)起動中アプリも無さそうなんだけれど……。
s.jkunblog.com
これ(エクスプローラーの再起動)をやると、確かに隠れるようにはなるのだけれど、タスクトレイに常駐しているアプリがいくつか見えなくなってしまうので、困る。

その後、今度はタスクバーが隠れっぱなしになって、どうやっても出てこない現象も発生した……どうなっているんだ。

FileZillaでアップロードしたときに、タイムスタンプが維持されないレンタルサーバに困っている

$
0
0

FileZillaを使用してファイルをアップロードした際に、レンタルサーバによっては、タイムスタンプが維持されないことがあり、割と困っていたりする。
具体的には、ファーストサーバのレンタルサーバを使用していると、タイムスタンプが維持されない(少なくとも自分が会社で使用しているマネージド共有・専用サーバーにおいては。Zenlogic等の比較的新しいサービスについては不明)。
当然ながら、転送(T)→転送したファイルのタイムスタンプを維持(P)には、チェックが入っている前提。

回避方法があれば、ご教授願いたい。
まぁ、FFFTPでは、ファーストサーバにおいても、タイムスタンプが維持されるようなので、そちらを使えばいいという話もあるのだが……ただ、FFFTPは逆に、ダウンロード時にタイムスタンプが維持されなかったり等の問題があった気がするんだよな……(うろ覚え)。

レンタルサーバの比較

レンタルサーバのサービス元アップロード時のタイムスタンプの維持詳細
ファーストサーバ×アップロードした時刻になってしまう
お名前.com(GMO)秒の単位については0にされてしまう
また、半年以上前のファイルは、FileZillaで見ると日の単位までしかタイムスタンプが表示されない(ダウンロードすると、分の単位までは一致)
さくらインターネット秒の単位まで維持される

いずれもプレーンなFTPを使用した場合。
FTP over TLSや、SFTPを使用した場合には結果が異なるかもしれないが、現時点では細かくは検証していない(ただ、ファーストサーバ・お名前.comはFTP over TLSで、さくらはSFTPで常用しているが、結果は変わらなかった気がする←これもうろ覚え)。

手動で FTP ログインしたときのサポートコマンド表示

tadtak.jugem.jp
の記事中に、

クライアントは FileZilla。FileZilla は Wikipedia によると、

FTPの場合、サーバがMFMTコマンドをサポートする場合のみ、アップロードされたファイルの日付/タイムスタンプ属性が保持される。
SFTPの場合、FileZilla 3.0.8 以降では同属性が保持される

らしいです。

vsftpd 経由で ftp アップロードするとタイムスタンプを維持してくれない | 日頃の行い

という記述があり、実際、

アップロード

  • FTPモード: サーバがMFMTコマンドをサポートする場合のみ、アップロードされたファイルの日付/タイムスタンプ属性が保持される。
  • SFTPモード: FileZilla Client 3.0.8 以降では同属性が保持される。
FileZilla - Wikipedia

となっている。

そこで、試しに各レンタルサーバに手動でログインしてもみると……いずれもMFMTコマンドはサポートされていない……?
ということは、FileZillaでも、MFMTコマンド以外でタイムスタンプを維持する努力はしているが、ファーストサーバではそれもうまくいっていないということ……?

ファーストサーバ
$ telnet ftp.***.*** ftp
Trying ***.***.***.***...
Connected to ftp.***.***.
Escape character is '^]'.
220 Firstserver FTP Server Ready
user ***
331 Password required for ***
pass ***
230 User *** logged inhelp214-The following commands are recognized (* =>'s unimplemented): CWD     XCWD    CDUP    XCUP    SMNT*   QUIT    PORT    PASV EPRT    EPSV    ALLO*   RNFR    RNTO    DELE    MDTM    RMD XRMD    MKD     XMKD    PWD     XPWD    SIZE    SYST    HELP NOOP    FEAT    OPTS    AUTH    CCC*    CONF*   ENC*    MIC* PBSZ    PROT    TYPE    STRU    MODE    RETR    STOR    STOU APPE    REST    ABOR    USER    PASS    ACCT*   REIN*   LIST NLST    STAT    SITE    MLSD    MLST214 Direct comments to root@***.***.***.***quit221 Goodbye.Connection closed by foreign host.
お名前.com(GMO)
$ telnet ftp.gmoserver.jp ftp
Trying 157.7.144.19...
Connected to ftp.gmoserver.jp.
Escape character is '^]'.
220 ProFTPD 1.3.2d Server (ftp.gmoserver.jp)[157.7.144.19]
user ***@gmoserver.jp
331 Password required for ***@gmoserver.jp
pass ***
230 User ***@gmoserver.jp logged inhelp214-The following commands are recognized (* =>'s unimplemented): CWD     XCWD    CDUP    XCUP    SMNT*   QUIT    PORT    PASV EPRT    EPSV    ALLO*   RNFR    RNTO    DELE    MDTM    RMD XRMD    MKD     XMKD    PWD     XPWD    SIZE    SYST    HELP NOOP    FEAT    OPTS    AUTH    CCC*    CONF*   ENC*    MIC* PBSZ    PROT    TYPE    STRU    MODE    RETR    STOR    STOU APPE    REST    ABOR    USER    PASS    ACCT*   REIN*   LIST NLST    STAT    SITE    MLSD214 Direct comments to root@ftp02-ext.sd.internal-gmoquit221 Goodbye.Connection closed by foreign host.
さくらインターネット
$ telnet ***.sakura.ne.jp ftp
Trying ***.***.***.***...
Connected to ***.sakura.ne.jp.
Escape character is '^]'.
220 ProFTPD 1.3.5a Server (SAKURA Internet FTP Server)[::ffff:***.***.***.***]
user ***
331 Password required for ***
pass ***
230 User *** logged inhelp214-The following commands are recognized (* =>'s unimplemented): CWD     XCWD    CDUP    XCUP    SMNT*   QUIT    PORT    PASV EPRT    EPSV    ALLO*   RNFR    RNTO    DELE    MDTM    RMD XRMD    MKD     XMKD    PWD     XPWD    SIZE    SYST    HELP NOOP    FEAT    OPTS    AUTH    CCC*    CONF*   ENC*    MIC* PBSZ    PROT    TYPE    STRU    MODE    RETR    STOR    STOU APPE    REST    ABOR    USER    PASS    ACCT*   REIN*   LIST NLST    STAT    SITE    MLSD    MLST214 Direct comments to root@www998.sakura.ne.jpquit221 Goodbye.Connection closed by foreign host.

余談

お名前.com(GMO)のレンタルサーバーに関する愚痴

FTPで、ときどきうまく接続できなかったり(詳細は忘れたが、接続数が上限に達した、みたいなエラーが出る)、多数のファイルのアップロード/ダウンロード時に脈絡なく失敗したりと、動作が不安定なのが困る(これらの現象は、FileZillaでもFFFTPでも発生)。
FTPクライアントの設定をいじれば、どうにかなったりするのだろうか……?

あと、SSHをサポートするようになったのはいいのだが、SFTPには対応していないのかな?
これは自分が設定をわかっていないだけかもしれないが。
アカウント(ユーザー名)が「xxx@gmoserver.jp」のように"@"を含んでいるのも、

$ ssh -l xxx@gmoserver.jp ssh.gmoserver.jp

とかしないといけなくて、地味に面倒だし。
ホームディレクトリにファイルが置けない(~/.bash_profile等もいじれない)のも不満。

Twitter メディアダウンローダ:ユーザータイムラインの原寸画像をまとめてダウンロードするユーザースクリプト(PC用Google Chrome・Firefox等対応)

$
0
0

Web 版公式 Twitter上で、あるユーザーの画像(メディアタイムライン上の画像)を原寸*1でまとめて(ZIP)保存することが出来るようになるユーザースクリプト/Chrome拡張機能です。



インストール

Chrome 拡張機能版(Google Chrome対応)

chrome.google.com

より追加。
Twitter メディアダウンローダ - Chrome ウェブストアのページ上に表示されている [+CHROME に追加] ボタンを押してインストール。


ユーザースクリプト(Gresemonkey / Tampermonkey)版(Firefox/Google Chrome対応)

Firefox+Gresemonkey、Google Chrome+Tampermonkeyの環境で、

Twitter メディアダウンローダ・ユーザースクリプト版(twMediaDownloader.user.js)

GitHub - furyutei/twMediaDownloader: Twitter メディアダウンローダ

をクリックし、指示に従ってインストール。

使い方

基本的な使用方法

インストール後には、Web 版公式 Twitter上で、ユーザータイムライン()を表示時に、「メディア」の横に下向きの矢印が表示されるようになります。

f:id:furyu-tei:20160725180612p:plain


これをクリックするとダイアログが表示されるので、[開始]ボタンをクリックすると、原寸画像の ZIP 化が開始されます。
ZIP 化の進捗は、下部にログ出力されます。
f:id:furyu-tei:20160723224527j:plain

ZIP 化が完了するか、もしくは[停止]を押すと、対象となる画像ファイルをまとめた ZIP ファイルがダウンロードされます。
このとき、ログの内容も ZIP の中に保存されています。

オプションの指定

制限数は、ダウンロード対象となるツイート数の上限です(デフォルトは現状 100 件にしてあります)。
これを超えた分のツイートはダウンロードされません。
大きい値を指定すると、その分メモリを消費してしまい、ブラウザがフリーズする等の不具合が発生する可能性がありますので、ご注意ください。

ダイアログの保存対象 Tweet ID 範囲に、具体的な Tweet ID(ツイートの URL の数値部分・例えば https://twitter.com/furyutei/status/743443761980596224ならば、"743443761980596224")を指定してやることで、その範囲にあるツイートの画像のみをダウンロードすることができます。

■以前にダウンロードしたものよりも後の画像をダウンロードする
以前にダウンロードしたときのログファイルが、

[Complete] 101392230006267904 - 756891141912481792 ( Tweet: 333 / Image: 398 )

のような形で終わっている場合には、下限(左の入力欄)として "756891141912481792"を指定してやることで、これより後に更新された画像をまとめてダウンロードすることができます。

■以前にダウンロードしたものよりも前の画像をダウンロード

[Complete(limited)] 582865505758748672 - 680344335049601024 ( Tweet: 100 / Image: 120 )

この例だと、100件制限によって、"582865505758748672"より前のものが含まれていませんが、この場合は上限(右の入力欄)として "582865505758748672"を指定してやることで、これ以前に更新された画像をダウンロードできます。

注意・制限など

  • ダウンロードできるのは、Web 版公式 Twitter上のメディアタイムラインで遡れるところまでに限られますので、悪しからず。
    800ツイートくらいかな?
  • [2016/07/24追記]ダウンロードできるのは、Web 版公式 Twitter上のメディアタイムラインおよび検索タイムラインで取得できるもののみです。
    メディアタイムラインでは最大で800ツイートくらいまで(動画付きツイートも含むため、画像のみではもっと少なくなる)しか取得できないため、それよりも前は検索タイムラインで取得します。ただし、検索タイムラインでは取得もれが発生することも多いため、全ての画像付きツイートがダウンロードできるわけではありませんので、悪しからず。

開発経緯

Twitter 原寸びゅーのおかげで、日常的な用途では原寸画像の表示や保存が随分楽にできるようになりましたが、たまたま発見したイラストレーターや写真家の方々等の画像/写真に魅了された際に、ひとつずつダウンロードするのはさすがに手間だなぁ……と思ったので、まとめてダウンロードできるように、スクリプトを試作してみた次第です。

独り言

動画(アニメーションGIF含む)とかまでダウンロードできるとさらに嬉しいので、だれか作ってくれないでしょうか……(丸投げ)。
ちなみに自分は、ちょっと調べている内に結構面倒だということがわかったために、保留中。

[2016/07/27追記]というか、例によって作ってから探したところ、普通に
shimarisu.webcrow.jp
shimarisu.webcrow.jp
という高性能なアプリが見つかったので、これをインストールするのが吉かと思います。
いや、自分自身はまだ入れていないのだけれども。

*1:URL末尾に『:orig』が付いた画像を便宜上こう呼んでいますが、『原寸』といっても実際にはTwitter側でサイズ変換や圧縮がかかっています

v6プラス利用で輻輳時間帯(夜間等)の通信速度が劇的に改善した

$
0
0




承前と結論

以前、ビッグローブ光で、特に夜間(21時~25時頃)、通信速度がものすごく遅い(10Mbps以下、ひどいときには1Mbps未満になることも)という記事を書いた。
furyu.hatenablog.com

あれから一年以上経ったが、一向に改善される気配がないため、ISP乗換も視野に入れてあらためて調査し、設定を見直してみたところ……なんと、v6プラス
support.biglobe.ne.jp
を利用することで、劇的に改善することが判明。
輻輳する時間帯であっても、数十Mbpsで安定して通信できている。2016/10/07現在、データ取得中・後ほど公開予定→記事を公開した

デメリットとして、

「v6プラス」では一部利用できないサービスがあります。
すでに利用中もしくは今後、サービスのご利用を予定している方は「v6プラス」はご利用いただけません。

  • BIGLOBEフォン
  • 固定IPサービス
  • 一部通信型ゲームなど、特定ポートを使用するサービス、または、複数のユーザでIPアドレスを共有すると利用できないサービス。
  • 利用可能なポート番号、ポート数に制限があります。 外部へサーバ公開をお考えの方はご利用できません。
  • OP25Bブロックを実施しています。メール送信には587(サブミッションポート)を利用する必要があります。
IPv6接続「v6プラス」のご案内:BIGLOBE会員サポート

というものがあるが、これらを許容できる方で、

  • NTT東西のホームゲートウェイレンタル中(ひかり電話に加入済み、もしくは加入予定(月額500円(税別)が別途必要)の方など)

または

という条件に当てはまる方は、追加費用(初期費用/月額費用共) 0 ということでもあるし、導入を検討されてはいかがだろうか。

なお、v6プラスはVNE接続事業者のひとつであるJPNE(日本ネットワークイネイブラー株式会社)がISP向けに提供しているサービスでありBIGLOBEの他にも対応しているISPがいくつか存在する

v6プラス導入に伴う、自宅のインターネット接続環境の変遷

1. v6プラス加入以前

f:id:furyu-tei:20161007192131p:plain

  • PPPoE により ISP と接続
  • 特に夜間(21時~25時頃・輻輳時と思われる)での通信速度が遅い(数百Kbps~10Mbps程度しか出ない)
  • フレッツNGN網内の速度は数百Mbpsで比較的安定→ボトルネックはNGN~ISP間の相互接続点(POI)にあると推測
2. v6プラス加入(2015/08/18)~最近(2016/10/06)まで

f:id:furyu-tei:20161007192344p:plain

3. 設定見直し後(2016/10/07現在)

f:id:furyu-tei:20161010003054p:plain

という経緯で、格段に通信速度が安定した環境に生まれ変わった。

なお、Wi-Fiブロードバンドルータ(WZR-1750DHP)は、ルータモードで使用(モードの切替方法)。
ブリッジ(AP)モードでも動作するし、余分な機能がない分だけスループットはその方が大きい気もするけれど、

  • 設定画面にアクセスしやすい(ブリッジモードだとルータのIPアドレスは192.168.11.100なので、いちいちPCの設定を変える必要がある)
  • MACアドレス→IPアドレスのマッピング機能により、端末に固定のローカルIPアドレスを割り当てられる

という具合に、ひかり電話ルータ(PR-S300NE)よりもいろいろと設定がしやすいので(特に、v6プラス加入後は、PR-S300NEはIPv4関連の設定がほとんどできなくなる)、ルータモードで使用している。

独り言

まぁ、v6プラスに加入する方が増えてきたら、やっぱり遅くなってしまうのかも知れないけれども……。
なにせ、これまでISP毎に分散されていたトラフィックが、JPNEに集中する構造なわけで……上記の図では省略しているけれど、NGN~JPNE間にも当然 POI(Point Of Interface・相互接続点)はあるわけだし、BR(Border Relay)の処理能力にも上限はあるだろうしね。この辺りの見通しはどうなっているのかな……?

[2016/10/09 追記]

MAP-Eはステートレスであるため、BRはユーザ数やセッション数ではなくトラフィック量に応じた設備投資が可能であり [2]、冗長構成を容易に構築できます。

ネットワーク | JANOG31 Meeting

なるほど、ステートレスである(NAPT機能はCPE(HGW)側に持たせるため、BR側はパケットのカプセリング/デカプセリング機能のみ持てばよく、セッション管理をする必要がないために機能的にシンプルになる)ために、トラフィック量のみを考慮した設備投資でよくなるし、冗長化も容易になる(障害に強い構成にできる)のか。


あと、この記事上の図はdraw.ioを使わせていただいた。
初めて使ったのだけれど、お手軽だし使いやすい。おすすめ。


余談

今回、あらためて調べる気になった理由。


……「響け!ユーフォニアム」はいいぞ!
anime-eupho.com
ch.nicovideo.jp
www.onsen.ag

響け! ユーフォニアム 北宇治高校の吹奏楽部日誌 (宝島社文庫)

響け! ユーフォニアム 北宇治高校の吹奏楽部日誌 (宝島社文庫)

このマンガがすごい! Comics 響け! ユーフォニアム 北宇治高校吹奏楽部のいちばん熱い夏 1

このマンガがすごい! Comics 響け! ユーフォニアム 北宇治高校吹奏楽部のいちばん熱い夏 1

響け!ユーフォニアム2 1巻 [Blu-ray]

響け!ユーフォニアム2 1巻 [Blu-ray]

TVアニメ『響け!ユーフォニアム2』OP主題歌「サウンドスケープ」

TVアニメ『響け!ユーフォニアム2』OP主題歌「サウンドスケープ」

TVアニメ『響け!ユーフォニアム2』ED主題歌「ヴィヴァーチェ!」

TVアニメ『響け!ユーフォニアム2』ED主題歌「ヴィヴァーチェ!」

v6プラス関連の覚え書き

$
0
0

前の記事
furyu.hatenablog.com
がらみで調べたことなどをメモ書き。
あちこち間違っていると思われるので、識者の突っ込み歓迎。



フレッツ光ネクストの接続環境例

VNE接続事業者のひとつであるJPNE(日本ネットワークイネイブラー株式会社)は、ISP向けに、NTT東西のフレッツ光ネクスト網(NGN)を利用するIPv6インターネット接続サービス及びv6プラス2014/07/01より提供している

これを使用した接続環境例を示す。

環境1. IPv4 PPPoE2. IPv6インターネット接続サービス3. v6プラス
IPv6伝送方式-IPv6 IPoEIPv6 IPoE
IPv6アドレス割当-JPNEが保持するアドレスをNTT東西が割当JPNEが保持するアドレスをNTT東西が割当
フレッツ・v6オプション加入
(NTT東西)
-
ホームゲートウェイ(HGW)によるMAP-E終端--
※IPv4 PPPoE関連機能は無効化される
IPv4伝送方式IPv4 PPPoEIPv4 PPPoEIPv4 over IPv6(MAP-E)
IPv4アドレス管理ISP
※エンドユーザ単位
ISP
※エンドユーザ単位
JPNE
※共有アドレス

なお、IPv6インターネット接続サービスおよびv6プラスは、BIGLOBE・@nifty等のISPからは、初期費用・利用料共に無料でエンドユーザ向けに提供されている。

1. IPv4 PPPoE接続時(IPv6インターネット接続サービス/v6プラス非加入時)

f:id:furyu-tei:20161007233703p:plain

  • グローバルIPv4アドレスはエンドユーザ(ルータ)毎に割当
  • ボトルネックがNGN~ISP間の相互接続点(Point Of Interface)POIにあり、ISPやサポート地域・時間帯等によって左右され、エンドユーザ毎のサービス品質に差異が出やすい
2. IPv6インターネット接続サービス加入時(BIGLOBE:『フレッツ光 IPv6接続』@nifty:『IPv6接続オプション』等)

f:id:furyu-tei:20161008001612p:plain

  • IPv4 に関しては、1. と同様の伝送形式(PPPoE)であり、同様のメリット/デメリットあり
  • IPv6関連の機能が、フレッツ・ジョイントにより HGW へと自動配信される
  • IPv4(ISP経由)とIPv6(JPNE経由)で経路は別
  • IPv6のグローバルアドレスは、PC等の端末単位で割当(HGWにはNGNよりDHCPv6-PDによりJPNEが所有するプレフィックスを持つIPv6アドレスが割り当たり、さらにHGWからのRAにより各端末にIPv6アドレスが割り当てられる(再分配))

3. の v6プラスと異なるのは IPv4 over IPv6接続関連のみであり、これは、HGWに対するMAP-E終端機能とIPv4関連機能の無効化が実施されるかどうかによると思われる。
実際、MAP-E(とDS-Lite)の終端機能があるバッファローのWi-Fiルータを使用する場合には、

※ BUFFALO製 WXR-1750DHP/WXR-1900DHP/WXR-1900DHP2/WXR-2533DHP/WXR-2533DHP2をご利用の方へ
本機器をご利用の場合は、「フレッツ光IPv6接続」をお申し込みいただくことで、v6プラスが利用できます。以下のサイトより手順通りにお申し込みください。
本ページでv6プラスのお申し込み手続きを行った場合、エラーメール(ErrorCode:E0009)が届き、v6プラス機能はご利用いただけません。

https://support.biglobe.ne.jp/ipv6/

という注意書きが見られる。
ただ、この推測が正しいとすると、HGWに設定されているIPv4 PPPoEの設定を手動でOFFにする必要がある気がするが、実際のところどうなのだろうか?

[2016/10/09追記]
考えてみると、ひかり電話に契約していない場合、そもそもHGWが無い場合が大半なのかな。
そうすると、ONUにサードパーティ製のMAP-E対応ルータを直結する形なので、

  • HGWそのものが存在しないため、v6プラス設定時のフレッツ・ジョイントによるHGWへの設定は失敗する(→エラーメールが返る)
  • 「IPv6インターネット接続サービス」の場合、MAP-E終端はサードパーティ製のMAP-E対応ルータが行うことで、結果的にv6プラス相当機能となる

ということなのかも知れない。
ただ、MAP-Eの場合には、CPE(ルータ)側でNAPTを実施するので、CPEに予めグローバルIPv4アドレス(共有)+NAPT利用可能なポート番号のセットを割り当てておく必要があると思うのだけれど、これをフレッツ・ジョイントでやっているとすると、つじつまが合わなくなってしまう……うーん、今一つよくわからない……。
→違った、NTT東西がNGNからJPNEの持つIPv6プレフィックスをDHCPv6-PDでCPEに割り当てるので、フレッツ・ジョイントは関係ないのか。このIPv6プレフィックスから、IPv4アドレス(共有)+NAPT利用可能なポート番号のセットを取り出していると考えると、つじつまが合いそうかな。

逆に、ひかり電話に契約している等してHGWを設置している場合、サードパーティ製ルータを使用していても、v6プラス設定時にエラーメールは返らないはず(ただしその場合、HGWの下にサードパーティ製ルータが設置されることになるので、MAP-E終端は HGW となるはずで、サードパーティ製ルータを MAP-E終端にする場合には、HGWのIPv4 over IPv6 IPoE機能を手動でオフにする必要があると思われる)。

3. v6プラス加入時

f:id:furyu-tei:20161010003322p:plain

  • IPv6 に関しては、2. と同様の伝送形式(IPoE)
  • IPv4 over IPv6接続(MAP-E)のために、HGWに対して自動的にMAP-E終端機能が配布され、またIPv4 PPPoE関連機能は無効化される(フレッツ・ジョイント機能による)
  • NGN~ISP間(POI)のボトルネックには左右されない

IPv4接続に関して、以下のような制限がある。
参考:BIGLOBE@nifty

■ 使用できないサービス
 ・ISPが提供するIP電話サービス(BIGLOBEフォン等)
 ・固定IPサービス

■ 制限のあるサービス
 ・IPv4グローバルアドレスを複数人で共有使用できないサービス
 ・特定プロトコル(PPTP,SCTP等)を使用するサービス
 ・特定ポート番号を使用するサービス(オンラインゲーム、サーバの公開など)

これらは主として

  • JPNE側グローバルIPv4アドレスを複数のエンドーユーザで共有
  • 利用可能なポート番号/数に制限

ことに伴う制限と考えられる。

[2016/10/09 追記]
v6プラスに加入すると、フレッツ・ジョイントにより、HGWに「IPv4設定(Setting IPv4)」というソフトウェアが配信される。
これは、HGWに対して

http://ntt.setup:8888/t

にアクセスすると表示される、「配信済み事業者ソフトウェア一覧」にて確認できる(参考:v6プラスの通信速度が振るわない件&PPPoEに簡単に切り替える方法 | 今日の気分はバリいくつ?)。

この設定内では、NAPTに使用される

  • HGWに割り当てられたIPv4グローバルアドレス(複数のエンドユーザで共有)
  • 利用可能ポート番号(Port-set:16ポート×15ブロックで、計240ポート)

が確認でき、この利用可能ポート番号の範囲であれば、静的NAPT設定も可能ではある。

トピックス

BIGLOBEの高速Wi-Fi × ギガ対応回線 プレミアムサービスに加入するメリットはあるか?
  1. 高速 Wi-Fi ルータ(NEC Aterm WG1810(JE)・無線LAN 1300Mbps(11ac/5MHz)・MAP-E機能搭載)レンタル
    「解約から1カ月を過ぎてもWi-Fiルータが返却されない場合、端末代金相当額として16,000円(税別)を請求」する旨記載あり
  2. ギガ対応・次世代ネットワーク接続
  3. 新しいメールアドレスの追加(希望者のみ)

で、月額800円(税別)(2016/10/3~2016/11/30の期間、最大2ヵ月分無料のキャンペーン中、ただし、無料期間中に解約時は、Wi-Fi-ルータ返却手数料1,300円(税別)徴収)。
……という内容の、BIGLOBEの高速Wi-Fi × ギガ対応回線 プレミアムサービス
フレッツ光 IPv6接続(無料)や、v6プラス(無料)との違いが気になるところ。

プレミアムサービスでは次世代のネットワーク(IPoE接続)をご利用いただきます。
(中略)
また、すでにギガ対応回線の方でも、混雑している一般道路(PPPoE接続)から混雑していない高速道路(IPoE接続)に切り替えるため、速くなるのです。
(中略)
動画サービスの広がりなどにより、インターネットに流れる通信量が爆発的に増加しています。日本のインターネット全体で現在よく使われているネットワーク(PPPoE接続)での混雑がより顕著になっており、特に通信量が増える22:30頃には通信速度が低下する地域が出てきています。

しかし、プレミアムサービスなら次世代ネットワーク(IPoE接続)により、地域や時間帯の影響が少なく、快適にネットができます。

高速Wi-Fi × ギガ対応回線 プレミアムサービス:BIGLOBE会員サポート

といった記述を見る限り、v6プラスとの違いがわからない。

ただ、

  • v6プラスをご利用中のお客さまは本サービスをお申し込みすることができません。v6プラスを解約後、お申し込みください。
高速Wi-Fi × ギガ対応回線 プレミアムサービス:BIGLOBE会員サポート

ということで、どうやらv6プラスとは排他的なサービスらしい。
また、v6プラスでは特に要求されない、Wi-Fi ルータ(MAP-E対応)のレンタルも気になる。

これはあくまで推測であるが、

『高速Wi-Fi × ギガ対応回線 プレミアムサービス』≒『IPv6インターネット接続サービス』(『フレッツ光 IPv6接続』相当)+『MAP-E対応 Wi-Fi ルータ』+『希望者への新メールアドレス提供』

のような感じになっているのではなかろうか。
上記「2. IPv6インターネット接続サービス加入時」参照。

NEC Aterm WG1810(JE)とスペック的に遜色の無いと思われるMAP-E対応ルータWXR-1750DHPであれば1万円強で手に入るようなので、無料の『フレッツ光 IPv6接続』に加入したうえでこれを使うようにすればほぼ同等の機能となり、かつ1年程で元が取れるような気もする。
あとの違いは、『希望者への新メールアドレス提供』のみなので。
さて、真相は如何に……?

【2016/10/08 追記】
BIGLOBEの『高速Wi-Fi × ギガ対応回線 プレミアムサービス』と同じようなサービスが、GMOとくとくBBでも提供されていた。
gmobb.jp
こちらは堂々と『v6プラス』としての提供で、「v6プラス」+「Wi-Fiルーターレンタルサービス」がサービス内容。
Wi-Fiルータはまさに、WXR-1750DHPである。
月額991円(税抜)フレッツ光の回線利用料は別に発生)。

ただし、BIGLOBE の場合は、もともとの契約(ビッグローブ光等)に加えて上記の値段が必要なので、それを考えると、GMOとくとくBBの方が新規で契約する分にはお得、なのかも知れない。

なお、GMOとくとくBBの方では、速度の公開もされている
これは、速度測定システム Radish Networkspeed Testing マルチセッション版-β- 東京で実測されたデータの平均値らしい。
ちなみに、試しに自分の環境(BIGLOBE光ネクスト+v6プラス)で測定してみると、

===== Radish Network Speed Testing Ver.4.0.4β - Test Report =====
測定条件
 精度:高 データタイプ:圧縮効率低
下り回線
 速度:289.8Mbps (36.23MByte/sec) 測定品質:91.6 接続数:2
上り回線
 速度:355.1Mbps (44.39MByte/sec) 測定品質:95.6 接続数:3
測定者ホスト:*************.v*.enabler.ne.jp
測定時刻:2016/10/8(Sat) 8:49
==================================================================

こんな感じである。
マルチセッションで測定されることもあり、比較的高めの速度が出ている。

[2016/10/15 追記] v6プラスのIPv4アドレス/ポートセット割り当て方法の推測

IPv6インターネット接続サービス/v6プラス加入時に、ホームゲートウェイ(HGW・ひかり電話ルータ)やv6プラス対応ルータに対して、DHCPv6-PDにより通知されるIPv6プレフィックス(/56)は、現状以下のような構成になっている模様。

240b:XXXX:AABB:CC00::/56
 240b:XXXX::/32 → IPv4プレフィックス(アドレス上位16ビット)へのマッピング
 AABB → IPv4アドレス下位16ビット
 CC → ポートセットID

なお、このマッピングルールは、ひかり電話ルータに割り当てられている情報やネット上の情報等から推測したものであり、実際には、JPNEが用意するマップ配信サーバとHGWとの通信によって配信されることに注意。
ここに記述したものだけだと、IPv4アドレスが最大でも6*256*256=393,216、IPv4アドレス辺りのポートセットが256であるため、約1000万ユーザーにしか対応できないが、マップ配信サーバから配信されるルールを変更することで拡張していくものだと思われる。
マップ配信サーバ~HGW/ルータ間のマップ配信手順の仕様は見つけられなかった(非公開?)。

■ IPv6プレフィックス→IPv4プレフィックスマッピング(例)

IPv6プレフィックスIPv4プレフィックス
240b:0012::/3214.8.0.0/16
240b:0013::/3214.9.0.0/16
240b:0250::/3214.10.0.0/16
240b:0251::/3214.11.0.0/16
240b:0252::/3214.12.0.0/16
240b:0253::/3214.13.0.0/16

■ ポートセットIDによる利用可能ポート割当(例)
現状、

  • 1ポートセットあたりの利用可能ポートは 240 個
  • 1つのIPv4アドレスを、256ユーザで共有(61440個(4096~65535)のポート番号→ 61440/240 = 256)

となるように割り当てられている模様。

ポートセットIDを CC とすると、利用可能ポート範囲は、

mCCn (16進数)
  CC: 00~FF
  m: 1~F
  n: 0~F

で表される。

例えば、CC = 00 の場合、

16進1000-100F2000-200F3000-300F4000-400F5000-500F
10進4096-41118192-820712288-1230316384-1639920480-20495
16進6000-600F7000-700F8000-800F9000-900FA000-A00F
10進24576-2459128672-2868732768-3278336864-3687940960-40975
16進B000-B00FC000-C00FD000-D00FE000-E00FF000-F00F
10進45056-4507149152-4916753248-5326357344-5735961440-61455

となる。

◆ 参考

関連

IPv6 IPoE サービス提供 VNE 接続事業者

国内において、JPNEと同等のVNE接続事業者としては、他にBBIX株式会社インターネットマルチフィード株式会社があり、それぞれがIPv6 IPoEを用いたIPv6インターネット接続サービスを ISP 向けに提供している。以下に簡単にまとめる。

VNE接続事業者日本ネットワークイネイブラー(JPNE)BBIXインターネットマルチフィード
IPv6サービス名v6プラスIPv6 IPoE + IPv4 ハイブリッドサービスtransix
IPv4 over IPv6 技術MAP-E4rd/SAMDS-Lite
専用ルータ要否基本不要
NTT東西のHGWを使用していれば自動更新で対応可能
※ひかり電話未加入かつHGWもない(ONU/VDSLのみの)場合、対応ルータが必要

BBIX(ソフトバンク)より専用ルータ(光BBユニット)提供

対応ルータをエンドユーザが用意
ポート開放
(静的NAPT)
×?
割り当てられた範囲のポートであれば開放可能かも?
○?×
ISP例BIGLOBE、@nifty、その他ソフトバンク・Yahoo! BB 光 with フレッツIIJmio:FiberAccess/NF
Viewing all 92 articles
Browse latest View live