Hatena::ブログ(Diary)

初学者の箸置 このページをアンテナに追加 RSSフィード

2012-01-27

[] オプションの追加方法(とおまけ)

@KSuzukiiさんがおもしろいこと始めたようでブログに載ってました。set nuの数字との区切り文字を変更できるようにするという壮大な計画!

自由に設定出来るようにするにはどうすればいいんだろう?

Vim:行数と文字との間を空白文字以外にしたい - LSI設計雑記帳 http://lsifrontend.blog100.fc2.com/blog-entry-231.html

とのことだったので、ちょうど昨日やったやつと共にちょっとした説明など。

何してたのか?

実は随分前に set nu のナンバリングを特定の位置からの相対値にする(http://d.hatena.ne.jp/tkuro/20081219/1229676014)、というのをやったのですが、あのあとしばらくなにもせずに放置していたら、vimのほうでいつの間にか 'relativenumber' というのが追加されていたみたいです。これを使うと、「現在のカーソルの位置」からの相対値表示ができます(カーソルを動かすとグリグリうごくw)。値は abs() してあって上方向も正の値になってます。すなわち、あくまでvim的に「上 14k」とか「うりゃっ 14dd」のように華麗に行移動するためのものであって、僕の目的である「行数えてよ。」とはちっと違います。

とっとと弄ってしまいましょ。と。

#source は hg clone https://vim.googlecode.com/hg/ vim で最新版拾って来ました。

どこいじるのか?

とりあえずまずはオプションをつけるとこまでやります。

src/option.cを見ると最初の方にコメントにて

/*
 * Code to handle user-settable options. This is all pretty much table-
 * driven. Checklist for adding a new option:
(1)- Put it in the options array below (copy an existing entry).
 * - For a global option: Add a variable for it in option.h.
 * - For a buffer or window local option:
(2)  - Add a PV_XX entry to the enum below.
(3)  - Add a variable to the window or buffer struct in structs.h.
(4)  - For a window option, add some code to copy_winopt().
 *   - For a buffer option, add some code to buf_copy_options().
 *   - For a buffer string option, add code to check_buf_options().
(-)- If it's a numeric option, add any necessary bounds checks to do_set().
 * - If it's a list of flags, add some code in do_set(), search for WW_ALL.
 * - When adding an option with expansion (P_EXPAND), but with a different
 *   default for Vi and Vim (no P_VI_DEF), add some code at VIMEXP.
(-)- Add documentation!  One line in doc/help.txt, full description in
 *   options.txt, and any other related places.
(-)- Add an entry in runtime/optwin.vim.
 * When making changes:
(-)- Adjust the help for the option in doc/option.txt.
(-)- When an entry has the P_VIM flag, or is lacking the P_VI_DEF flag, add a
 *   comment at the help for the 'compatible' option.
 */

と全てやり方が書いてあります*1

今回やってみようかなーというものに番号を振って見ました。do_set()での範囲チェックとか必要無いのでカットです。。。

ドキュメントどうしようかなー。

さてさて、まずは(1)。src/option.c に options[] というvimoption 構造体の配列があります。ここに追加するようです。

どんなふうに?

順番に

{
  "オプション名", "短縮名", 
  フラグ, 
 オプション変数へのポインタ, 
  ローカルインデックス(グローバルな場合PV_NONE), 
  { vi 向けの初期値,  vim 向けの初期値 },
  SCRIPT_INIT(ここはvimが面倒みてくれます)
}

今回みたいに window-local なオプションの場合、少し注意が必要ですが、まあまあ直感的(?)。

以下順番に。

名前を決めます
今回は 'numbertop', 'nbt' としました
フラグを決定
P_NUM|P_VIM|P_RWIN (数値、vim専用フラグ、変更されたら即画面更新) で
オプション変数へのポインタ
これはwindow-localの場合 VAR_WIN で(詳しくはoption.cの該当コメントを参照してください)
ローカルインデックス
 ここでは PV_NBT としました。
初期値
両方 0

てな感じ。

(2) ローカルインデックス

ローカルインデックスはwindow-local(またはbuffer-local)な変数を取得するためのインデックスですね。'number'のエントリWV_NU を真似して、WV_NBTエントリをつくり、そこからOPT_WIN(WV_NBT)でPV_NBTエントリを作りました。

(3) ウィンドウ構造体に変数追加

structs.h にwinopt_Tな構造体があります。ここに追加します。今回は負の数も使いたかったのでlongにしました。

(4) copy_winoptにコピーコード追加

他の真似して追加するだけですね。

さてやってみよう(まずはオプション動作確認だけ)

実際に上記の作業をしてみます。diffがわかりやすいのかどうかわかりませんが、とりあえずhg diffにて、

diff -r 54d621a3b561 src/option.c
--- a/src/option.c      Thu Jan 26 20:58:26 2012 +0100
+++ b/src/option.c      Fri Jan 27 18:32:21 2012 +0900
@@ -209,6 +209,7 @@
 #endif
 #define PV_NU          OPT_WIN(WV_NU)
 #define PV_RNU         OPT_WIN(WV_RNU)
+#define PV_NBT         OPT_WIN(WV_NBT)
 #ifdef FEAT_LINEBREAK
 # define PV_NUW                OPT_WIN(WV_NUW)
 #endif
@@ -1868,6 +1869,9 @@
     {"number",     "nu",   P_BOOL|P_VI_DEF|P_RWIN,
                            (char_u *)VAR_WIN, PV_NU,
                            {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
+    {"numbertop",   "nbt",  P_NUM|P_RWIN|P_VIM,
+                           (char_u *)VAR_WIN, PV_NBT,
+                           {(char_u *)0L, (char_u *)0L} SCRIPTID_INIT},
     {"numberwidth", "nuw",  P_NUM|P_RWIN|P_VIM,
 #ifdef FEAT_LINEBREAK
                            (char_u *)VAR_WIN, PV_NUW,
@@ -9610,6 +9614,7 @@
        case PV_FMR:    return (char_u *)&(curwin->w_p_fmr);
 #endif
        case PV_NU:     return (char_u *)&(curwin->w_p_nu);
+        case PV_NBT:    return (char_u *)&(curwin->w_p_nbt);
        case PV_RNU:    return (char_u *)&(curwin->w_p_rnu);
 #ifdef FEAT_LINEBREAK
        case PV_NUW:    return (char_u *)&(curwin->w_p_nuw);
@@ -9804,6 +9809,7 @@
     to->wo_list = from->wo_list;
     to->wo_nu = from->wo_nu;
     to->wo_rnu = from->wo_rnu;
+    to->wo_nbt = from->wo_nbt;
 #ifdef FEAT_LINEBREAK
     to->wo_nuw = from->wo_nuw;
 #endif
diff -r 54d621a3b561 src/option.h
--- a/src/option.h      Thu Jan 26 20:58:26 2012 +0100
+++ b/src/option.h      Fri Jan 27 18:32:21 2012 +0900
@@ -1067,6 +1067,7 @@
 #endif
     , WV_NU
     , WV_RNU
+    , WV_NBT
 #ifdef FEAT_LINEBREAK
     , WV_NUW
 #endif
diff -r 54d621a3b561 src/structs.h
--- a/src/structs.h     Thu Jan 26 20:58:26 2012 +0100
+++ b/src/structs.h     Fri Jan 27 18:32:21 2012 +0900
@@ -169,6 +169,8 @@
 #define w_p_list w_onebuf_opt.wo_list  /* 'list' */
     int                wo_nu;
 #define w_p_nu w_onebuf_opt.wo_nu      /* 'number' */
+    long       wo_nbt;
+#define w_p_nbt w_onebuf_opt.wo_nbt    /* 'numbertop' */
     int                wo_rnu;
 #define w_p_rnu w_onebuf_opt.wo_rnu    /* 'relativenumber' */
 #ifdef FEAT_LINEBREAK

実行してみて各windowで異なる値が設定できることを確認します。おー、できてる。

良さげなので一回commit。

行番号のところを弄る

仕様としては

numbertop = 0 の時
通常動作。カーソル位置が原点。
numbertop > 0 の時
設定した値の行を原点として固定。原点より上もプラス表示(abs)
numbertop < 0 の時
設定した値の行を原点として固定。原点より上はマイナス表示

とします。

ちらと見るとmisc2.c のget_cursor_rel_lnum()をいじれば良いことがわかります。

んで、オプションの値にはMAGICALな変数 curwin からアクセスできます。 curwin->w_p_nbtですね。

つわけで、おもむろに。

diff -r adff37f40674 src/misc2.c
--- a/src/misc2.c       Fri Jan 27 18:36:17 2012 +0900
+++ b/src/misc2.c       Fri Jan 27 18:55:25 2012 +0900
@@ -515,6 +515,15 @@
 #endif
        retval = lnum - cursor;

+    if (curwin->w_p_nbt > 0) {
+        retval -= curwin->w_p_nbt - cursor;
+    } else if (curwin->w_p_nbt < 0) {
+        retval += curwin->w_p_nbt + cursor;
+        return retval;
+    }
+
+    retval = labs(retval);
+
     return retval;
 }

diff -r adff37f40674 src/screen.c
--- a/src/screen.c      Fri Jan 27 18:36:17 2012 +0900
+++ b/src/screen.c      Fri Jan 27 18:55:25 2012 +0900
@@ -2321,7 +2321,7 @@
                num = (long)lnum;
            else
                /* 'relativenumber', don't use negative numbers */
-               num = labs((long)get_cursor_rel_lnum(wp, lnum));
+               num = (long)get_cursor_rel_lnum(wp, lnum);

            sprintf((char *)buf, "%*ld ", w, num);
 #ifdef FEAT_RIGHTLEFT
@@ -3481,7 +3481,7 @@
                            num = (long)lnum;
                        else
                            /* 'relativenumber', don't use negative numbers */
-                           num = labs((long)get_cursor_rel_lnum(wp, lnum));
+                           num = (long)get_cursor_rel_lnum(wp, lnum);

                        sprintf((char *)extra, "%*ld ",
                                                number_width(wp), num);

うむむ。でけた。ヒドイコードだけどもなんとかできた。

f:id:tkuro:20120127191122p:image

あとがき

マイナスの場合widthが足りなくなるので補正しなければ、なのとか、get_cursor_rel_lnum()がfoldの計算を変なふうにやってるので(実際に順に追っかけて見てる)微妙にカーソル位置によっておかしくなったりするんだけど、とりあえずはおっけー。

そのうち治そう。

結論

以上、参考になるでしょうか?

わかりにくかったらツッコミお願いしますー

*1:実は僕は読まずにやってしまった ,,,,,

2012-01-01

[]タッチパッドのスクロール方向を逆にする

MacOSXLionになってからというものあの逆スワイプが癖になってしまいました。Linuxノートでもつい逆に。ペンタブのスワイプも、ついつい。機械カウンタとか、ドラムマシンのスライダーとか、子供を撫でるときとか(違う

せめてLinuxくらいなんとかしたいなーと。

いや、あっという間

Xorgでこういうのいじるって言ったら・・・ とおもむろに man xmodmap してみたらもろにありました。

pointer = NUMBER ...

This sets the pointer map to contain the indicated button codes. The list always starts with the first

physical button. Setting a button code to 0 disables events from that button.

あとはxevでボタンコードを拾ってみると

ButtonPress event, serial 33, synthetic NO, window 0x5600001,

root 0xb1, subw 0x0, time 7352231, (39,130), root:(1005,183),

state 0x0, button 5, same_screen YES

ButtonRelease event, serial 33, synthetic NO, window 0x5600001,

root 0xb1, subw 0x0, time 7352231, (39,130), root:(1005,183),

state 0x1000, button 5, same_screen YES

ButtonPress event, serial 33, synthetic NO, window 0x5600001,

root 0xb1, subw 0x0, time 7353424, (39,130), root:(1005,183),

state 0x0, button 4, same_screen YES

ButtonRelease event, serial 33, synthetic NO, window 0x5600001,

root 0xb1, subw 0x0, time 7353424, (39,130), root:(1005,183),

state 0x800, button 4, same_screen YES

4 と 5をひっくり返せばいいのですね。

ということでやってみる。

pointer = 1 2 3 5 4 6 7 8 9 10 11 12

これをxmodmapに食わせてみると、、、あっけなく成功。

すばらつまらん。

結論

Linuxさいこー

2011-12-31

[]avahi-daemonエラーメッセージ

ふとdaemon.logを見てるとやたらとavahi-daemon

Dec  6 09:36:36 sawshark avahi-daemon[874]: Invalid query packet.
Dec  6 09:36:36 sawshark avahi-daemon[874]: Invalid query packet.
Dec  6 09:36:37 sawshark avahi-daemon[874]: Invalid query packet.
Dec  6 09:54:39 sawshark avahi-daemon[874]: Withdrawing address record for 2001:xxxx:1160 on eth0.
Dec  6 09:54:39 sawshark avahi-daemon[874]: Registering new address record for fe80::xxx:1160 on eth0.*.
Dec  6 09:55:29 sawshark avahi-daemon[874]: Registering new address record for 2001:xxx:1160 on eth0.*.
Dec  6 09:55:29 sawshark avahi-daemon[874]: Withdrawing address record for fe80::xxxx:1160 on eth0.

とかいうのを連呼しているのに気がついて、気になったので調べてみた。、という 2009/12 の下書き(!)が残っていたので落穂ひろいしてみました*1

avahi-daemonとは?

manしてみるまでよく知らなかったのですが*2、Zeroconfのオープンソースの実装だそうです。AppleのBounjour(旧名Rendezvous) としての方が知られてるかも。

manによると

Avahi mDNS/DNS-SDデーモンはAppleのZeroconf("Rendezvous"または"Bonjour"としても知られています)を実装しています。
このデーモンはローカルのIPアドレスを登録し, mDNS/DNS-SDを使った静的サービス 2つのIPC APIをローカルプログラム
mDNSレコードキャッシュ
simple protocol
avahi-dnsconfd(ユニキャストを処理)
nss-mdns(mDNSによる名前解決を行うlibc NSS プラグイン)。
D-Bus対応アプリへのオブジェクト指向I/Fも提供。

DNS-SDSDはService Discoveryとな。wikipediaによると

Avahi は、特定の構成情報のないローカルネットワーク上のサービスホストの発行と発見を可能とする。
例えば、ネットワークに接続したとき、即座にプリンタを検出し、ファイルを探し出し、他者と会話で
きるようにする。GNU Lesser General Public License (LGPL) の条件でライセンス提供される。
Avahi はBonjourのZeroconf仕様の実装であり、マルチキャストDNS、DNS-SD、RFC 3927/IPv4LL を実装
している。各種言語バインディングを提供しており(Python、Monoなど)、多くの Linux や BSD 系の
ディストリビューションに付随して出荷されている。モジュール化されているため、Avahi は GNOMEの
GNOME VFSやKDEのKIOなどに組み込まれている。

とのこと。他にもPulseAudio(sound server)やbazaarにもプラグインとして入ってるっぽいです。

でもZeroconfってなんとなくしか知らないので、少し勉強してみようかと。。。。

Zeroconfとは?

  1. ネットワークI/Fの自動設定
  2. マルチキャストの自動割り当て
  3. サービスの通知
  4. 名前引き(アドレス変換・逆変換)

ふむ。件のavahi-daemonはこのうち一番最後の名前のresolvに関係しているっぽいですね!

multicast を224.0.0.251宛に投げて、返事を待つ、というスタイルらしいです。

で、お試しには avahi-resolv, avahi-browserとかを使うと簡単。

来年やってみようかな

*1:今年の汚れ、今年のう・・・

*2:何気によく理解せずになんとなくhostname.localは使ってたり・・・

2011-10-20

[]Garbage Collection - Algorithms for Automatic Dynamic Memory Management

Garbage Collection: Algorithms for Automatic Dynamic Memory Management

Garbage Collection: Algorithms for Automatic Dynamic Memory Management

AADMMが届いたので読もうかなーというところ。 ??? のところが良くわからんくて面白そーなので集中予定です。

古典的アルゴリズムの紹介

  1. Classical Algorithms Overview
    1. Reference Counting, Mark-Sweep, Copying

.... and Compare those

  1. Issues to consider: Cyclic data structures, Roots and pointer finding, Processing cost, Space overhead, Heap occupancy and collector degradation

リファレンスカウンタの章

  1. Reference Counting
    1. Non-recursive freeing
    2. Costs and benefits of lazy deletion
  2. Deferred reference counting
    1. The Deutsch-Bobrow algorithm ???
    2. ZCT overflow ???
    3. The efficiency of deferred reference counting
  3. Limited-field reference counts
    1. Sticky reference counts, Tracing collection restores reference counts
    2. One-bit reference counts,
    3. Restoring uniqueness information ???
    4. The 'Ought to be Two' cache ???
  4. Hardware reference counting !!!!
  5. Cyclic reference counting
    1. Functional programming languages (read only だから、とかいう話かな?)
    2. Bobrow's technique ???
    3. Weak-pointer algorithms, Partial Mark-Sweep Algorithms
  6. Issues to consider: Ease of implementation, Control, optimization and correctness, Garbage collection delay , Space overhead, Recursive freeing, Mutator overhead, Space for reference counts, Locality of reference, Cyclic data structures...

マークスイープ

  1. Mark-Sweep Garbage Collection
    1. Comparisons with ref count
  2. Using a marking stack
    1. Making the recursion explicit, Minimizing the depth of the stack , Stack overflow
  3. Pointer reversal
    1. Deutsch-Schorr-Waite algorithm, Pointer-reversal for variable-sized nodes
    2. Costs of pointer-reversal !
  4. Bitmap marking
  5. Lazy sweeping
    1. Hughes's lazy sweep algorithm
    2. Boehm-Demers-Weiser sweeper ???
    3. Zorn's lazy sweeper ???
    4. Issues to consider: Space and locality, Time complexity, Object mobility

マークコンパクト

  1. Fragmentation
    1. Two-level allocation
  2. Styles of compaction
  3. The Two-Finger Algorithm ???
    1. Analysis, Variable-sized cells
  4. The Lisp 2 Algorithm
      1. おおぉぉぉぉぉぉ
  5. Table-based methods
    1. The break table, updating pointers
  6. Threaded methods
    1. Threading pointers, Jonker's compaction algorithm???
    2. Forward pointers, Backward pointers, Analysis of threaded algorithms
  7. Issues to consider: Smaller address space, Repeated copying Handling abnormal residencies, Locality, Choosing between compacting collectors

コピーGC

  1. Cheney's copying collector
    1. The tricolour abstraction, The algorithm, example
  2. Cheap allocation
  3. Multiple-area collection
    1. Static areas, Large object areas, Incremental incrementally compacting garbage collection

世代別GC

  1. The generational hypothesis
    1. Object lifetimes
  2. Generational garbage collection
    1. Pause time, The root set for minor collections, Performance
  3. Promotion policies
    1. Multiple generations, Promotion threshold, The Standard ML of New Jersey collector,
    2. Adaptive tenuring ??? (tenure は保持/保有する、とか)
  4. Generation organisation and age recording
    1. One semi-space per generation, Creation space, Age recording, Large object areas
  5. Inter-generational pointers( お、おっかない)
    1. The write-barrier, Entry tables, Remembered sets, Sequential Store Buffers
    2. Page marking with hardware support !!!
    3. Page marking with virtual memory support
    4. Card marking, Remembered sets or cards?
  6. Non-copying generational garbage collection
  7. Scheduling garbage collections
    1. key objects, Mature object spaces

インクリメンタル & 平行GC

  1. Synchronization
    1. Tricolour marking (またか)
  2. Barrier methods
  3. Mark-Sweep collectors
    1. The write-barrier, New cells, Initialization and termination, Virtual memory techniques
  4. Concurrent Reference Counting
  5. Baker's Algorithm
    1. The algorithm, Bounds on the latency of Baker's algorithm, Limitations of Baker's algorithm, Variations on Baker, Dynamic regrouping
  6. The Appel-Ellis-Li collector ???
    1. Improvements, Large objects, Generations, Performance
  7. Replication Copying Collectors
    1. Nettles's replicating collectors, The Huelsbergen and Larus collector, The Doligez--Leroy-Gonthier collectors ????
  8. Baker's Treadmill collector
  9. Hardware support for real-time garbage collection !!!

CのためのGC

  1. A taxonomy of ambiguous roots collection
  2. Conservative garbage collection
    1. Allocation, Root and pointer finding, Interior pointers, Problems of conservative garbage collection, Misidentification, Efficiency, Incremental/generational garbage collection
  3. Mostly Copying collection
    1. Heap layout, Allocation, Garbage collection, Generational garbage collection, Ambiguous data structures, The efficiency of Mostly Copying
  4. The optimizing compiler devil

C++のためのGC

  1. Garbage collection for object-oriented languages
  2. Requirements for a C++ garbage collector
  3. In the compiler or in a library?
  4. Conservative garbage collection
  5. Mostly Copying collection
    1. Generating pointer finding methods automatically
  6. Smart pointers
    1. Conversions without a smart pointer hierarchy, Multiple inheritance, Incorrect conversions, Some pointers cannot be smartened, Const and volatile pointers, Smart pointer leaks, Smart pointers and reference counting, A simple reference counting pointer, Smart pointers for flexible garbage collection, Smart pointers for tracing garbage collection
  7. Changes to C++ to support garbage collection
  8. The Ellis-Detlefs proposal ???
  9. Finalization
    1. Support for finalization

キャッシュ思慮のGC

  1. Modern processor architectures
    1. The effect of cache misses on CPU time
  2. Cache architectures
    1. Cache size, Placement policy, Write strategy, Special cache instructions.
  3. Patterns of memory access
    1. Mark-sweep with bitmap and lazy sweep, Copying garbage collection, Incremental garbage collection, Avoiding fetches
  4. Standard way to improve cache performance
    1. Cache size, Block size, Associativity, Special instructions, Prefetching

とにかくそそる本である

  1. Miss rate and overall cache performance
  2. Special purpose hardware...!!!

分散GC

  1. Network restrictions
  2. Virtually shared memory
    1. Shared virtual memory , Shared data-object model, Garbage collection over distributed shared memory
  3. Distributed garbage collection issues
    1. Taxonomy, Synchronization, Robustness
  4. Distributed amark-sweep
    1. Hudak and Keller ???
    2. Ali's algorithm ???
    3. Hughes's algorithm ???
    4. The Liskov-Ladin algorithm ???
    5. Augusteijn's algorithm ???
    6. Vestal's algorithm ???
    7. The Schelvis-Bledoeg algorithm ???
    8. The Emerald collector ???
    9. The IK collector ???

ロイヤルストレートフラッシュ!!!

  1. Distributed copying
  2. Distributed reference counting
    1. The Lermem-Maurer protocol ???
    2. Indirect reference counting
    3. The Mancini-Shrivastava algorithm ???
    4. The SPG protocol ???
    5. 'Garbage collecting the world'
    6. Network objects
    7. Wieghted reference counting
    8. Generational reference counting
  3. Garbage collecting actors
    1. Halstead's algorithm ???
    2. Marking algorithms ??
    3. Logically centralized collectors

そそりまくる本です。

はよう読みたいです。時間を下さい。

2011-10-03

[][]TIPなど

そういえば何となく書くだけ書いてて、全然説明してなかった事とか。順次増えるかも

  1. 裁断後、表紙と裏表紙はよく糊が残って癒着しているので、ここをまずはチェック。
  2. 癒着チェックは切断面側をパラパラめくって確かめるくらいで充分。特にS1500はまず間違いなく重なりチェックしてくれるので、かなり気楽。
    1. 深めに裁断する、というのも手。僕の読むような雑誌は本文までのマージンがかなりあるので、思い切って切り落としてます。その場合、表紙/裏表紙だけは別にすると良いかも。
  3. 信頼性が低いスキャナの場合は 100 とか切りのいいページで分けておくとスキャン枚数チェックが楽(例によってS1500はまず間違いなくエラーを検出するのであまり神経質にならなくてOK)
  4. ページ数えは書籍によってポリシーが違う。表紙を1ページ目と数えるとか、広告ページは別勘定だとか。こういったポリシーはだいたい出版社で固定なので、最初にこれを把握しておくとチェックが楽。
  5. 結構困るのが 白紙ページ(海外書籍に多い)。これはScanSnapはデフォルトでは勝手に削除する。と、言って残されると残されるでなんかいやーなので今は放置している。うーむ
  6. アンケートハガキや綴じ込み広告は難物。気がついたらなるべく先に外す。
  7. スキャナに紙を入れるときは、お札を数えるときのようにさばいて、奥側(最初にスキャンされる側)が先に入るように紙をずらす(Graphicsでいうsheer)しておくと良い。こうすると二百枚弱くらいならなんとか一発でいける
  8. S1500はなぜかトレイのガイドが異様に緩く設計されていて、簡単に広がってしまう。その結果、用紙がズレて斜めに入りジャムる。ガイドの横に何かコーン状のものを挟んでおく(僕は近くにあったギター用のジャックをはさんでます)とGOOD。ロック機構があれば良かったんだけど。*1
  9. ネットから検索/拾えるようにしておくと便利。数回仕事でも役に立ちました

*1:S1500でジャムるのの大半が、癒着部分が残っていた場合か、この斜めにズレて引っかかった場合なのです。ちなみに斜めになってもある程度であればScanSnapのソフトが補正してくれます