ぷろじぇくと、みすじら。

コンソールでくるくるするやつ for .NET Core

Created at:

コンソールで時間がかかる処理をやっているときなどにくるくるするやつを.NET Core(.NET Standard 2.0)で表示するライブラリを作りました。node.jsのcli-spinnersoraを参考にというか実質ポートみたいな感じです。これで.NET Coreでツールを作った時にもちょっとオサレにできるはず…!

使い方は簡単で Spinner.Start もしくは Spinner.StartAsync にアクションを渡すだけです。

await Spinner.StartAsync("Stage 1...", async spinner =>
{
    await Task.Delay(1000 * 3);
    spinner.Text = "Stage 2...";
    await Task.Delay(1000 * 3);
    spinner.Fail("Something went wrong!");
});

ちなみにくるくるするやつが記号や絵文字を使っているものが多い都合、WindowsではコマンドプロンプトのコードページがCP932のようになっていると残念なことになるのでコードページを見てASCII文字のアニメにフォールバックする仕組みが入っています(他のライブラリにはない)。

また ora と同様にCI環境のようなノンインタラクティブな時には発動しないようにして、結果のみが表示されるようになっています。

コマンドラインツールを作る際にはどうぞご利用ください。

Surface Book 2

Created at:

ついにモデルチェンジ(マイナーチェンジ)したSurface Book 2 (Core i7モデル)を買ったので、Surface Book 無印 (Core i5+dGPUモデル)からの変化でレビューというか気づいたところとかをいくつか。

暑さと重さ

Core i7(dGPU)モデルでは無印のdGPUモデルよりもベース側(通称下半身)が1mm程度厚くなり100g程度重くなっています。

Surface Book 2 vs Surface Book

無印のwith Performance Baseモデルと同じになったと言った方がいいかもしれません。大きく重くなるの嫌だなーとは思っていたのですが、実際比べると元から重いのでもはや誤差みたいなものでした。とはいえMacBook Proは薄く軽くなる方へ進化しているので頑張っていただきたかったところですね。

ベースのヒンジ

ベースのヒンジは見た目が変わらず中身が変わったという話ですが、比べてみると開く角度が若干広がっています。ヒンジを改良するなら開く角度変わらないかなーと思っていたのでうれしい改修ですね。

Surface Book 2 vs Surface Book

キーボードまわり

キーボードのファンクションキーのFnでの機能をみると若干変わっていました。以前はキーボードのバックライトの明るさ調整(F1とF2)でしたが画面の明るさ調整になっています。ちなみにキーボードのバックライトは1つのキーで段階切り替えになっています。…まあ、そうなるな。

Surface Book 2 (Keyboard, Function keys)

CPU

目に見えないところで地味に変わっている点としてディスプレイ側がファンレスとなったのはとても大きいです。

第8世代 Core i7が搭載されたことで4コアになったにもかかわらずファンレスになっていてヤバそうな感じがしますが、負荷のかかり続けるセットアップ時にサーマルスロットリングのようなものを感じなかったので基本問題なさそうです。素直にすごいですね。当然ベース側にはGPUの冷却用のファンはあるのでGPUをヘビーに使うとそちらはファン音がします。ちなみに日本では発売されない15インチモデルはディスプレイ側にもファンがついているそうです。

CPUの速度自体は第6世代のCore i5と比べると当然速いというか、デスクトップでCore i5-4570Sを使っているのですが、それと同等かむしろ上回るぐらいなので十分です。やはり4コアは偉大…。

その他

一応今回からついたUSB Type-Cにも触れておくと、この口からSurface Bookを充電できます。出力が足りないと充電できないのはMacBook Proと同じです。試した感じNintendo SwitchのACアダプターで充電できたのでMacBookのACアダプターでも充電できそうです(試してはいない)。

最後は買うときの注意ですが、初代はペンが同梱でしたがSurface Book 2では別売りになっているのでペンを使いたいと思っているのであれば一緒に買う必要があります。Surface Proとかもそうみたいなのでそういう方向性なのでしょうか。その一方でOfficeは日本モデルらしくOffice Home & Business Premiumがついています。Office 365をすでに契約していると完全に損なので同時購入でOfficeを安くみたいなキャンペーンにしてむしろOfficeを外してほしいですね。

最初はほとんど変わりがなくて面白くないなーと思ったのですが、Surface Dockはそのまま使えるし、細かい改善があったりCPUも体感で圧倒的に速くなっているので全体的な満足度は高いです。あとは値段がもう少しお安くなるといいのですがー。

Google Homeからプロセス、WebHookやIRKitを呼び出してあれこれする

Created at:

Google Home/AssistantからプロセスやWebHook、IRKitなどを呼び出すサーバーアプリケーション、Beatrice を公開しました。

これを家の中で立ち上げて連携しておくと、プロセスを実行したり、IRKitをキックしたり、WebHookを呼び出したりをGoogle Homeから仮想的なデバイスとして認識できるので、例えば「OK Google、Excelをオン(オフ)にして」でExcelを起動したり終了するといったことができます。

WebHookとプロセス実行さえあれば何とでもなるじゃろ感というやつです。

特徴 & IFTTTを使う場合との違い

[それIFTTTでできるよ]と言われそうですがBeatriceはIFTTTのトリガーと異なり、スマートホームデバイスのサービスとして振舞います。

例えばIFTTTのtriggerでは特定のワードに反応してWebHookを呼び出すといった形のため特定のワードを正確に発音する必要があり、「明かりをすべて消して」とお願いしてもホームデバイスとして認識していないので反応しません。

対してBeatriceはキーワード反応ではなく、操作する対象をスマートホームデバイスのサービス(Hueなどと同じ)のデバイスとして見せかけるため、他のホームデバイスと同列の操作可能がです。例えばプロセスの起動/終了を仮想的なスイッチとして公開できるので、いろいろなことができます。ただしその分設定は面倒です。

動機

最初はGoogle Homeで明かりのオンオフなどを行うのにIFTTT経由のIRKit呼び出しでいいかと思ったのですが、いざ使ってみるとそもそも設定したワードから外れると認識されない、スマートホームのデバイス扱いではないのでまとめてコントロールする命令が効かないといったところがイマイチだなーと感じていました。

そこでHomeKitに対するHomebridgeのようになんでもスマートホームのデバイスに見えるようにブリッジするツールがあればよいのではというところが出発点となっています。

仕組み

一般的にGoogle Homeの連携アプリはDialogflowあたりを使うと思いますが、Beatriceでは先にも書いた通りスマートホームデバイス向けのGoogle on ActionsのSmart home appの仕組みを利用します。

Smart home appの作り方のページにも書いてあるのですが、Smart home appはBeatriceに限らず下記の図のようにサービス登録して、連携するというフローとなります。

要するにサービスはOAuthのサーバーとなって、Googleは音声入力を解釈してコマンドに変換した後OAuthのクライアントとして投げつけてくるという構成ですね(意外とめんどくさい)。

そもそもこれは一般向けではなくHueのようなデバイスを多くのユーザーに対して提供する企業向けの仕組みです。そのため完全個人の固有のものであるBeatriceはテストプロジェクトとして動かすことになり、完全無保証です(!)

ちなみにもしこのようなものを作りたい(作ることになった)という方は actions-on-google/actionssdk-smart-home-nodejsというサンプルがあるのでこちらを参考にするのがおすすめです。

動作環境 & クイックスタート

外部からアクセスでき、.NET Core 2.0が動けば動きます。つまりWindows、Linux、macOSで動作します。Raspberry Pi 3 + Raspbian Lite (Linux)でも動作可能です。

お試ししたい方はQuickStart(Quickとは言っていない)にそってお試しください。これ以外のドキュメントはREADMEしかないのです…。

なお現状サポートしているFeature(Beatrice用語で機能単位)はIRKit, WebHook, Process, Loggingです。

制限

テストプロジェクトで動かす都合、1アカウントにつきプロジェクトは1つしか有効にできません。 そもそも使い方として想定されていないので使えなくなってもまあそういうものです。

おわりに

現状ではオンオフ以外に対応していませんがステートを公開したり、モード切替、Web UIからの実行テストなどにも対応していきたいところです。

微妙なハックをしてる感のある代物の上、まだ作りかけなところも多くきちんと動かないかもしれませんが、もしお役に立つようであればどうぞご利用ください。

ドメインに参加しているとMicrosoftアカウントで同期できない

Created at:

問題

Windows 10でドメインに参加しているデバイスでMicrosoft アカウントを登録してもアカウントの同期設定を有効にできない問題があります。その一方で以前からある環境は有効なままとなっていることもあります。

発生する環境

理由

設定とデータのローミングに関する FAQにあれこれ書いてありますが、要するにWindows 10 Creators Update以降ではいわゆる企業のアカウント(AD, Azure AD)とMicrosoftアカウントを結びつけることができなくなった影響です。

企業の所有の下で Azure AD に接続された Windows 10 デバイスの Microsoft アカウントは、今後ドメイン アカウントに接続できません。 Microsoft アカウントをドメイン アカウントに接続してそのユーザーの全データを Microsoft アカウントに同期させる機能 (Microsoft アカウントと Active Directory との接続による Microsoft アカウントでのローミング機能) は、Active Directory と Azure AD とが接続された環境に参加している Windows 10 デバイスからは削除されます。

Feedback Hubにもフィードバックが起票されていますが、企業アカウントの場合にはMSAではなくてAzure ADのEnterprise State Roamingを使ってくださいと。

In the Windows 10 Anniversary Update, domain joined users who connected their Microsoft Account (MSA) could roam settings and data between Windows devices. Many IT Pros told us that this functionality was not consistent with their policies for managing information owned by the organization. They did not want their PCs roaming to an individual’s personal cloud. A group policy to prevent users from connecting their MSAs did and does exist, but this setting also prevents users from easily accessing their personal Microsoft services. To address IT Pro concerns, we removed the ability for domain joined machines to roam with an MSA. Enterprises can still enable Enterprise State Roaming with Azure Active Directory.

ややこしいのが同期できている環境も場合によってはあるというところでしょうか。

どうやらCreators Update前にすでに同期していた環境であれば設定が引き継がれているためMicrosoftアカウントとの同期が可能なままということのようです。そのため新しくセットアップした場合に設定できずにハマります。

現時点で一応機能は残っているのでレジストリをいじると動かせるという話もありますが、今後を考えるとやめておいた方がよい気もします。

まとめ

つまり要するにどういうことなのかという話ですが…

確かに一貫性はありそうではありますが…うーん、今までできていたので不便ですね…。

まあとりあえずこれを踏まえて新しく設定するのであればアカウントの種類の使い分けとしては以下のような感じにするとよさそうです。

メモ: Enterprise State Roamingで同期するとテーマが同期されない

ところでAzure Active Directoryに参加したデバイスでEnterprise State Roamingを利用した同期を行った際、テーマの設定(背景、ロック画面、アクセントカラー)が同期されませんでした。ExplorerやEdge、タスクバーなどの設定は同期されているので謎です…。

ASP.NET CoreでLet's EncryptのChallengeのような拡張子なしのファイルを返す

Created at:

ASP.NET Coreの StaticFiles ミドルウェアは拡張子が既知のMIMEタイプに見つからない場合(不明なMIMEタイプ)、ファイルが見つからないものとして扱います。ところが場合によってこの挙動では困る場合があります。

例えばLet's Encryptは認証のために /.well-known/acme-challenge/Kk5osRC8Q2IKAVgreqBx6lCNgZ-nxzyKje8HJa611_c のようなパスにアクセスを試みますが、標準の挙動のままであればファイルがあっても404が返ってエラーとなります。わかりやすい組み合わせではAzure App Serviceで.NET CoreとLet's Encrypt Site Extensionを利用している場合に発生します。

解決方法1. StaticFiles のオプションで不明な種類も返せるようにする

UseStaticFiles メソッドには StaticFileOptions という StaticFiles ミドルウェアの設定を渡せますが、その際に不明な種類を返せるようにする ServeUnknownFileTypes プロパティがあるのでそれを true にすることで返せるようになります。

app.UseStaticFiles(new StaticFileOptions
{
    ServeUnknownFileTypes = true,
    DefaultContentType = "application/octet-stream"
});

ただしこの設定を行うと、アプリケーション全体に反映されてしまうので意図せずファイルが公開される可能性が増えるのでやらなくていいのであれば設定したくないものでもあります。

解決方法2. ファイルの種類を提供する IContentTypeProvider を実装する

StaticFiles ミドルウェアはファイルの種類を取得するためのプロバイダー IContentTypeProvider を受け取ることもできます。この IContentTypeProvider にはファイルパスも渡ってくるのでパスを見て判断できます。

例えばLet's Encryptが来るのは /.well-known/acme-challenge/ 以下と分かっているのでそこだけ知っているかのように処理をして、それ以外はデフォルトの FileExtensionContentTypeProvider や指定された IContentTypeProvider に任せます。

public class LetsEncryptWellKnownContentTypeProvider : IContentTypeProvider
{
    private IContentTypeProvider _baseProvider;

    public LetsEncryptWellKnownContentTypeProvider()
        : this(new FileExtensionContentTypeProvider())
    { }

    public LetsEncryptWellKnownContentTypeProvider(IContentTypeProvider baseProvider)
    {
        _baseProvider = baseProvider;
    }

    public bool TryGetContentType(string subpath, out string contentType)
    {
        if (subpath.StartsWith("/.well-known/acme-challenge/"))
        {
            contentType = "application/octet-stream";
            return true;
        }

        return _baseProvider.TryGetContentType(subpath, out contentType);
    }
}

IContentTypeProvider を実装したら、StaticFileOptionsContentTypeProvider プロパティにセットすれば完了です。

app.UseStaticFiles(new StaticFileOptions
{
    ContentTypeProvider = new LetsEncryptWellKnownContentTypeProvider()
});