順列の問題を解く

駿台の講師陣が受験生に贈ることばを集めた広告が話題になっている。

解いたらスッキリする答えが出てくる問題とはこれ。

"GAKKOU"の6文字を並べ替えてできる360個の文字列を辞書式に並べるとき、100番目の文字列を求めよ。

JavaScriptで実装する場合の素直な書き方。再帰呼び出しを使う。

function permute(arr) {
  if (arr.length === 0) return [];
  if (arr.length === 1) return [arr];

  let result = [];
  for (let i = 0; i < arr.length; i++) {
    const currentElm = arr[i];
    const remainingElms = arr.slice(0, i).concat(arr.slice(i + 1));
    const remainingElmsPermuted = permute(remainingElms);
    for (let j = 0; j < remainingElmsPermuted.length; j++) {
      const permutedElms = [currentElm].concat(remainingElmsPermuted[j]);
      result.push(permutedElms);
    }
  }
  return result;
}

const arr = "GAKKOU".split("").sort();
const permutetion = permute(arr).map((elm) => elm.join(""));
const permutetionSet = new Set(permutetion);
console.log(Array.from(permutetionSet)[99]);

もう少しすっきりさせたやつ。

function permute(arr) {
  if (arr.length <= 1) return [arr];

  let result = [];
  arr.map((head, i) =>
    permute([...arr.slice(0, i), ...arr.slice(i + 1)]).forEach((rest) =>
      result.push([head, ...rest])
    )
  );
  return result;
}

は〜ん、なるほどね。受験生の努力が報われますように。

参考にした記事:Step-by-Step Guide to Array Permutation Using Recursion in JavaScript

PowerPoint for Macでデフォルトテンプレートをさくっと開く

WordではNormal.dotmというファイルが既存のデフォルトテンプレートとなっており、ファイルを新規作成するときのテンプレートを変更することができる。

PowerPointでは「新しいプレゼンテーション」というテンプレートがデフォルトになっていて、こいつを変更するにはWordと同様にしてNormal.potxでいけるんじゃない?って思ったんだけど、ダメだった。

ググったらblank.potxでいけるよっていくつかのサイトに書いてあったんだけど、それも無理。たぶんWindows限定。

既定のテーマは設定できる…けど?

確かに、テーマなら「既定のテーマとして設定」することができる。

f:id:k_sakurako:20211219011212p:plain
「既定のテーマ」が設定されると、PowerPointの「ホーム」画面でテーマをすばやく選択できるようになる。

設定する手順は、まず、ファイルを新規作成、あるいは、既存のファイルを開き、好みの色やフォントを設定する。スライドマスターでスライドのサイズを変えたり会社のロゴを入れたりすることもできる。

""

デザイン作業が終わったら、リボンの「デザイン」タブの「テーマ」ウィンドウの下にある下矢印ボタンでメニューを展開し、一番下の「現在のテーマを保存」を選ぶ。

ファイル名をDefault Theme.thmxにして「保存」する。保存先へのパスは以下の通り。

/Users/(username)/Library/Group Containers/UBF8T346G9.Office/User Content.localized/Theme/Default Theme.thmx

これで「既定のテーマ」は使えるようになったが「新しいプレゼンテーション」のデザインは変更されない。

Automatorを使ってblank.potxを開く

解決策としてはAutomatorを使って、パワーポイントを立ち上げたときにblank.potxを開く方法がある。

まずAutomatorアプリケーションで「ファイル」>「新規」と選択するか、Command + Nキーを入力する。

つぎに、ワークフローの種類を選択する。ここでは、8項目のうち先頭から2つめの「アプリケーション」を選択し、「選択」をクリックする。

「アプリケーション」を選択している状態。項目の説明“アプリケーション”は、自己実行型のワークフローです。“アプリケーション”にドロップされたすべてのファイルやフォルダがワークフローへの入力として使われます。

選択したら、アクションの追加を行う。「アクション」>「ライブラリ」>「ユーティリティ」>「シェルスクリプトを実行」を選択する。検索フィールドに「シェルスクリプト」と入れると一発で出てくる。

右側のペインに「シェルスクリプトを実行」アクションが追加されるので、コマンドを追加する。

open -a "Microsoft PowerPoint" "/Users/(username)/Library/Group Containers/UBF8T346G9.Office/User Content.localized/Templates.localized/blank.potx"

ファイルパスは一例でDocuments(書類)の中でもよい。入力し終えると以下のような状態になっている。

f:id:k_sakurako:20211219014313p:plain
アクションを追加し終えた画面

入力し終えたらファイル名をつけて保存する。ファイルは任意の場所に置いてよいが、Applicationsフォルダに保存すればLaunchPadから起動できるようになる。

アイコンを変更する

Automatorで作ったアプリケーションのアイコンは、デフォルトではAutomatorアプリのアイコンが設定されて、ロボットのアイコンになる。棒みたいなやつを持っててつよそう。

他にもアプリを作っていると、全てロボットアイコンになってしまい見分けがつきにくくなるので、アイコンを変更しておく。

まず、新しいアイコンを用意する。他のアプリケーションのアイコンでもよいし、自作してもよい。今回は、PowerPointのpotxファイルのアイコンを利用する。

ファイルのパスは以下の通り。icnsファイルはMacのアイコンに使われるファイルで、Windowsのicoという拡張子に相当する。

/Applications/Microsoft PowerPoint.app/Contents/Resources/POTX.icns

つぎに、作ったアプリの情報を表示する。「ファイル」>「情報を見る」と選択するか、CommandIキーを押す。左上にアプリのアイコンが表示されているので、そこに置き換えたいアプリのアイコンをドラッグ&ドロップする。

f:id:k_sakurako:20211219020954p:plain
アクションを追加し終えた画面

icnsファイルではなく、jpgやpngを単体のままアイコンとして使いたいときは、Finderで表示されているアイコンではうまくいかない。jpgやpngに関連づけられたアプリのアイコンになってしまう。

画像そのものをアイコンにするには、画像ファイルをプレビューアプリで開く必要がある。Command + Aで範囲を選択し、Command + Cでコピーし、作ったアプリのアイコンにペーストすれば変更することができる。

アイコンをPhotoshopで自作する

自作アイコンを作りたい人はApple Design Resourcesからテンプレートを落としてPhotoShopで編集しよう。

テンプレートのpsdファイルを開くと、アイコンのサイズごとにレイヤーが分かれている。たとえば"Icon-MacOS-512x512@2x.png"の"512@2x"をダブルタップで開く。

""

すると、新しいタブで@.psbなるタブが出てくる。こちらもレイヤーが重なっていて"Mask" > "Place Icon Here (Scale art to 824x824px)"を選択する。この"Place Icon Here"グループの中に画像のレイヤーを配置するのが重要なポイント。

以下の例では"Bg Fill"レイヤーを一番下にして重ねてみた。アイコンの画像はいらすとやさんのコウテイペンギンのヒナのイラストを拝借した。

""

psbファイルを保存すると、もとのpsdファイルと同じ階層に"Template - Icon - App-assets"というフォルダが自動で作られて、その中にサイズごとのpngファイルが格納される。

psbファイルの編集と保存を繰り返してテンプレートを埋めていく。(Command + Shift + Vで「同じ位置にコピー」を使うと楽。)

練習用に全部作ってみた結果がこれ。自分だけしか使わないのなら512x512@2xと256x256@2xがあれば十分だと思う。

"Photoshopアプリでの作業が完成した画面。512px, 256px, 128pxは全身が入っているアイコンで、32pxでは上半身だけ、16pxになるともう目と鼻しか入らない。"

ICNSファイルに変換する

PSDファイルから生成されたフォルダからICNSファイルを作るには、あともうひと手間必要。

任意の名前をつけた.iconsetフォルダーを作成する。"foobar.iconset"とか、なんでもいい。

さらに、ファイル名のIcon-MacOS-icon_にリネームする。たとえば"Icon-MacOS-512x512@2x.png"ならば、"icon_512x512@2x.png"になる。

cp -r "Template - Icon - App-assets" "foobar.iconset"
for f in foobar.iconset/* ; do ; mv $f ${f/Icon-MacOS-/icon_} ; done

コマンドを正しく実行できていればfoobar.iconsetフォルダーの中身はこうなる。

icon_128x128@1x.png    icon_256x256@1x.png icon_512x512@1x.png
icon_128x128@2x.png icon_256x256@2x.png icon_512x512@2x.png
icon_16x16@1x.png   icon_32x32@1x.png
icon_16x16@2x.png   icon_32x32@2x.png

(不要なファイルがあれば消去して)、iconutilコマンドを実行。

iconutil -c icns foobar.iconset

これでfoobar.icnsファイルが生成される。最後に、さきほど作ったアプリのアイコンにドラッグ&ドロップすればおしまい。

Kindle本 新書/文庫の新刊チェックに使えるURL

AmazonのKindle検索なんか使いにくいよね、ってことでURLを解読してみた。

  • 検索ワード (k=ブルーバックス)
  • Kindleストア (bbn=2275256051)
  • 出版日の新しい順 (s=date-desc-rank)
  • 出版社名 (rh=p_lbr_publishers_browse-bin:講談社)

出来上がった検索クエリ。

https://www.amazon.co.jp/s?k=(キーワード)&bbn=2275256051&rh=p_lbr_publishers_browse-bin:(出版社名)&s=date-desc-rank

OR検索は|で区切ることにより可能。(例: 岩波書店|講談社|筑摩書房)

以下、主要な出版社の一般向けレーベルを中心にリストアップした。

新書レーベル

文庫レーベル

その他

Mac向けOfficeでユーザー定義のフォントを追加する

PowerPoint for Macだとユーザー定義のフォントをアプリ上で追加できない。Windows版だとできるのに、なんでやねん。

というわけで定義ファイルを直接追加する方法を紹介する。

ファイルの場所

Office 365の最新版では、 ユーザー > (ユーザー名) > (xxxx.Office) > ライブラリ > Group Containers > ユーザーコンテンツ > テーマ > Theme Fontsとたどる。

ファイルパスは筆者の場合以下の通り。kazamiUBF8T346G9の部分は環境によって異なる。

/Users/kazami/Library/Group Containers/UBF8T346G9.Office/User Content.localized/Themes.localized/Theme Fonts

Finderアプリ上でファイルを追加した状態は以下の通りである。

FinderアプリでTheme Fontsフォルダを表示

ファイル

以下のようなテキストファイルを作成する。保存するときは.xmlファイルとする。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<a:fontScheme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="my-fonts">
    <a:majorFont><a:latin typeface="Arial"/><a:ea typeface="MS Pゴシック"/><a:cs typeface=""/></a:majorFont>
    <a:minorFont><a:latin typeface="Arial"/><a:ea typeface="MS Pゴシック"/><a:cs typeface=""/></a:minorFont>
</a:fontScheme>
  • MajorFontが見出し用、minorFontが本文用
  • a:latinが欧文フォント、a:eaが和文フォント

ファイル名がユーザー定義の名前になる。たとえば上記を"MSOffice.xml"として保存すると、再起動不要で即反映されて以下のようになっているはずだ。

f:id:k_sakurako:20211213101218p:plain
MSOffice.xmlを追加したあとの状態

この方法でRounded M+ 1cやBIZ UDP新ゴ、BIZ UDP新丸ゴを追加し、以下のような状態になった。

f:id:k_sakurako:20211213095011p:plain
PowerPointでユーザー定義のフォントを設定した状態

M1 MacにUTMでCentOSをインストール

某レクチャーのhands-onでM1 MacにVirtualBoxでCentOSを積もうとしたら2021/12現在未対応だったので代替策としてUTMを使用した際のメモ。

ホスト側環境: M1 Mac (メモリ16GB), Mac OS Big Sur

ディスクイメージを入手

まずCentOSのISOイメージを入手する。通常はDVDイメージを選択。4.5GBあるので1時間くらいかかる。

UTMをインストール

Terminal.appを開く

Macのターミナル環境はデフォルト(arm64)のままで進める。

Homebrewの入手

UTMはApp Storeから入手すると有償なので、Homebrew経由でインストールする。

Homebrewをまだ入れていなければ下記コマンドを実行:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

brew installを実行する

$ brew update
$ brew install --cask utm

インストールするとLaunchPadにUTMのアイコンが出る。

仮想マシンを作る

File -> New Virtual Machine (⌘N)で新規仮想マシンを作成する。

Information

NameとNoteはUTMのUI上で区別するためのものなので自分でわかりやすいように設定しておく。変えなくてもよい。

f:id:k_sakurako:20211212124515p:plain
New Virtual Machineを選択後に表示される画面

System

Architectureは入手したISOイメージに合わせる。x84_64のままでよい。

メモリはホストマシンの容量に合わせる。DVDイメージを入れるとインストール画面がGUIなので、4GBほど積んでおいたほうがよい。8GBなら4GB、16GBなら8GBを超えないように設定する。

f:id:k_sakurako:20211212125354p:plain
Systemタブ メモリ容量設定後の状態

Drive

まずインストール用のドライブを作成する。New Driveボタンをクリックして、Removalにチェックを入れ、InterfaceにUSBを選択。 さらにDisk Imageを作成。InterfaceはIDE、サイズは10GB(あるいは余裕を持たせて20GB)とする。

f:id:k_sakurako:20211212125056p:plain
Drive作成後の状態

Display

Emulated Display Cardを変更する。M1チップではまだGPU Supportedのものは使えないらしく、さらに、デフォルト値を選ぶとエラーが出るのでVGAを選ぶ。(vmware-svgaも使えたけどGUIがえらく重かった。)

f:id:k_sakurako:20211212125936p:plain
Displayタブ Emulated Display Cardを変更後

これで最低限必要な設定は完了なのでSaveして閉じる。

Network (optional)

CentOS7インストール後、SSH経由でMacのターミナルからアクセスしたければPort Forwardingを設定する。

SSHポートは22なので、Host Port、Guest Portともに22にする。Addressは変更不要。(別のアプリケーションでホスト側の22番ポートが塞がれている場合はホスト側を2222などにしてssh user@localhost -p 2222のようにして接続)

f:id:k_sakurako:20211212131234p:plain
Networkタブ Port Forwarding設定後

ISOイメージを仮想CD/DVDドライブに入れる

メイン画面に戻ったら、右ペインの一番下、CD/DVDという項目があるので、Browseをクリックし、ダウンロードしたISOイメージを入れる。

f:id:k_sakurako:20211212132530p:plain
メイン画面 CD/DVDにISOイメージが入っている状態

入れたらRun(▶︎)を押すと仮想マシンが起動し、CentOSのインストールが開始される。

インストール作業そのものは他の環境と同じなので省略。

インストール完了後、CD/DVDの項目をclearしないと再度インストールが始まってしまうので注意。

Excelファイル群の集計

集計対象データ

フォルダーの中に集計対象のファイル群をおく。集計対象のXLSX形式のファイルには「入力用」と「集計用」のワークシートがあり、「集計用」のワークシートは以下のようになっている。date(C列)は日付書式である。

month address date shift name answer
11月 $D$3 2021/11/01 A Kazami True
11月 $D$4 2021/11/01 B Kazami True
11月 $D$5 2021/11/01 C Kazami False

パッケージ

Python3.9.4上でOpenpyxlを使用する。

pip install openpyxl

コード

必要に応じてエラー処理などを書き足していけばよい。

from datetime import datetime as dt
import glob
import openpyxl

def get_worksheet(sheet):
    rows = []
    for row in sheet.iter_rows(min_row=2):
        data = [
            row[2].value.strftime("%Y/%m/%d"),
            row[3].value,
            row[4].value,
            row[5].value
        ]
        rows.append(data)
    return rows

def write_output(sheet, collected_data):
    output_data = [
        ["date", "shift", "name", "answer"],
        *collected_data
    ]
    for i, datum in enumerate(output_data, 1):
        for j in range(0, len(datum)):
            sheet.cell(i, j+1).value = datum[j]

def collect_data(files):
    file_count = 0
    collected_data = []
    
    try:
        for file in files:
            if "~$" not in file:  # 一時ファイルを除く
                continue
            wb = openpyxl.load_workbook(file, data_only=True)
            ws = wb["集計用"]
            data.extend(get_worksheet(ws))

    except Exception as e:
        print(f"エラーが発生しました: {e}")
    finally:
        print(f"集計対象ファイル数: {file_count}")
    return collected_data

def save_result(data):
    if len(data) == 0:
        print(f"出力データがありません。処理を終了します。")
        return
    
    wb = openpyxl.Workbook()
    sheet = wb.active
    sheet.title = "集計結果"
    write_output(sheet, data)

    current_time = dt.now().strftime("%Y%m%d_%H%M%S")
    output_path = f"./results/result_{current_time}.xlsx"
    wb.save(output_path)

    print(f"ファイルを書き出しました: {output_path}")


if __name__ == "__main__":
    target_files = glob.glob("./submitted_files/*")
    collected_data = collect_data(target_files)
    save_result(collected_data)

Highlight.jsを使う

アウトプット用のブログをいまさらながら。

さて、はてなブログのシンタックスハイライト機能はイマイチなのでhighlight.jsを導入することにする。

設定箇所

はてなブログProであれば<head>要素でscriptタグを使うことができる。

設定 > 詳細設定 > HEAD内タグ > <head>要素にメタデータを追加

はてな特有の注意事項としては<pre>要素にcode lang-javascriptというクラス名がつくのでマッチするようにlanguageDetectReを変更する。hljs language-javascriptが追加されていればOK。

スタイル

スタイル名.min.cssを呼べばよい。好みのスタイルがNordならばnord.min.cssである。ファイル名はhighlight.js demoのソースを参照。

サンプル

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/styles/nord.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/highlight.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', (event) => {
  document.querySelectorAll('pre.code').forEach((el) => {
    hljs.configure({
      languageDetectRe: /\lang-([\w-]+)\b/i,
    });    
    hljs.highlightElement(el);
  });
});
</script>

適用されていれば変わるはずである。

適用前

<pre class="code lang-javascript" data-lang="javascript" data-unlink=""></pre>

はてなブログのデフォルト状態

適用後

<pre class="code lang-javascript hljs language-javascript" data-lang="javascript" data-unlink=""></pre>

Highlight.js適用後