2019/04/26

Explorer でフォルダを開いてファイルを選択(既に開かれている場合は再利用) - Delphi

Windows Explorer でフォルダを開いてファイルを選択、これは通常の explorer.exe /select, オプションで実現可能ですが、既にフォルダが開かれている場合、そっちを再利用したい

参考文献

uses 節に FileCtrl, ShlObj, ActiveX が無ければ追加
function OpenFolderAndSelectFile(FileName: string): boolean;
var
    DidInitCOM: boolean;
    IIDL: PItemIDList;
begin
    Result := False;
    DidInitCOM := False;
    try
        IIDL := ILCreateFromPath(PChar(FileName));
        if (IIDL <> nil) then
            try
                Result := (SHOpenFolderAndSelectItems(IIDL, 0, Nil, 0) = S_OK);
            finally
                ILFree(IIDL);
            end;
    finally
        if DidInitCOM then
            CoUninitialize;
    end;
end;

VoIP GW - ODトランク接続の結線とメーカー別(NEC, 日立, ナカヨ)端子名称

専用線等で使われるODトランクの結線と共にメーカー(NEC, 日立, ナカヨ)ごとに名称がバラバラなのでまとめてみた

VoIP GWへRJ45(A結線)接続した場合のPBX側端子名称
PBX側VoIP GW側
日立ナカヨNECRJ45信号NECナカヨ日立
SSBBSB1(緑白)SGGSRB
SSASSM2(緑)ESRSRA
TBSL24WS(ring)3(橙白)4WR(ring)RL2RB
RBRL24WR(ring)4(青)4WS(ring)SL2TB
RARL14WR(tip)5(青白)4WS(tip)SL1TA
TASL14WS(tip)6(橙)4WS(tip)RL1RA
SRASRE7(茶白)MSSSSA
SRBGSG8(茶色)SBBSSB
※VoIP GW 側は、日立であれば NTシリーズ, NECであれば IP-Masterシリーズ等です
※アース起動の場合、PBXによってSSB-SRB間にジャンパーが必要です


一般的にPBX側はクイックコネクタですが、両端が RJ45の場合、SS ⇔ SR, R ⇔ S の上り下りが逆になるように接続

2019/04/19

Webフォームからの spam対策 - javascript

Webフォームからの広告入力対策

その1 - URL入力禁止
<script type="text/javascript">

 function checkUrl(form){
  for(var i=0; i < form.children.length; i++){
   if( form.children[i].nodeName.toUpperCase() === 'TEXTAREA' ){
    var urlCount = (form.children[i].value.match(/http(s)?:\/\//g)||[]).length;
    if( urlCount > 0 ){
     alert("テキストエリアにURLは記載できません");
     // form.children[i].value = '';
     return false;
    }
   }
  }
  return true;
 }

</script>
スクリプトを追加して、フォームのonsubmit へ checkUrl を記載
例) <form onsubmit="return checkUrl(this);">

その2 - コピペ禁止
<script type="text/javascript">

 window.onload = function(){
  document.body.onpaste = function(){
   alert("このページはペーストが禁止されています");
   return false;
  }
 }

</script>

2019/04/18

Google スプレッドシートの ImportXML関数に XPath をコピペしても #N/A になる原因

Google スプレッドシートで他サイトの情報を取得する(スクレイピングって言うの?)のに便利な ImportXML 関数

よくある解説には、
Chrome なら 右クリック→検証
取得したいエレメントで Copy → Copy XPath で得られた値の ダブルコーテーションをシングルに置き換えて、=ImportXML(url, xpath)
とやれば、ホラ簡単!
みたいなのがあるけど、ほとんど取得できねぇ~~~~~~~  #N/A

ということで原因と対策を調べてみた
ここでは、とあるサイトの値を取得するというよくあるパターン

最初に問題となるのは、取得するサイトの文字コードが UTF-8 ではない場合
これは、相手の問題なので今回はあきらめる

次に今回の本題 XPath の値がなぜ流用できないか、というか面倒なので流用したい
XPathは、主にソース固有の場所(id等は一意なので)からの相対パスとなる

該当部分のHTMLソース

ソースを見ると
div[id='cnt01']→div[の1番目]→table[の1番目]→tr[の2番目]→td
となっている

デベロッパーツールのエレメント構成

ここで得られる XPath の情報(コーテーションは変更済み)

//*[@id='cnt01']/div[1]/table[1]/tbody/tr[2]/td

このまま ImportXML へ貼り付けても そんなんありません(#N/A)となるが
//*[@id='cnt01']/div[1]/table[1]/tbody/tr[2]/td
//*[@id='cnt01']/div[1]/table[1]/tbody/tr[2]
//*[@id='cnt01']/div[1]/table[1]/tbody
//*[@id='cnt01']/div[1]/table[1]
と上位へ変更してみると、突然表示されはじめるポイントがある
(もぅ、お気づきでしょう。というか画像に答え書いてあるけど)

デベロッパーツールで表示されるエレメントツリーは、ソースで省略されたタグを補完して正しい形にしたものです(こういうライブラリを用いて修正したりする)
したがって、上記例では tbody が補完されているため、そのまま XPath を利用しようとしても、そんなエレメントありませんとなるワケです

上記の例では tbody を取り去った下記の表記が答えとなります

//*[@id='cnt01']/div[1]/table[1]/tr[2]/td

つまり、ソースコードをベースに記述しなければならない ということです

2019/04/15

GOM Player 終了時のブラウザ広告を止める

GOM Player が終了時に既定のブラウザで広告を表示するようになった

レジストリを調べると広告を表示した時刻を Unixtime で記録して、この値が24時間以上(たぶん)古いと広告を出しているようなので、値を未来へ変更
※そのうち対策される可能性があります

レジストリの変更手順
  1. ファイル名を指定して実行(Win+R)で regedit を入力、レジストリエディタを起動
  2. \HKEY_CURRENT_USER\Software\GRETECH\GomPlayer を開く
  3. EndingBrowser の値を 10進数で 1735657200 (2025/1/1)等の未来に設定


2019/04/12

Python のキーワード引数へ変数を使う

Python のキーワード引数へ変数を使いたい
→ 辞書(dict)を利用して、連想配列のような形で渡す

def main(): option1 = 100 option2 = 200 options = {'opt1': option1, 'opt2': option1} test('Test', **options) # や test('Test', **{'opt1': option1, 'opt2': option2}) def test(s, *, opt1=1, opt2=2): print(s) print(opt1) print(opt2) print('')

Python3 でシリアルポートを使う

centos7 上で、Python3 でシリアルポートのモデム(実際はUSBポートに接続した Omron ME5614U2)へATコマンドを実行

デバイスの確認
/dev で ls
Omron ME5614U2 をUSBポートへ差し込んだら認識してました
/dev/ttyACM0 ←これ

pyserialのインストール
# pip install pyserial

python3コード
import serial ser = serial.Serial('/dev/ttyACM0', baudrate=9600, timeout=3) ser.write(b"AT\n") print(ser.read(16).decode(encoding='utf-8')) ser.close()
※python3からバイト列でやり取りするようになっているので、変換が必要です

引数の timeout は、read() で指定するサイズ(16byte)に到達しなくても、readが発生する時間(sec)です。read に貯まっているサイズを取得する inWaiting() を監視して、都度取得することも可能です。

2019/04/11

コンビニで貯められるポイントと還元率

コンビニで貯められるポイント(利用可能なポイントカード)と還元率 - 2019-04-11
楽天ポイントTポイントdポイントWAON
ポイント
WAON
POINT
Pontananaco
セブン-イレブン------1.00%
ファミリーマート0.5%0.5%0.5%----
ローソン--1.0%--1.0%-
ミニストップ---0.70%0.5%--
サークルKサンクス1.0%------
ポプラ1.0%------
スリーエイト1.0%------
色→要決済2019/11以降
※レシートポイント、クレジットカード一体型やポイントアップ制度によるポイントアップ等は反映してません

私は、ポイントが貯まったと実感するほどコンビニで買物しないのですが、いずれも切り捨てのため、0.5%は200円未満, 1.0%は100円未満では購買によるポイントがそもそも付与されなかったりします。
したがって、1%還元の店で 10万円使っても 1,000ポイント貯まる可能性は限りなく低くなります。
クレジットカード決済のポイントとあわせるとか、他で貯まったポイントを利用できるという意味ならあるかもしれませんが...

2019/04/09

Amazon Prime から Twitch Prime を有効にできない【解決】

大変申し訳ありませんが、お客様のアカウントで Twitch Primeを有効にできません。
Twitchプライムを有効にしている間にエラーが発生ししたようです。
一般的な問題には、クレジットカードが無効か拒否されている可能性がある場合に、プライムのサインアップに使用されるクレジットカードに関する問題などがあります。 クレジットカード情報の更新を含め、お客様のプライムメンバーシップを管理するには、ここをクリックしてください。 他の一般的な問題については、ここをクリックしてください。

紐づけの手順

  1. Amazon Prime 会員になる
  2. Twitch で会員登録する(この時点では無料会員)
  3. ブラウザをプライベートモードで起動
  4. Amazon へサインイン
  5. Twitch へサインイン Twitch Prime を試すから 日本を選択する
  6. 紐づけする Amazonアカウントの確認 → Twitch Prime へ

確認と試したこと

  • Amazon.com (米国の)のアカウントがあれば、Amazon.co.jp とメールアドレスを別にする(Amazon Echo で日本語に反応しないときも同じ)
  • ブラウザのプライベートモードを利用して紐づけを行う
  • Amazon Prime の支払い方法が登録されている
  • Amazon Prime の支払い方法に登録された手段で、少なくとも1度は決済を行っている ← 今回コレがひっかかっていた

私の場合、Amazon Prime 支払の後、クレジットカード更新があり、支払い方法を一旦削除して再登録していた(同じカードを延長すれば問題なかった)ので、Amazon Prime の支払い方法が登録されていない状態だった。そして、Amazon Prime の支払い方法を登録したものの、決済を一度も行っていなかったため、Twitch Prime との紐づけが有効にならなかったらしい。
Amazon Prime へ登録されている支払い方法で買い物をした翌日、紐づけて続きを行ったら、問題なく Twitch Prim へ登録が完了した。



コールバックから Delphi VCLのCaptionを変更すると文字列などが乱れる

コールバックから呼ばれる関数内で、VCL(今回は Label )のCaptionを変更すると、表示が乱れる(フォントサイズや幅がおかしくなる)

スレッド内と同様に Synchronize 内からVCLへアクセスする
    TThread.Synchronize(nil,
        procedure
        begin
                Label1.Caption := AFilename;
        end);