non vorrei lavorare

昔はおもにプログラミングやガジェット系、今は?

2018年版、Rustで多次元配列を使うには

こんばんは。連休の真ん中の日曜日、長男のPASMOのタッチの仕方をめぐり、乗換駅で妻と口論になり、自分だけ、訪問先に行くことなく、自宅に引き返してきました。@kjunichiです。

背景

abrakatabura.hatenablog.com

の方法が最近のRustでは使えないことが判明。

2018年7月時点でのRustで多次元配列を扱う方法

ndarrayを使うのがお手軽な模様。

Cargo.tomlに以下を追加

[dependencies]
ndarray = "0.11.2"

ndarrayでの多次元配列の使用例

以下の様なコードで、 1x2x3x4のサイズの4次元配列が扱える。

extern crate ndarray;
use ndarray::ArrayD;
use ndarray::IxDyn;
fn main() {
    let mut b = ArrayD::<f32>::zeros(IxDyn(&[1,2, 3, 4]));
    println!("b = {}",b);
}

関連記事

6年前の記事

5年前の記事

4年前の記事

2年前の記事

アレクサで「iPhoneを探す」をpuppeteerを使って出来るようにした

おはようございます。卒園式のDVDが完成し、その上映会を行い、久しぶりに長男の保育園の皆さんと再会し、寿退職された担任の先生、0歳児から担当してくれて、昨日はお泊り保育明けの先生も来てくださり、子供たちも再開を喜び、上映会も楽しめたようです。@kjunichiです。

既存方法の問題点

実は、このアレクサで「iPhoneを探す」は、IFTTT経由でiPhoneに電話をかけることで実現する方法がずいぶん前からあったのですが、 多分これは、日本ではできそうではないですし、電話代がかかる心配もあって見送っていました。

もう一つ

dev.classmethod.jp

に紹介されている方法ですが、多分これも、2要素認証で運用していると面倒そうなことが、 利用しているiCloudライブラリpyicloudGithubページを斜め読みする限りでは伺えました。

puppeteerで実現した

今回取った方法は、最近2要素認証でもブラウザ経由でiPhoneを探すのリンクに直接アクセスすると、自分の環境では、 2要素認証を回避してアクセスできるので、これで行けるかも?と思い試した。

なお、puppeteerの起動は、IFTTTでAlexaのトリガーを仕掛けて、Dropbox経由でローカルのPCにファイルを作成し、 PC側でこのファイルの作成を監視するとこで実現した。

f:id:kjw_junichi:20180708101311p:plain

いきなりAppleの嫌がらせにあうの巻

何故か、iframeで認証ページ、iPhoneを探すページとも組まれており、devtoolsで要素名を調べてもpageオブジェクト経由では アクセスできないようになっていました。

以下のページが大変参考になりました。

qiita.com

また、そもそも今回puppeteerを始めて使ったので、全般的なコードは公式ページの他、以下のページが参考になりました。

qiita.com

成果物

TARGET_ID、TARGET_PWDiCloudのアカウントを入れて、TARGET_PHONE_NAME は対象のiPhoneに付けている名前を入れる。 そして、pathはDropboxのパスを入れることで、動くはず。

const fs=require('fs')
const puppeteer = require('puppeteer');

const TARGET_ID = "test@mac.local";
const TARGET_PWD = "password";
const TARGET_PHONE_NAME = 'iphonename';
const path="D:/Dropbox/Amazon Alexa";

const findmyiphone = () => {
(async () => {
  const browser = await puppeteer.launch({headless: false});
  const page = await browser.newPage();
  page.goto('https://www.icloud.com/#find');
  await page.waitFor(12000);
  const dimensions = await page.evaluate(() => {
    return {
      text: document.body.innerHTML
    };
  });

  //console.log('Dimensions:', dimensions);
  //await page.type("input#account_name_text_field", "input");

  //await page.screenshot({path: 'example.png'});

  const frame = await page.frames().find(f => f.name() === 'auth-frame');
  await frame.type("input#account_name_text_field", TARGET_ID);
  const tform = await frame.evaluate(() => {
    return {
      text: document.body.innerHTML
    };
  });
  await frame.click('i');
  await frame.waitFor(1000);
  //await frame.waitFor('input#password_text_field',{timeout: 1000});
  await frame.type("input#password_text_field", TARGET_PWD);
  await frame.click('i');
  await page.waitFor(12000);
  const frame2 = await page.frames().find(f => f.name() === 'find');
  await frame2.click('label[id="sc2348-label"]')
  await frame2.click(`div[title="${TARGET_PHONE_NAME}"]`)
  await frame2.click('div[title="このiPhoneでサウンドを再生"]')
  //console.log(tform);
  await browser.close();
})();
}

fs.watch(path, (event, filename) => {
  if(filename&& event =="rename") {
      if(filename.startsWith("AmazonAlexa_findmyiphone")) {
          console.log("Find my iphone!")
          findmyiphone();
      }
  }
  console.log(event,filename)
});

あとがき

puppeteerでGUI非表示でやらせたかったものの、GUI表示しないと、エラーとなり、 まぁ、自分の用途では何が何でも非表示する必要もなかったので、これは放置してます。

また、Dropboxでのファイル作成もWindowsではIFTTTのデフォルトの日付入りだとファイルが作成されないので、 固定のファイル名にする必要があった。

参考資料

この記事を書いてからしばらくたちますが、以下のようにpuppeteerに関して日本語で書かれた書籍も最近は 出版されているようです。

ryoichi0102.hatenablog.com

関連記事

11年前の記事

6年前の記事

2年前の記事

1年前の記事

goroutineを使って高速にLAN内の*.localなホスト名の一覧を取得するツールを作った

こんばんは。次男が週末に初の保育園のお泊り会がある@kjunichiです。

Go言語による並行処理

Go言語による並行処理

背景

DHCPでLANに繋げる環境であれば、 raspberry piなどえはraspberrypi.localというホスト名でsshできたり、macOSなどでも ホスト名.localで手軽にアクセスできるため、/etc/hostsすら編集しなくても便利にリモートPC等に アクセスできる。

しかし、このホスト名が何か分からない場合、少なくともmacOSdns-sdコマンドではDNSの逆引きに 相当することが出来ず、数年間途方に暮れていた。。avahiはこれが出来るのを知っていた。

SOで以下のページを発見するも、最近までdigコマンドに結構なスターがついている意味が まるで分らなかった。

serverfault.com

最近になって、このdigコマンドが、21世紀のnslookupでmDNSにも対応しているので、 これでmacOSでもdigコマンドでホスト名.localをIPアドレスから逆引きできることが分かった。

IPアドレスから逆引きしてホスト名.localな名前を引くことが出来ることが分かったので、 LAN内のIPアドレスを片っ端から引数に指定して結果を表示すれば、やりたかった LAN内に現在どんなホスト名.localが存在しているのかコマンドができる。

コマンドラインで存在しないIPアドレスを指定して以下の様にdigコマンドを実行すると

dig +short -x 192.168.0.9 @224.0.0.251 -p 5353

かなり、待たされる。

ということで、Goでgoroutine使って、並行にコマンドを実行すれば良いのでは? ということを思いついた。

Goで外部プロセスの実行結果を取得する処理は「Raspberry Piの温度をgRPCを使ってElectronで作ったデスクトップマスコットに表示させた」の記事で習得済み。

学べたこと

同時に実行するコマンド数を絞りつつ、複数同時に実行する

さすがに、digコマンドに渡す引数のIPアドレスをクラスCで1から254まで指定してそれを同時に実行するのは ちょっとOSに優しくないだろうということで、同実行数を絞りつつ実行する方法を 探した。

mattn.kaoriya.net

今回のコードの大枠はこちらのコードをベースにさせてもらった。

for内でgoroutineを実行する際にやりがちなミスを学習

qiita.com

goroutineに渡しているループ変数は、ループされる度に作られる変数ではなく、 ループ全体で使われる変数

ただし、上の例だと文字列のアドレスを渡すことになるから この問題は発生しないのかも?と思いもしたが、Sleep消したら駄目だった。。。

ちなみに、この問題、VS Codeのおかげで早期に発見できた。

#golang vs codeのこの警告のおかげでサッサと問題解決出来た。

Junichi Kajiwaraさん(@kjunichi)がシェアした投稿 -

sprintf的なものがある

qiita.com

テンプレートの仕組みも見つけるも、ちょっと大げさだったので、 Cのsprintf的なものも見つけたので、今回はこちらを採用した。

成果物

こうして、今回も実際に自分の手を動かして取り組んだところ、多くの学びがあった。

github.com

今後の課題

あらたな使い道

iPhoneWifi接続になっていると、dareka-no-iPhone.localなどと一覧に表示さるので、自宅に自分や奥さんがいるかをコマンドラインでチェック可能になった

参考資料

今回はavahiのないmacOSで逆引きする方法としてdigコマンドを用いて行ったが、Windowsでもdigコマンドを インストールすることが以下の記事によると出来るようなので、たぶんWindowsでも動くのでは。

www.atmarkit.co.jp

関連記事

12年前の記事

6年前の記事