プライバシーポリシー

広告の配信について

当サイトは第三者配信の広告サービス「Googleアドセンス」を利用しています。
広告配信事業者は、ユーザーの興味に応じた広告を表示するために「Cookie(クッキー)」を使用することがあります。Cookieを無効にする設定およびGoogleアドセンスに関して、詳しくはこちらをクリックしてください。
三者がコンテンツおよび宣伝を提供し、訪問者から直接情報を収集し、訪問者のブラウザにCookie(クッキー)を設定したりこれを認識したりする場合があります。

アクセス解析ツールについて

当サイトでは、Googleによるアクセス解析ツール「Googleアナリティクス」を利用しています。このGoogleアナリティクスはトラフィックデータの収集のためにCookieを使用しています。このトラフィックデータは匿名で収集されており、個人を特定するものではありません。
この機能はCookieを無効にすることで収集を拒否することが出来ますので、お使いのブラウザの設定をご確認ください。この規約に関して、詳しくはこちらをクリックしてください。

当サイトへのコメントについて

当サイトでは、スパム・荒らしへの対応として、コメントの際に使用されたIPアドレスを記録しています。これはブログの標準機能としてサポートされている機能で、スパム・荒らしへの対応以外にこのIPアドレスを使用することはありません。
当サイトでは、次の各号に掲げる内容を含むコメントは管理人の裁量によって承認せず、削除する事があります。
- 特定の自然人または法人を誹謗し、中傷するもの。
- 極度にわいせつな内容を含むもの。
- 禁制品の取引に関するものや、他者を害する行為の依頼など、法律によって禁止されている物品、行為の依頼や斡旋などに関するもの。
- その他、公序良俗に反し、または管理人によって承認すべきでないと認められるもの。

免責事項

当サイトで掲載している画像の著作権・肖像権等は各権利所有者に帰属致します。権利を侵害する目的ではございません。記事の内容や掲載画像等に問題がございましたら、各権利所有者様本人が直接メールでご連絡下さい。確認後、対応させて頂きます。
当サイトからリンクやバナーなどによって他のサイトに移動された場合、移動先サイトで提供される情報、サービス等について一切の責任を負いません。
当サイトのコンテンツ・情報につきまして、可能な限り正確な情報を掲載するよう努めておりますが、誤情報が入り込んだり、情報が古くなっていることもございます。
当サイトに掲載された内容によって生じた損害等の一切の責任を負いかねますのでご了承ください。

運営者:waysaku
初出掲載:2020年8月30日

RSSの <content:encoded> の文字列が数値文字参照になっているので読める文字列に変換する

こんなやつ

www.vogue.co.jp

大昔にRSSでシステム間連携を実装したときにハマった気がしたけど一切覚えてない。

content:encoded にある &#x30E1;&#x30FC;&#x30AC;&#x30F3;&#x5983; のような文字列はどうやら 符号化文字集合の一つである Unicode におけるその文字のCode Point を16進数で表示する 数値文字参照 という形式で出力されてるらしい。

https://ja.wikipedia.org/wiki/%E6%96%87%E5%AD%97%E5%8F%82%E7%85%A7#%E6%95%B0%E5%80%A4%E6%96%87%E5%AD%97%E5%8F%82%E7%85%A7%EF%BC%88%E6%96%87%E5%AD%97%E5%8F%82%E7%85%A7%EF%BC%89

ISO/IEC 10646 - Wikipedia

この数値文字参照を実際の文字に戻すには

            文字符号化方式
         vvvvvvvvvvvvvvvvvvvvv
文字 <-> Code Point <-> byte列
^^^^^^^^^^^^^^^^^^^
   符号化文字集合

のうち Code Point > 文字 をすればよい。
Pythonでやる場合は unicodedata モジュールを使って

def unicode_test(codepoint):
    import unicodedata
    #コードポイントを対応する文字の名前に変換
    name = unicodedata.name(codepoint)
    #対応する名前に当てはまる文字を取得
    letter = unicodedata.lookup(name)
    result = """
        Unicode文字: {}
        対応する文字の名前: {}
             """.format(letter, name)
    print(result)

kanitamago5503.hatenablog.com

とすると変換できる。

試してみる

>>> import re
>>> pattern = '&#x([0-9A-F]{4});'
>>> res = re.findall(pattern, '&#x30E1;&#x30FC;&#x30AC;&#x30F3;&#x5983;')  # 数値文字参照からCode Pointの16進数文字列部分だけ抜き出す
>>> print(res)
['30E1', '30FC', '30AC', '30F3', '5983']

>>> m = map(lambda x: unicode_test(chr(int(x, 16))), res) #16進数文字列から16進数数値型に変換した上で、(Unicode)文字列に変換して上記の関数に渡してみる
>>> print(list(m))
        Unicode文字: メ
        対応する文字の名前: KATAKANA LETTER ME

        Unicode文字: ー
        対応する文字の名前: KATAKANA-HIRAGANA PROLONGED SOUND MARK

        Unicode文字: ガ
        対応する文字の名前: KATAKANA LETTER GA

        Unicode文字: ン
        対応する文字の名前: KATAKANA LETTER N

        Unicode文字: 妃
        対応する文字の名前: CJK UNIFIED IDEOGRAPH-5983

できた。

Pythonhtml.unescape() を使うと 数値文字参照からコードポイント16進数文字列への変換コードポイント16進数文字列から文字に変換 を一気にやってくれるから便利。

Presto/HiveにはUTF-16を操作する関数が用意されてないっぽい
あるにはあったが、数値文字参照からコードポイント16進数文字列への変換コードポイント16進数文字列から文字に変換SQLでやるのは相当気合がいりそう(できるかどうかわからない)

prestodb.io

Raspberry Piでmdadmを使ったraid1ディスクでTimeMachineサーバ構築のメモ

Raspberry Pi OSをインストールした後の作業メモ

GUIでの設定

ネットワーク設定

とりあえずwifiつなげる

その他

GUIから - sshの有効化 - CUIでのデフォルト起動に変更 - current user(piユーザー)でのデフォルトログインを無効化 - キーボード設定を日本語キーボードに変更

apt upgrade と vimインストール

pi@raspberrypi:~ $ sudo apt update
pi@raspberrypi:~ $ sudo apt upgrade
pi@raspberrypi:~ $ sudo apt install -y vim gnome-screenshot

ユーザーの追加とpiユーザのパスワード変更

FYI: https://qiita.com/R-STYLE/items/b481ba2d695ddf8bcee4

pi@raspberrypi:~ $ sudo adduser watanabe_yusaku
pi@raspberrypi:~ $ sudo gpasswd -a watanabe_yusaku sudo
pi@raspberrypi:~ $ sudo gpasswd -d pi sudo

piユーザーはデフォルトユーザとして何かしらOSのデフォルト設定に絡んでるかもしれないので削除せずにパスワード変更だけしておく

pi@raspberrypi:~ $ sudo passwd pi

固定IPの設定

pi@raspberrypi:~ $ sudo vim /etc/dhcpcd.conf
interface eth0
static ip_address=192.168.11.203/24
static routers=192.168.11.1
static domain_name_servers=8.8.8.8

interface wlan0
static ip_address=192.168.11.204/24
static routers=192.168.11.1
static domain_name_servers=8.8.8.8

再起動後にCUIでログイン

再起動してIP確認

watanabe_yusaku@raspberrypi:~ $ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.11.203  netmask 255.255.255.0  broadcast 192.168.11.255
        inet6 fe80::58d9:9e7:854:df74  prefixlen 64  scopeid 0x20<link>
        inet6 2400:4051:23c0:600:6c36:2388:c5:e8ab  prefixlen 64  scopeid 0x0<global>
        ether dc:a6:32:91:39:36  txqueuelen 1000  (Ethernet)
        RX packets 543  bytes 131236 (128.1 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 149  bytes 22984 (22.4 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.11.204  netmask 255.255.255.0  broadcast 192.168.11.255
        inet6 fe80::fd63:d724:db0d:fbd5  prefixlen 64  scopeid 0x20<link>
        inet6 2400:4051:23c0:600:225b:bdb7:cad3:d443  prefixlen 64  scopeid 0x0<global>
        ether dc:a6:32:91:39:37  txqueuelen 1000  (Ethernet)
        RX packets 386  bytes 106463 (103.9 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 35  bytes 4952 (4.8 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

時刻合わせ

FYI: https://www.xn--tckk6a9dufrb.com/raspberry-piraspbian%E3%81%AEntp%E3%82%B5%E3%83%BC%E3%83%90%E8%A8%AD%E5%AE%9A/

watanabe_yusaku@raspberrypi:~ $ sudo vim /etc/systemd/timesyncd.conf
[Time]
NTP=ntp.jst.mfeed.ad.jp
FallbackNTP=ntp.nict.jp time.google.com

を追記してrestart

sudo systemctl restart systemd-timesyncd
sudo systemctl status systemd-timesyncd

で確認するとSyncronizedになっていたが、TimezoneがUSになっていたのでraspi-configから 4 Localisation Options -> I2 Change Timezone でTokyoに設定したら時間が正しくなった

mdadmインストールとraid1デバイスの復旧

/dev/sda1と/dev/sdb1は既にmdadmでraid1デバイスとして構築されているものを再度assembleする。 新たにmd0デバイスを構築する場合はこっちを参考に

watanabe_yusaku@raspberrypi:~ $ sudo apt install -y mdadm
watanabe_yusaku@raspberrypi:~ $ sudo mdadm --assemble /dev/md0 /dev/sda1 /dev/sdb1
mdadm: /dev/md0 has been started with 2 drives.

watanabe_yusaku@raspberrypi:~ $ cat /proc/mdstat
Personalities : [raid1]
md0 : active (auto-read-only) raid1 sda1[0] sdb1[1]
      976629440 blocks super 1.2 [2/2] [UU]
      bitmap: 0/8 pages [0KB], 65536KB chunk

unused devices: <none>


watanabe_yusaku@raspberrypi:~ $ sudo mdadm --detail /dev/md0
/dev/md0:
           Version : 1.2
     Creation Time : Tue May 19 05:30:38 2020
        Raid Level : raid1
        Array Size : 976629440 (931.39 GiB 1000.07 GB)
     Used Dev Size : 976629440 (931.39 GiB 1000.07 GB)
      Raid Devices : 2
     Total Devices : 2
       Persistence : Superblock is persistent

     Intent Bitmap : Internal

       Update Time : Fri May 22 18:45:33 2020
             State : clean
    Active Devices : 2
   Working Devices : 2
    Failed Devices : 0
     Spare Devices : 0

Consistency Policy : bitmap

              Name : raspberrypi:0  (local to host raspberrypi)
              UUID : 30e8a7d7:7fe4d381:3a337844:d762b48f
            Events : 10672

    Number   Major   Minor   RaidDevice State
       0       8        1        0      active sync   /dev/sda1
       1       8       17        1      active sync   /dev/sdb1

/dev/md0のマウント

watanabe_yusaku@raspberrypi:~ $ sudo mkdir /data
watanabe_yusaku@raspberrypi:~ $ sudo chmod 777 /data
watanabe_yusaku@raspberrypi:~ $ sudo mount -t ext4 /dev/md0 /data

TimeMachineサーバ設定

netatalkのインストール

watanabe_yusaku@raspberrypi:~ $ apt install -y netatalk
watanabe_yusaku@raspberrypi:~ $ sudo vim /etc/netatalk/afp.conf
;
; Netatalk 3.x configuration file
;

[Global]
; Global server settings
mimic model = TimeCapsule6,106
mac charset = MAC_JAPANESE
log file = /var/log/netatalk.log

; [Homes]
; basedir regex = /xxxx

; [My AFP Volume]
; path = /path/to/volume

[TimeMachine]
valid users = watanabe_yusaku
path = /data/timemachine
time machine = yes

time machine = yes を書くの忘れててTimemachine設定の バックアップ用デスク選択の一覧に表示されなくてだいぶ時間とられた

再起動

watanabe_yusaku@raspberrypi:~ $ sudo service netatalk restart

確認

MacからTimeMachineの設定からディスク選択を確認すると表示されていることを確認

Google Cloud SpannerでFORMAT_TIMESTAMP関数使うと時間がずれる

SpannerにUTCでTIMESTAMP型で保存されてるデータをJSTに戻そうとしたときにはまった。

SELECT 
  TIMESTAMP "2017-08-20 20:00:00 UTC"                                                                              AS ORIGIN_UTC,
  TIMESTAMP_ADD(TIMESTAMP "2017-08-20 20:00:00 UTC", INTERVAL 9 HOUR)                                              AS DateTime_9_Plus,
  FORMAT_TIMESTAMP('%Y-%m-%d %H:%M:%S', TIMESTAMP_ADD(TIMESTAMP "2017-08-20 20:00:00 UTC", INTERVAL 9 HOUR))       AS DateTime_WITH_TIME_9_Plus_FORMATED,
  FORMAT_TIMESTAMP('%Y-%m-%d %H:%M:%S', TIMESTAMP_ADD(TIMESTAMP "2017-08-20 20:00:00 UTC", INTERVAL (8 + 9) HOUR)) AS DateTime_8_Plus_9_FORMATED
ORIGIN_UTC DateTime_9_Plus DateTime_WITH_TIME_9_Plus_FORMATED DateTime_8_Plus_9_FORMATED
2017-08-20T20:00:00Z 2017-08-21T05:00:00Z 2017-08-20 22:00:00 (なぜかずれる) 2017-08-21 05:00:00 (8時間を補正分としていれてズレを戻す

よくわからんが、内部で太平洋標準時(たいへいようひょうじゅんじ、Pacific Standard Time: 略称PST)+8:00が影響してるとかしてないとか? www.en.advertisercommunity.com

docs.looker.com

FORMAT_TIMESTAMP関数の第三引数で"+9:00"のように指定しないとだめだった。

FORMAT_TIMESTAMP(format_string, timestamp[, time_zone])

でも、Data Studio使ったときに期間指定すると

(FORMAT_TIMESTAMP('%Y%m%d', t0.DateTime) >= '20181201' AND FORMAT_TIMESTAMP('%Y%m%d', t0.DateTime) <= '20181231')

みたいなクエリになっちゃうので、上記のように手動で8を足しこんだカラムにしないとだめだった

さくらVPSにSoftEtherサーバ構築

基本的にはラズパイに構築したときと同じ
waysaku.hatenablog.com


ただ、すっかり忘れていたのでメモ
基本的にはここの通りにセットアップすればOKだが、vpnserverとvpnclientの両方セットアップが必要
linuxconfig.org

あと、さくらのVPSはiptableが /etc/iptables/iptables.rules で明示的にセットされてしまっているのでデフォだとudp/500とudp/4500がつながらないっぽい。
/etc/iptables/iptables.rules を削除してrebootして解決

golangでbyte配列から整数型への変換メモ

メモ

package main

import (
    "fmt"
    "golang.org/x/crypto/scrypt"
    "encoding/hex"
    "encoding/binary"
    "bytes"
)


func main() {

    b := []byte{0x00, 0x00, 0x00, 0xFF}
    fmt.Println(b)
    fmt.Println(hex.EncodeToString(b))

    var i int32
    buf := bytes.NewReader(b)
    err := binary.Read(buf, binary.LittleEndian, &i)
    if err != nil {
        fmt.Println("binary.Read failded:", err)
    }

    fmt.Println(i)
}

package.jsonのpeerDependenciesについての理解

依存の解決の違い(dependencies, devDependencies, peerDependencies)

親アプリで利用されるためのnpmモジュールを開発している時に、このモジュールをインストールするときはmoduleA:0.5.0と一緒にインストールする必要がある」 というケースを考える

 親アプリ
 |
 |- このモジュール
 |          |
 |          |- moduleA

1. このモジュールのpackage.jsonのdependenciesにmoduleA:0.5.0を書いた場合
親アプリにも自動的にmoduleA:0.5.0がインストールされるが、もし親アプリのpackage.jsonにmoduleA:1.5.0が設定されてた場合は上書きされて実行時エラーになる



2. このモジュールのpackage.jsonのdevDependenciesにmoduleA:0.5.0を書いた場合
親アプリでnpm installした時に、このモジュールのdevDependenciesは無視されるのでmoduleA:0.5.0はインストールされないため実行時エラーになる
対処: 親アプリ側でmoduleA:0.5.0をpackege.jsonに書く必要がある



3. (1.か2.に加えて) このモジュールのpackage.jsonのpeerDependenciesにmoduleA:0.5.0を書いた場合
npm-v3より前の場合は、親アプリのnode_modulesにmoduleA:0.5.0も一緒にインストールされる(WARNは出る)
npm-v3以降の場合は、 `このモジュール@1.0.0 requires a peer of moduleA@^0.5.0 but none was installed.` みたいなWARNが出るだけでmoduleA:0.5.0はインストールされない


それぞれの違い

2.のケースはそもそもとして、このモジュールの実行に必要なmoduleA:0.5.0をdevDependenciesに書くのは間違いである(開発用途に必要なモジュールではなく、実行に必要なモジュールのため)

1.のケースは親アプリ側がこのモジュールを利用するときにmoduleA:0.5.0が必須なことに気づけないため、なんらかの理由で親アプリのpackage.jsonにmoduleA:1.5.0を入れた場合に、このモジュールが動かなくなることを事前に気づくことができない

そのため、3.のpeerDependenciesをこのモジュールが使っていれば、警告として親アプリ側に通知することができるので、親アプリ側は明示的に(意図的に)moduleA:0.5.0を追加することができる。

はまったところ

この時注意が必要なのは、peerDependenciesはあくまで親アプリ側に警告を促すだけである。
親アプリは `このモジュールがmoduleA:0.5.0に依存しているからそれを利用しよう'と意図的に親アプリのpackage.jsonにmoduleA:0.5.0を追加することができるということが重要である。
もしも親アプリがmoduleA:1.5.0を利用したかったとしてもこのモジュールはmoduleA:0.5.0を使っているので、それぞれのモジュールの依存バージョンの互換性を解決してくれるものではない

どういうときに使うのか?

開発ではmoduleA:1.5.0を使っているが、このモジュールを利用するときは最低でもmoduleA:0.5.0を使ってほしいときとか?

結局、親アプリでmoduleA:1.5.0を参照して、このモジュールではmoduleA:0.5.0を参照するようにして依存性をよしなに解決して同時に使いたい

そのままではできないっぽい。
(なんかごにょごにょ工夫すればできるかもしれないけど)

疑問に対する推測

peerDependenciesって親アプリに設定するものじゃないのか?

親アプリのpeerDependenciesに指定することにより、このモジュールがどのバージョンのmoduleAに依存しているのかを指定する使い方なのもと思ったがどうやら違うっぽい

  • 親アプリにpeerDependenciesを設定してもこのモジュールのバージョン依存を解決してくれるわけではないっぽい(WARN出るし)
  • そもそも、peerDependenciesの書式的にどのモジュールがどのモジュールのどのバージョンに依存しているという書き方ができない
じゃぁ、devDependenciesとpeerDependenciesの両方に違うバージョンで書いてあるOSSモジュールをよく見るのはなんで?

これとか
リリースバージョンの依存はpeerDependenciesに書いて、開発中とか動作確認中のものはdevDependenciesに書いているのでは?

このモジュールのpeerDependenciesだけに書いた場合、このモジュールでnpm iinstallした場合はどうなるの?

peerDependenciesに書いただけでは、npm installしてもnode_modulesにインストールされない。
dependenciesかdevDependenciesと組み合わせて利用するみたい。








あんまり情報がなくて推測の部分が多い。
あんまりしっくり来てないけどこれ以上時間かけられないのでこんなもんの理解でとどめておく。




package.jsonのpeerDependenciesについて調べた
http://yukidarake.hateblo.jp/entry/2016/02/16/201614

Peer Dependencies
https://nodejs.org/en/blog/npm/peer-dependencies/