Author Archives: admin
pipでパッケージをアップデートする
個々のパッケージをアップデートする
1 |
pip install <package_name> --upgrade |
一括でアップデートする
1 2 |
pip install pip-review pip-review --interactive |
viewport覚書
前提知識
デバイスピクセルとCSSピクセル
デバイスピクセルはscreen.widthなどで取得できるもので物理的ピクセルを表す。CSSピクセルはwindow.innerWidthなどで取得できるもので、ズーム値によって異なる。
screen.widthよりもエレメントのwidthが小さければ画面に収まることになる。しかしユーザがズーム機能を使って200%とかにするとそうはならない。ズーム機能はピクセルを広げる機能と考えられるのでCSSピクセルのサイズはズーム値によって異なる。
デバイスピクセルはズームに関わらず常に一定であり、CSSピクセルはデバイスピクセルにズーム率を掛けたものになる(実際は縦横ともにズームされるので平方で掛ける)。
screen.widthはスクリーン全体の幅でデバイスピクセル値なのでブラウザのズーム値では値は変わらないが、window.innerWidthはブラウザウインドウの幅を表しCSSピクセルなのでズーム値によって値が変わる。(ズーム値を100%以下にしていくとwindow.innerWidthのほうがscreen.widthより大きくなることもある)
viewport
画面の狭いスマホではviewportと呼ばれる仮想のウインドウにページをレンダリングし、その後ページをひと目で見れるように全体を縮小する。ユーザはスワイプやズームを使って見たいところにフォーカスする。
これはモバイルに最適化されていないサイトをできるだけ見やすいようにする仕組み
visual viewportとlayout viewport
モバイル端末では画面が小さすぎるので、viewportを2つの概念に分割する。
visual viewportは画面に表示されているページの一部。ユーザはスクロールやズームで表示内容を変えることができる。layout viewportは全体でvisual viewportはlayout viewportの一部を表示していることになる。
モバイル端末ではlayout viewportの値は800pxから1000pxくらいになっている。モバイル端末の幅は400pxくらいなので実際よりも大きい値になる。デスクトップではブラウザウィンドウのサイズになっている。
CSSの%で指定されている値はlayout viewportに対して適用される。
モバイル端末のブラウザでは初期表示時は完全にズームアウトされた状態で表示されることが多く、このときは2つのviewportは一致している。
2つのviewportはCSSピクセルで測られ、visual viewportはズームによってサイズが変わる。
document.documentElement.clientWidthはlayout viewportの幅を返す。メタタグのviewportがない限り常にこの値は一定であるが、document.documentElement.clientHeightは端末を回転させて縦横が変わると変わる。
window.innerWidthはvisual viewportの幅を返す。
viewportメタタグ
viewportメタタグがない場合はサイズ指定なしのエレメントは親のサイズを継承するのでlayout viewportのサイズになる。layout viewportのデフォルトサイズは800px~1000pxだったのでエレメントもそのサイズになり、通常とても小さく表示される。
<meta name="viewport" content="width=320">
この記述があると、layout viewportの幅が320pxになり、最初の表示のときでもエレメントのサイズは320pxになるので小さく表示されない。
まとめ
デスクトップブラウザではviewportはブラウザウィンドウの幅と同じなので気にすることはなかった。モバイル端末ができて、どうやって今までのサイトを表示しようか考えたときにlayout viewportという概念で800pxくらいの全体のサイズを決め打ちして表示するようにした。しかしそれだと表示がとても小さくなってしまうので、メタタグviewportができてここでlayout viewportのサイズを指定できるようにした。
参照
マウスホイールが回転がたまに逆向きになる
マウスの故障の話。マウスを長期間使っているとホイールを下に回転してるのにたまに上回転になったりして、すごく煩わしいので直したい。
大体の場合はほこりが詰まっているだけだと思うので、分解してほこりを除去すればいいのだが安いマウスの場合、分解したときに固定されていた部品が外れて元に戻すのがすごく大変になったりするので、まずは分解しないで直したい。
やり方はホイールの脇の隙間から軸に向かって狭くて強い空気を送ってほこりを吹き飛ばす。多くの場合右側に軸があると思う。
自分の場合はこれで吹いたらほこりが結構吹き飛んでとりあえず直った感じになった。もしこれがなければストローとかで吹きかければいいと思う。
分解する場合は蓋を外すときに細心の注意を払って部品が吹き飛んだりしないようにして、固定されている部品の状態を維持するようにこころがける。
回復パーティションが2つある
Windowsをアップグレードすると回復パーティションが新たにつくられることがあるそうだ。古い回復パーティションはもう必要ないため削除してもいいらしい
注意:以下の作業はシステムが壊れる可能性があるので自己責任でお願いします。
今使ってる回復パーティションを見つける
管理者権限でコマンドプロンプトを起動しreagentc /info
を実行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
C:\WINDOWS\system32>reagentc /info Windows 回復環境 (Windows RE) およびシステム リセット構成 情報: Windows RE の状態: Enabled Windows RE の場所: \\?\GLOBALROOT\device\harddisk0\partition3\Recovery\WindowsRE ブート構成データ (BCD) ID: 2983278f-a0ba-11ea-b1f0-000c29ee486d 回復イメージの場所: 回復イメージ インデックス: 0 カスタム イメージの場所: カスタム イメージ インデックス: 0 REAGENTC.EXE: 操作は成功しました。 C:\WINDOWS\system32> |
ここから今使ってる回復パーティションはharddisk0\partition3
であることがわかる。
回復パーティションを削除する
削除にはDISKPARTを使う。管理者権限でコマンドプロンプトを起動して以下のように行う。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
C:\WINDOWS\system32>diskpart Microsoft DiskPart バージョン 10.0.19041.964 Copyright (C) Microsoft Corporation. コンピューター: WIN DISKPART> list disk ディスク 状態 サイズ 空き ダイナ GPT ### ミック ------------ ------------- ------- ------- --- --- ディスク 0 オンライン 64 GB 0 B DISKPART> select disk 0 ディスク 0 が選択されました。 DISKPART> list partition Partition ### Type Size Offset ------------- ------------------ ------- ------- Partition 1 プライマリ 100 MB 1024 KB Partition 2 プライマリ 62 GB 101 MB Partition 3 回復 467 MB 63 GB Partition 4 回復 450 MB 63 GB DISKPART> select partition 4 パーティション 4 が選択されました。 DISKPART> delete partition override DiskPart は選択されたパーティションを正常に削除しました。 DISKPART> exit DiskPart を終了しています... C:\WINDOWS\system32> |
今使っている回復パーティションは3だったのでいらないはずの4を削除した。ディスクの管理でみると以下のようになっている。
あとはこの空いた領域をCドライブと合体させたいので、AOMEI Partition Assistantを使って以下のように行った。
ここで確認を押してツールバーの「適用」を押すと処理が始まる。
完了後の「ディスクの管理」の状態
ショートカットファイルで設定したショートカットキーが効かない
以下のフォルダに置かないと効かないようだ。
- デスクトップ
- スタートメニュー(C:\ProgramData\Microsoft\Windows\Start Menu\Programs)
- ユーザごとのスタートメニュー(%USERPROFILE%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs)
XPからsambaに接続できない
バージョン確認
1 2 3 4 5 6 7 8 |
$ cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=20.04 DISTRIB_CODENAME=focal DISTRIB_DESCRIPTION="Ubuntu 20.04.2 LTS" $ smbd --version Version 4.11.6-Ubuntu $ |
直ったやつ
/etc/samba/smb.conf
に以下を追加。
1 2 3 |
min protocol = NT1 lanman auth = yes ntlm auth = yes |
C言語の標準ライブラリで文字コードの変換
Visual Studioだけで試した。自分用に貼っておく。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
char szA[32]; wchar_t szW[32]; { // 普通は日本語を直接こう書いてはいけない // 日本語環境のWindowsをつかっているとソースコードの文字コードに関わらず // pはcp932になる // 英語環境の場合はpには文字化けした文字しか入らない // char p[] = "あいうえお"; // "あいうえお"のcp932での値列 char p[] = { 0x82, 0xa0, 0x82, 0xa2, 0x82, 0xa4, 0x82, 0xa6, 0x82, 0xa8, 0x00 }; // これを書かないと動かない // 第2引数""はユーザの環境でロケールを初期化することを意味する // setlocale(LC_ALL, ""); // 日本語Windowsの場合はこれでも大体動く setlocale(LC_ALL, ".932"); // 日本語じゃないWindowsの場合でも動く size_t converted = 0; int ret = mbstowcs_s(&converted, szW, p, _countof(szW) - 1); assert(ret == 0); // もとに戻す ret = wcstombs_s(&converted, szA, szW, _countof(szA) - 1); assert(ret == 0); assert(strcmp(p, szA) == 0); } { // こう書くのはセーフ // ただしソースコードをutf8で保存すること char p[] = u8"あいうえお"; // これを書かないと動かない // 第2引数はUTF8でロケールを初期化することを意味する setlocale(LC_ALL, ".UTF8"); size_t converted = 0; int ret = mbstowcs_s(&converted, szW, p, _countof(szW) - 1); assert(ret == 0); // もとに戻す ret = wcstombs_s(&converted, szA, szW, _countof(szA) - 1); assert(ret == 0); assert(strcmp(p, szA) == 0); } |
C言語とC++のlocale
localeの基本
日付の表示方法は国によって違う。アメリカなら’Friday, July 23, 2021’みたいになり、日本なら’2021/7/23’みたいになる。ほかにも、数字のカンマやピリオドのつけ方や金額表示の仕方もちがう。このような違いを扱うのがlocaleという概念。
1 2 3 4 |
char *setlocale( int category, const char *locale ); |
catergoryには時刻を扱う。LC_TIMEなどいろいろあるが、ここでは一括で扱うLC_ALLを基本的に考える。
locale文字列は国・地域・言語を表す文字列で、”en-US”などと指定するがプログラム開始時には”C”になっており、”C”は1文字1charであることを意味している。”en-US”などの場合は言語と地域を表しており、さらに追加して”en-US.UTF8″などとも書ける。localeにNULLを渡すと現在の値を取得する。localeに空文字を渡すとユーザのデフォルトの国や地域そしてコードページが指定される。
1 2 |
printf("Current locale is '%s'\n", setlocale(LC_ALL, NULL)); printf("Locale for empty is '%s'\b", setlocale(LC_ALL, "")); |
これを英語のWindowsで実行すると以下のように出力される。
1 2 |
Current locale is 'C' Locale for empty is 'English_United States.1252' |
Englishが言語で、United Statesが国・地域、1252がコードページを表しこれは’en-US.1252″と同じ意味だろう。
localeに”.UTF8″とするとコードページだけ変えることができる。ここで指定したコードページはmbtowcsなどでワイド文字列に変換するときに使われる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
wchar_t szW[32]; { setlocale(LC_ALL, ".1252"); char p[] = "あ"; // 文字化け、コードページ1252(latin1)に'あ'はない // ここの"あ"はソースコードの文字コードがどうであろうとANSIと解釈されるはず // つまり英語環境のWindowsではpはそもそも文字化けしている。 mbtowc(szW, p, strlen(p)); } { setlocale(LC_ALL, ".UTF8"); char p[] = u8"あ"; // pはUTF8 // ちゃんと変換できる。 mbtowc(szW, p, strlen(p)); } |
C++の場合
上記の話はC言語の話だった。C言語ではlocaleは1つしかなく、グローバル設定があるだけだったが、C++ではlocaleはクラスになった。
C言語との関係
stdにもstd::setlocale()があり、これは上記と同じようにグローバルなlocaleを設定するものだろう。
localeクラス
- C++ではcategoryの代わりにFacetと言うようになった。
- C言語ではsetlocal()で設定した情報はグローバルでどこかに格納されそれがアプリコードからは見えないところで参照されるが、C++のストリームでは明示的にlocaleクラスを設定しなければならない
コンストラクタ―
引数のないコンストラクタstd::locale()は、グローバルlocaleクラスのコピーを作成する。
文字列を指定
std::locale("ja-JP")
は”ja-JP”のlocaleクラスを作成する。作成しただけではどこにも反映されない。
std::locale::classic();
これはsetlocal(LC_ALL, "C")
と同じlocaleのインスタンス参照をかえす。
グローバルに設定
staticなstd::locale::global(locale& l)
を呼ぶと、locale lをグローバルに設定する。
ストリームに設定
C++方式でグローバルに設定したlocaleはC言語の関数には影響を与えるがストリームには影響しない。ストリームに反映させるにはimbue()
を使って設定する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
{ std::locale loc("en-US"); std::wcout.imbue(loc); std::wcout << loc.name().c_str() << " " << d << '\n'; } { std::locale loc("ja-JP"); std::wcout.imbue(loc); std::wcout << loc.name().c_str() << " " << d << '\n'; } { std::locale loc("de-DE"); std::wcout.imbue(loc); std::wcout << loc.name().c_str() << " " << d << '\n'; } |
1 2 3 |
en-US 1,234.56 ja-JP 1,234.56 de-DE 1.234,56 |
Facetとstd::codecvt
省略、facetはbasic_stringのtraitsのように自分で作ることができる、codecvtもfacetの一つ、これは非推奨でなおかつlocaleを使いにくい。globalなlocaleも反映されない。
式の中に出てくるtypenameやtemplate
これらのキーワードは次のトークンがタイプなのかテンプレートなのかを指定する。テンプレート関数内でテンプレート引数Tに依存するトークンが出てきたとき、コンパイラはそのトークンがタイプなのかテンプレートなのか関数なのか変数なのかわからない。
1 |
T::A<0>(x); |
Aが変数なら、例えば0に置き換えてみると以下のようになる。
1 |
0<0>(x); |
<や>は小なりと大なりと解釈され、有効な式になる。
Aが関数の場合は<0>はテンプレート引数となりxを引数とする関数コールになる。
Aがテンプレートクラスの場合はそのクラスインスタンスxの定義になる。
テンプレートが実体化されたときにわかりそうだが、意図した動作と違う時にエラーの発見が難しくもなりそうなので、Tに依存するトークンでそれがあいまいな場合(どんな時あいまいなのかはよくわからない)はtypenameやtemplateといったキーワードをつける約束になっているようだ。この例の場合はAはintなどの基本タイプにはなれない。
このような用途で使うのがtypenameとtemplate。
typename
T::Aがタイプの場合に指定する。これはよく使う。意味不明なエラーが出た場合につけると直ることが多い。
template
カギカッコなしのtemplateは他の使い方もあるが、ここではTに依存する(Tの中にある)テンプレートクラスやテンプレート関数を指定するときにつけるようだ。テンプレートクラスの場合はタイプでもあるので、両方つけることもある。
1 |
typename T::template A<0>(x); |
こういうものをつけなければならないときはusingを使って別名にしておいた方がいいだろう。
実験したまとめ
Aが変数の場合
typenanmeもtemplateもつけてはいけない(つけるとエラー)
Aが関数テンプレートの場合
typenameとtemplateと両方つけるか、何もつけない(typenameだけだとエラー)
Aがクラステンプレートの場合
両方つけないとエラー
ソース
https://github.com/ambiesoft/blogprogs/tree/master/6151/templatetypename
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
#include <iostream> struct S1 { static constexpr int A = 0; }; struct S2 { template<int N> static void A(int) {} }; struct S3 { template<int N> struct A {}; }; // Uncomment one of three // #define SISS1 #define SISS2 // #define SISS3 #ifdef SISS1 template <class T> void foo() { //// error C2903: 'A': symbol is neither a class template nor a function template //typename T::template A<0>(x); //// error C7511: 'A': 'typename' keyword must be followed by a qualified name //typename A<0>(x); int x = 0; T::A<0>(x); } int main() { foo<S1>(); } #endif #ifdef SISS2 template <class T> void foo() { int x = 0; typename T::template A<0>(x); T::A<0>(x); //// error C7511: 'A': 'typename' keyword must be followed by a qualified name //typename A<0>(x); } int main() { foo<S2>(); } #endif #ifdef SISS3 template <class T> void foo() { typename T::template A<0>(x); //// error C7511: 'A': 'typename' keyword must be followed by a qualified name //typename A<0>(x); //int x = 0; //// error C2371: 'x': redefinition; different basic types //T::A<0>(x); //// error C3861: 'x': identifier not found //T::A<0>(x); } int main() { foo<S3>(); } #endif |