ユダヤの教え タルムード 説話集
書籍
レビュー
子供に聞かせる「昔話」には教育的側面、知恵などが含まれる。
例えば日本昔ばなしのそれは大抵が「勧善懲悪」「良いことは帰ってくる」「悪いことはいつかしっぺ返しが来る」「ズルはしてはならない」といった話が非常に多い。
これは悪いとは言わないし、むしろ被災しようが整然と並ぶ規範意識や、世界有数の犯罪率の低さにも影響が無いとは言うまい。
子供に宗教に寄らない善悪を徹底する効果が確かにあるといえる。
この「昔話」だが、やはり民族の差が出てくるようだ。
と言うのは世界で最も富豪やノーベル賞受賞者を作り出したユダヤ人。その彼らの「昔話」、タルムードはまた毛色が違う。
感想としては「こんなん幼少期から聞かされて考え続けたらそりゃ成功者になるわ」です。
この話には、「リスクの取り方」「備えることの重要性」「議論することの重要性」社会で成功するためのノウハウが詰まっているのだ。
しかも面白いのは、この説話の最中、親は途中で話を止めて子供に「どうすればいいと思う?」「どうすべきだと思う?」はたまた「この先どうなると思う?」と考えさせると言う。
そうして「考える」習慣も身に着けさせるのだという…
そりゃ大人になったときに差がつくわけだわ(汗
続きを読むNodeJS でRESTサーバを最短で(Salesforceのコールアウトテストサーバ)
Salesforce でほぼ標準の開発環境 sfdx
ですが、コレ、nodejs
経由でインストール出来るのですよね。
逆に言うと、nodejs
と親和性が高いとも言えます。
そこで、Salesforce のコールアウト(Apex
*1 から、Salesforce 外の HTTP リクエストを送信する仕組み)のテスト用サーバをしれっと作ろうというのが今回の課題。
目次
- 目次
- NodeJS で秒殺RESTサーバ
- ngrok で URL を取得する
- 補足
NodeJS で秒殺RESTサーバ
全部デフォルトでOKなのでコマンドを実行
npm init
: nodejs のプロジェクトを作成npm install -d express
: Nodejs の軽量サーバライブラリインストールnpm install -d compression
: レスポンスの圧縮ライブラリ
index.js
を作成して
const compression = require('compression'); const express = require('express'); const app = express(); const port = 3000; app.use(compression()); app.use(express.json()); app.get('/test', (req, res) => { res.json({ message: 'Welcome to JSON!' }); }) app.use('/', express.static('static')); app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`); });
見たままですね。/test
にアクセスすると JSON 応答が返り、それ以外のURLアクセスは static
フォルダ内を参照します。
node index.js
で起動。
> node index.js Example app listening at http://localhost:3000
ちなみに、ExpressJS の公式サイトは下記です。
*1:Salesforce 専用の開発言語
Python2.7 で死ぬほどシンプルな REST サーバ
とりあえずコレを見つけて、楽だったのでメモ
このシンプルさでしれっと REST サーバ立つのはいいね。
#!/usr/bin/env python import sys, os, re, shutil, json, urllib, urllib2, BaseHTTPServer # Fix issues with decoding HTTP responses reload(sys) sys.setdefaultencoding('utf8') here = os.path.dirname(os.path.realpath(__file__)) # この辺で、ロジックを定義 def get_records(handler): return { 'test': 'Result!' } # 半分おまじないみたいな感じ def rest_call_json(url, payload=None, with_payload_method='PUT'): 'REST call with JSON decoding of the response and JSON payloads' if payload: if not isinstance(payload, basestring): payload = json.dumps(payload) # PUT or POST response = urllib2.urlopen(MethodRequest(url, payload, {'Content-Type': 'application/json'}, method=with_payload_method)) else: # GET response = urllib2.urlopen(url) response = response.read().decode() return json.loads(response) # 全体のレスポンス設定 class MethodRequest(urllib2.Request): def __init__(self, *args, **kwargs): if 'method' in kwargs: self._method = kwargs['method'] del kwargs['method'] else: self._method = None return urllib2.Request.__init__(self, *args, **kwargs) def get_method(self, *args, **kwargs): return self._method if self._method is not None else urllib2.Request.get_method(self, *args, **kwargs) # リクエストのルーティング定義 class RESTRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): def __init__(self, *args, **kwargs): self.routes = { r'^/$': {'file': 'web/index.html', 'media_type': 'text/html'}, r'^/get$': {'GET': get_records, 'media_type': 'application/json'}, } return BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kwargs) def do_HEAD(self): self.handle_method('HEAD') def do_GET(self): self.handle_method('GET') def do_POST(self): self.handle_method('POST') def do_PUT(self): self.handle_method('PUT') def do_DELETE(self): self.handle_method('DELETE') def get_payload(self): payload_len = int(self.headers.getheader('content-length', 0)) payload = self.rfile.read(payload_len) payload = json.loads(payload) return payload def handle_method(self, method): route = self.get_route() if route is None: self.send_response(404) self.end_headers() self.wfile.write('Route not found\n') else: if method == 'HEAD': self.send_response(200) if 'media_type' in route: self.send_header('Content-type', route['media_type']) self.end_headers() else: if 'file' in route: if method == 'GET': try: f = open(os.path.join(here, route['file'])) try: self.send_response(200) if 'media_type' in route: self.send_header('Content-type', route['media_type']) self.end_headers() shutil.copyfileobj(f, self.wfile) finally: f.close() except: self.send_response(404) self.end_headers() self.wfile.write('File not found\n') else: self.send_response(405) self.end_headers() self.wfile.write('Only GET is supported\n') else: if method in route: content = route[method](self) if content is not None: self.send_response(200) if 'media_type' in route: self.send_header('Content-type', route['media_type']) self.end_headers() if method != 'DELETE': self.wfile.write(json.dumps(content)) else: self.send_response(404) self.end_headers() self.wfile.write('Not found\n') else: self.send_response(405) self.end_headers() self.wfile.write(method + ' is not supported\n') def get_route(self): for path, route in self.routes.iteritems(): if re.match(path, self.path): return route return None # サーバ起動処理 def rest_server(port): 'Starts the REST server' http_server = BaseHTTPServer.HTTPServer(('', port), RESTRequestHandler) print 'Starting HTTP server at port %d' % port try: http_server.serve_forever() except KeyboardInterrupt: pass print 'Stopping HTTP server' http_server.server_close() # 実行 def main(argv): rest_server(3000) if __name__ == '__main__': main(sys.argv[1:])
セキュリティ気にしないなら、コレを crontab にでも仕込んでおけば良いかも?
ポート 3000 なんて一般公開しないでしょうよ…ローカルプロセスの都合で一時的にテストサーバがほしいとかでも使える
漫画 バビロン大富豪の教え
書籍
読んだのは「バビロン大富豪の教え」。原書は英語で、日本語訳も当然ある。
漫画で読みやすくなっていて、設定がそこそこ現代日本風にアレンジはされている。
原書は「バビロンいちの大金持ち(The Richest Man In Babyron)」
目次
- 書籍
- 目次
- レビュー
- 各章概要
- なぜ、同じように働いているのに、貧乏人と大金持ちがいるのか?
- 学び
- 大富豪だけが知っている「黄金に愛される7つ道具」
- 学び
- 価値があるのは、金貨が入った袋か?知恵が詰まった袋か?
- 学び
- 賢者の助言によって、貯金が賢明に働き出す
- 「守るべきもの」があるから人は何度でも立ち上がれる
- 学び
- 己の心は「奴隷」のものか、「自由民」のものか
- 学び
- はるか昔の借金返済記録が現代人を救う
- 学び
- なぜ人は働くのか。それは金のためではなかった
- 学び
- エピローグ:最後の黄金法則
- なぜ、同じように働いているのに、貧乏人と大金持ちがいるのか?
レビュー
主人公は借金が理由で妻子に逃げられ、失意で何もする気が起きない元考古学者。
彼の友人が、仕事の一環で古代バビロニアの石版を発見し、主人公に解析の依頼を行う。
石版は遠い昔古代バビロニア時代の自伝で、貧民から富豪に成り上がった人物のものだった。
彼の生涯の記録を通し、金に愛され、増やすための考え方、行動を学び、現代社会においても借金を返しきり、妻子を取り戻す。
という話である。
非常に興味深い点は
- 100年前の小説にも関わらず、ほぼ現代日本でも通じるお金の基礎が書かれていること
- 漫画化にあたり、非常に読みやすく、説教臭く無いため、スラスラ読めること
- 本気でこれをやるだけで、本当に貯蓄できること(というか同じ論理で貯蓄している)
決して FIRE を目指すというわけではない。
しかし、これを読んで行動を起こすことは決して無駄では無いと思う。
これと「お金の大学」(こちらは具体的なアクションの方法を載せてくれている)と合わせれば、小金持ちは十分狙える良書だと考えます。
続きを読むCentOS 7 の Apache (+PHP) から、シェルを経由して sfdx コマンドを実行する
Docker に CentOS + Apache + PHP
Dockerfile を作る
CentOS インストールと PHP インストールまで自動化
FROM centos:7 RUN yum update -y && yum clean all # Repository # EPEL RUN yum install -y epel-release # remi RUN yum -y install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm # installs RUN yum install -y httpd RUN yum -y install --enablerepo=remi,remi-php81 php php-devel php-mbstring php-pdo php-xml php-gd php-fpm php-mysqlnd php-opcache php-pecl-zip libzip5 EXPOSE 80 ENTRYPOINT ["/usr/sbin/httpd", "-DFOREGROUND"]
起動
コンパイルとコンテナ作成
> docker build --tag develop:1.0 . > docker run -ti --publish 8080:80 --detach --name develop develop:1.0
http://localhost:8080 で見れるはず
コンテナ番号を確認して
> docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES bcd685553188 develop:1.0 "/usr/sbin/httpd -DF…" 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp develop
ログイン
> docker exec -it bcd685553188 bash [root@bcd685553188 /]#
Vim を突っ込んで、確認用画面作成
# yum install vim -y # cd /var/www/html # vim index.php
内容は
<? phpinfo(); ?>
あれ?出ない…てかHTTP応答がまんまソースやんけ
モジュールは /etc/httpd/conf.d
とか /etc/httpd/modules
に入ってるから、 httpd.conf
いじって
LoadModule php7_module modules/libphp7.so AddHandler php7-script .php DirectoryIndex index.php
コンテナ再起動して再アクセスするも変化なし…?
もしかして php.ini
か?とおもったらアタリ
short_open_tag = Off
テメーか原因は…ってことで On
で書き換えて再起動。
表示された。
PHP から sfdx コマンドコールする
nodejs インストール
この辺 からインストールコマンドを引っ張る
# curl -fsSL https://rpm.nodesource.com/setup_18.x | bash - # yum install -y nodejs
すると
Error: Package: 2:nodejs-18.13.0-1nodesource.x86_64 (nodesource) Requires: libstdc++.so.6(GLIBCXX_3.4.20)(64bit) Error: Package: 2:nodejs-18.13.0-1nodesource.x86_64 (nodesource) Requires: libc.so.6(GLIBC_2.28)(64bit) Error: Package: 2:nodejs-18.13.0-1nodesource.x86_64 (nodesource) Requires: libstdc++.so.6(CXXABI_1.3.9)(64bit) Error: Package: 2:nodejs-18.13.0-1nodesource.x86_64 (nodesource) Requires: libstdc++.so.6(GLIBCXX_3.4.21)(64bit) Error: Package: 2:nodejs-18.13.0-1nodesource.x86_64 (nodesource) Requires: libm.so.6(GLIBC_2.27)(64bit)
…さいで…
# yum install -y glibc libstdc++
でも状況変わらず…どうも要求ライブラリバージョンが合わないようで…
yum install yum install https://rpm.nodesource.com/pub_16.x/el/7/x86_64/nodejs-16.17.0-1nodesource.x86_64.rpm
しょうがないから 16 入れるか…
sfdx 入れる
悩むこたぁない…。
# npm install sfdx-cli --global # sfdx --version sfdx-cli/7.185.0 linux-x64 node-v16.17.0
インストールされる先は
# ls /usr/lib/node_modules/ corepack npm sfdx-cli
つまり直たたきができるはず
# /usr/lib/node_modules/sfdx-cli/bin/run --version sfdx-cli/7.185.0 linux-x64 node-v16.17.0
php から sfdx を呼んでみる
apache(+PHP) から exec
コマンドを実行するとき、Path とかその他諸々空っぽなので、パス設定を行うシェルコマンドを作成しておく。
NPM_PACKAGES="/usr/lib/node_modules" echo "export PATH="\""\$PATH:$NPM_PACKAGES/bin"\"" npm config set prefix $NPM_PACKAGES" | tee '/etc/profile.d/node-path.sh'
実行結果と確認。
# NPM_PACKAGES="/usr/lib/node_modules" # echo "export PATH="\""\$PATH:$NPM_PACKAGES/bin"\"" > npm config set prefix $NPM_PACKAGES" | tee '/etc/profile.d/node-path.sh' export PATH="$PATH:/usr/lib/node_modules/bin" npm config set prefix /usr/lib/node_modules # cat /etc/profile.d/node-path.sh export PATH="$PATH:/usr/lib/node_modules/bin" npm config set prefix /usr/lib/node_modules
/etc/profile.d
は非ログインシェルでも読み込まれる。
apache ユーザから呼べるようにまずは指定(権限委譲まではいらんかも知れんけど、これ専用なので一応…)
# chown apache:apache /etc/profile.d/node-path.sh # chmod +x /etc/profile.d/node-path.sh
そしたら /var/www/example.sh
を作成 ※権限は気をつけて
#!/bin/bash /etc/profile.d/node-path.sh sfdx --version exit 0
(/etc/profile.d/node-path.sh
は書かなくても読み込まれるとは思うが、一応…)
で、index.php
を下記で書き換えます。
<? $cmd = '/bin/bash /var/www/example.sh'; $output=null; $retval=null; exec($cmd, $output, $retval); echo "Returned with status $retval and output:\n"; print_r($output); ?>
そして画面アクセスすると、無事に下記が表示されました。
Returned with status 0 and output: Array ( [0] => sfdx-cli/7.185.0 linux-x64 node-v16.17.0 )
JavaScript (+LWC)のチュートリアル: リバーシを作る(2)
概要
今回が単純なリバーシの実装と、シンプルな画面表示まで。 画面はこだわったものではなく、単純に文字表示のもの。つまり UI ではなく、ゲームのルール実装を優先します。
前提知識
前回までの知識
目次
- 概要
- 前提知識
- 目次
- ディレクトリ構造を変更する
- ロジックの実装
- まずはリバーシのボードを表示しよう
- 石を置けるようにしよう
- 石をひっくり返そう
- 石が置けない事を通知する
- ステータス表示
- ここまでのコードまとめ
ディレクトリ構造を変更する
前回までで LWC を設定しましたはが、「example」ディレクトリって…と思ったのは自分だけか?
ということで、これをまず変更する。
具体的にはこんな感じになっているので
- modules
- example
- app
- example
これをこうしたい
- modules
- reversi
- app
- reversi
これ自体は簡単なので、とりあえずディレクトリ名を変更しよう。
これだけで、 npm run dev
でサーバを起動すると…
500 - Error retrieving view for route "example"
と言われてしまいます。
これは example/app
をアプリケーションの起動ルートとして設定されているからですね…
この設定ファイルは lwr.config.json
ファイルで、こんな感じで書き換えます。
{ "lwc": { "modules": [{ "dir": "$rootDir/src/modules" }] }, "routes": [ { "id": "reversi", "path": "/", "rootComponent": "reversi/app" } ] }
その後再起動してみてください。前回までの画面が見えたと思います。
続きを読む