linux commandでのクォーテーションによる動作の違いメモ

linux commandでのクォーテーションによる動作の違いメモ

今のunixtimeの表示

date +%s  

2秒ごとにコマンドを実行し、内容を確認できる

watch  

試す

とくになし

更新される

watch date +%s  

ダブルクォーテーション

更新される

watch "date +%s"  

ダブルクォーテーション+$()

更新されない

watch echo "$(date +%s)"  

シングルクォーテーション+$()

更新される

watch echo '$(date +%s)'  

特に新しい技術を使っていないWEB SERVICEをリリースする

最初に

どうしても、技術者は技術で物事を解決しようとする。

それはとても良いことですが、
「たまには怠惰に別の方法での解決を模索してみよう。」
ということで、特に目新しい技術を使わずにWEB SERVICEをリリースしてみたので記事にしたいと思います。

結論

会議時間の見える化サービス「MetWatch」をリリースしました。
download.gif

https://metwatch.tk

コンセプト

全体

自分も会社に務めていて、1日の大半を会議で埋まると「今日は何もしていないな」などと感じてしまいます。
そこで、この時間がどれくらい「無駄か」を見えるようにすれば会社として会議のあり方をもう少し考えてくれるのではないかと思って作成しようと思いました。

さらに…そのようなニーズを持った人をそのサイトに呼び込むことが可能かも含めて試してみたいと思ったところもあります。

目的

・「会議が無駄」と感じているユーザが使いやすいものを作る
・共有しやすいものを作りたい
・そういったユーザが当サイトにうまく集められるか試したい

機能

会議が行っているとコストがかかることを体感させたいので、下記のような仕様にしました。
・リアルタイムでコストを計算し表示
・ユーザの年収は個別で設定可能
・部屋などの費用も入力可能
・共有しやすいようにURL引数で人数や部屋代などの初期値を指定可能
 (後で記載するようにQRコードなどでの共有を想定)
・それなりに見栄えを良くする

開発

利用技術

開発については細かい話は端折りますが、下記のような技術を利用して構築しました。

クライアントサイド

・html
・css
・vue.js
・bootstrap

サーバサイド

・docker
・docker-compose
・node

SaaS/IaaS等

・Google Cloud Platform
・freenom

開発手順

開発の手順としては下記のような形で行いました。

①自PCで仕組みだけ構築

仕組みだけなので、デザインは気にせずにVue.jsを勉強しながらリアルタイムでコストが表示される部分だけを作成しました。
また、URL引数を受け取り値を初期化する部分の仕組みについても構築しました。
この時点でテスト仕様書(項目だけのものですが…)を作成し、簡便なテストを行って完成としました。

②自PCで外見を飾り付け

ここも力を入れたくなかったのでbootstrapを持ってきて、それっぽく組み合わせる事を主として行っています。
ここまでメインのページが完成しました。

③ドキュメント作成

今回の目玉であるQRコードの作成と、それを挿入したドキュメントを作成しました。
また、それを表示するための別ページを構築しました。

④サーバ側リソース確保

今回はGoogleCloudPlatformの無料枠でサーバを立ち上げました。
また、ドメインについてもfreenomにて無料で取得したものです。
証明書についてはdocker-composehttps-portalというものを利用してLet's Encryptで取得したものを利用しています。

⑤公開・告知

私のTwitterアカウントで告知を行いました

反響

なんと1週間で9名の方にお越しいただけました!(内1名は私)
スクリーンショット 2019-09-07 8.46.49.png

おしまい。

目で追従するやつをriotで実装

背景

何やら入力を目で追従するようなサイトが流行っているので作ってみようと思った。

結論

こうなった
名称未設定.mov.gif

リンクは下記
http://hasito.com/kuma/

実装

メイン部分

コード全体は長いけど主は下記の部分のみだと思う…

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
その結果をオブジェクトに入れてstyleとしてhtml上に展開しています。  

``` javascript
move(e){
var kaku=(p1,p2)=>{
return Math.atan2((p1.y-p2.y),(p1.x-p2.x));
}
var shahen=(r,l)=>{
return {x:Math.cos(r)*l,y:Math.sin(r)*l};
}
var m1=shahen(kaku(e,bme1_p),me_size);
var m2=shahen(kaku(e,bme2_p),me_size);
self.styles['meb1']={
top:(bme1_p.y+m1.y)+ "px",
left:(bme1_p.x+m1.x)+"px"
};
self.styles['meb2']={
top:(bme2_p.y+m2.y)+ "px",
left:(bme2_p.x+m2.x)+"px"
};
self.update();
}
```


## ソース全体

``` html
<kuma>
<div onmousemove={move} style={styles['body']}>
<div class="kao"></div>
<div class="mimi p1"></div>
<div class="mimi p2"></div>
<div class="me p3"></div>
<div class="me p4"></div>
<div class="bme p5" style={styles['meb1']}></div>
<div class="bme p6" style={styles['meb2']}></div>
</div>
<style>
.kao {
border-radius: 50%;
height: 300px;
width: 300px;
top:100px;
left:100px;
background-color:#666;
position:absolute;
}
.mimi {
border-radius: 50%;
height: 100px;
width: 100px;
background-color:#666;
position:absolute;
}
.me {
border-radius: 50%;
height: 100px;
width: 100px;
background-color:#eee;
position:absolute;
}
.bme {
border-radius: 50%;
height: 50px;
width: 50px;
background-color:#000;
position:absolute;
transition:0.2s;
-webkit-transition: 0.2s;
}
.p1{top:100px;left:100px;}
.p2{top:100px;left:300px;}
.p3{top:150px;left:130px;}
.p4{top:150px;left:270px;}
.p5{top:175px;left:155px;}
.p6{top:175px;left:295px;}

</style>
<script>
var self = this;
self.styles={};
var bme1_p={y:175,x:155};
var bme2_p={y:175,x:295};
var me_size=25;
self.styles['body']={
update:function(){
this.height= window.innerHeight + 'px';
this.width= window.innerWidth + 'px';
},
height:"0px",
width:"0px",
'background-color':'#333',
margin: '0px',
display: 'block'
};
move(e){
var kaku=(p1,p2)=>{
return Math.atan2((p1.y-p2.y),(p1.x-p2.x));
}
var shahen=(r,l)=>{
return {x:Math.cos(r)*l,y:Math.sin(r)*l};
}
var m1=shahen(kaku(e,bme1_p),me_size);
var m2=shahen(kaku(e,bme2_p),me_size);
self.styles['meb1']={
top:(bme1_p.y+m1.y)+ "px",
left:(bme1_p.x+m1.x)+"px"
};
self.styles['meb2']={
top:(bme2_p.y+m2.y)+ "px",
left:(bme2_p.x+m2.x)+"px"
};
self.update();
}
window.onresize = ()=>{
self.styles['body'].update();
self.update();
}
window.onresize();
</script>
</kuma>

DynamoDBをPythonからSQLっぽく操作する。

set up

  
pip install dql   

code

  
import dql  
import boto3  
import os  
table_name=os.environ['TABLE_NAME'] # dynamodb  
  
  
engine = dql.Engine()  
c = engine.connect(  
    region=os.environ['AWS_DEFAULT_REGION'],  
    access_key=os.environ['AWS_ACCESS_KEY_ID'],  
    secret_key=os.environ['AWS_SECRET_ACCESS_KEY'],  
    host=os.environ['HOST'],  
    port=int(os.environ['PORT']),  
    is_secure=False  
)  
print("--scan--")  
results = engine.execute(f"SCAN * FROM {table_name} LIMIT 10")  
for item in results:  
    print(dict(item))  
  
print("--delete--")  
results = engine.execute(f"DELETE FROM {table_name} WHERE tm>=1235 and tm<=1236")  
  
print("--scan--")  
results = engine.execute(f"SCAN * FROM {table_name} LIMIT 10")  
for item in results:  
    print(dict(item))  

※Selectを利用するためには設定を変更する必要あり。

その他のクエリに関しては下記を参照ください。
https://dql.readthedocs.io/en/latest/topics/queries/index.html

備忘録

DQLドキュメント
https://dql.readthedocs.io/en/latest/ref/dql.engine.html

接続の実態は、dynamo3モジュールのDynamoDBConnectionという物
https://pypi.org/project/dynamo3

動画とDocker-compose

IMAGE ALT TEXT HERE

動画内で説明している通り、Docker-compose環境も作成しました。

nodejs+passportでYammerで投稿

#背景
社のYammerの方にMicrosoft flowとGoogle alertを使って投稿していたのですが、「毎日ものすごい数 投稿されて見にくい!」という批判が続発したため間にnodejs挟んで1日に数回まとめて投稿するようにかえました。

#やり方
スクリーンショット 2017-04-12 15.34.35.png
こんな感じのを1日に1回〜2回やる感じ

##読み込み
feedparserとrequestを利用します。
こんな感じでインストール。

npm install --save feedparser request  

こんな感じで実装。

var FeedParser = require('feedparser'),  
    request = require('request');  
var req=  request(url);  
var feedparser = new FeedParser({});  
var items=[];//ここに記事が入る。  
    feedparser.on('meta', function(meta) {});  
    feedparser.on('readable', function() {  
      while(item = this.read()) {  
        items.push(item);  
      }  
    });  
  
    var out="";  
    feedparser.on('end', function() {  
      if(items.length > 0){  
            //ここでYammerに出す記事を生成。  
        items.forEach(function(item) {  
          out = out + item.title +"\n"+ item.link + "\n\n";  
        });  
        out=out+"#"+val.name;  
        console.log(val.name+">post");  
      }else{  
        console.log(val.name+">no post");  
      }  
    });  
  

##投稿
passportとpassport-yammer3とyammerを使います。

実際はこんな感じ。

スクリーンショット 2017-04-12 16.52.10.png

まずは関係する所をインストール

npm install --save passport-yammer3 yammer express express-session fs  

access tokenを発行する所はこんな感じ…

var express = require('express'),  
    session = require('express-session'),  
    passport= require('passport'),  
    request = require('request'),  
    fs      = require("fs"),  
    YammerStrategy = require('passport-yammer3').Strategy;  
var app = express();  
app.use(session({ secret: 'keyboard cat' }));  
app.use(passport.initialize());  
app.use(passport.session());  
  
passport.use(new YammerStrategy({  
    clientID:'*****************',  
    clientSecret:'*****************',  
    callbackURL:'http://localhost:3000/auth/yammer/callback'  
  },  
  function(accessToken, refreshToken, profile, done) {  
    console.log(accessToken);//ここでtoken発行  
    fs.writeFileSync("accessToken.txt",accessToken);  
    return done(null, profile);  
  }  
));  
passport.serializeUser(function(user, done) {done(null, user);});  
passport.deserializeUser(function(user, done) {done(null, user);});  
app.all('/ng',function(req,res){res.send('ng');});  
app.all('/ok',function(req,res){res.send('ok');});  
app.all('/auth/yammer',passport.authenticate('yammer'));  
app.all('/',function(req,res){res.send('<a href="/auth/yammer">ここクリック!</a>');});  
  
app.all('/auth/yammer/callback',  
  passport.authenticate('yammer', {successRedirect: '/ok', failureRedirect: '/ng' })  
);  
app.listen(3000, function () {  
  console.log('Example app listening on port 3000!');  
});  

上記を動かしてlocalhost:3000にアクセスすれば動くはず。

最後に、投稿はこんな感じで。

var Yammer = new require('yammer').Yammer;  
  
var yammer_news_post = function(s){  
  var accessToken=fs.readFileSync("accessToken.txt",'utf-8');//これがアクセストークン  
  console.log(accessToken);  
  var yam = new Yammer({ access_token: accessToken });  
  var formdata={body:s,group_id:*********};  
  yam.createMessage(formdata, {},function(r1,r2){});  
}  

モチベーションが低いダイナモDB入門

はじめに

色々と訳あり、ダイナモDBを練習してみます。

事前知識

MySQLなどの知識は少しあります。
FirebaseでNoSQLには触ったことあります。

手順

AWSにアカウント作成済みとします。
pip3もインストール済みとします。

(1)AWS CLIインストール

pip3 にてAWS CLIをインストールします。

pip3 install awscli --upgrade --user  

(2)テーブルを作成する

AWSにログインし、DynamoDBを選択。
デカデカと出ているテーブル作成をクリックします。
image.png

テーブル名を[moti]、プレマリキーを[downs]にします。
ついでにソートキーは[num]にします。
image.png
よくわからないので「デフォルト」のまま作成します。

image.png

できたようです。

(3)awsでアカウントを作ります

IAMというのを作らないとAWS CLIで使えないので作ります。
IAMを選択し、ユーザを追加します

image.png

プログラムからのアクセスにチェックを入れます。

image.png

ダイナモDB系の権限を許容します
image.png

タグを作らず進めます

アクセスキーとシークレットキーをコピーしておきます
image.png

下記のようにawscliにログインします。

$ aws configure --profile hashito  
AWS Access Key ID [None]: XXXXXXXXXXXXXXXXXXXX  
AWS Secret Access Key [None]: xxxxxxxxxxxxxxxx  
Default region name [None]: hashito  
Default output format [None]:   

※一番下にもありますが…これ間違えています…
 Region→ap-northeast-1、output formatはtextなどがいいです。

(4)awscliで操作します

こんな感じのコマンドでデータを追加するようです。

  
$aws dynamodb put-item --table-name moti --item '{ "downs": { "S": "1" }, "num": { "S": "2"}, "created_at": { "S": "1544741492" }, "message": { "S": "aaaaaaaaaaaaaa" } }'  

よく読むとわかりますが基本的にJSON形式の入れ子になっています。
最も上の層が属性のキー名で次の層が属性(SはString、NはNumber的な感じ)になっています。

{"key name":{"type char":"var"}}みたいな感じですね

追加されています
image.png

table一覧

$ aws dynamodb list-tables  
TABLENAMES    moti  

データ取得

$aws dynamodb get-item --table-name moti --key '{ "downs": { "S": "1" }, "num": { "S": "2"}}'  
CREATED_AT    1544741492  
DOWNS    1  
MESSAGE    aaaaaaaaaaaaaa  
NUM    2  

(5)色々と試す。

プレマリキーが同一の場合はどうなるか

$aws dynamodb put-item --table-name moti --item '{ "downs": { "S": "1" }, "num": { "S": "2"}, "created_at": { "S": "1544741492" }, "message": { "S": "aaaaaaaaaaaaaa" } }'  
$aws dynamodb put-item --table-name moti --item '{ "downs": { "S": "1" }, "num": { "S": "3"} }'  
  

上書きされず、別データとして扱われます。

image.png

プレマリキーとソートが同一の場合はどうなるか

$aws dynamodb put-item --table-name moti --item '{ "downs": { "S": "1" }, "num": { "S": "2"}, "created_at": { "S": "1544741492" }, "message": { "S": "aaaaaaaaaaaaaa" } }'  
$aws dynamodb put-item --table-name moti --item '{ "downs": { "S": "1" }, "num": { "S": "2"} }'  

上書きされます。
image.png

いくつかまとめて持ってくるには?

雑にデータを追加します

$ aws dynamodb put-item --table-name moti --item '{ "downs": { "S": "1" }, "num": { "S": "3"} }'  
$ aws dynamodb put-item --table-name moti --item '{ "downs": { "S": "1" }, "num": { "S": "2"} }'  
$ aws dynamodb put-item --table-name moti --item '{ "downs": { "S": "2" }, "num": { "S": "2"} }'  
$ aws dynamodb put-item --table-name moti --item '{ "downs": { "S": "3" }, "num": { "S": "2"} }'  
  
$ aws dynamodb query --table-name moti --key-condition-expression 'downs =:_downs' --expression-attribute-values '{ ":_downs": { "S": "1" }}'  
None    2    2  
DOWNS    1  
NUM    2  
DOWNS    1  
NUM    3  

--expression-attribute-valuesというので変数を定義して、--key-condition-expression でwhereみたいにするようですね。

感想

NoSqlを初めて触ってみましたが楽しいですね。
ただ、SQL的なのがややこしい…
そもそも、あまりこれで条件区切って持ってこないのかもしれないです。

#(詰まった)

(詰まった)’aws’コマンドがない

インストールしたはずのawsコマンドが存在しませんでした。

$ aws help  
-bash: aws: command not found  

どうやらPython3-pipのインストールフォルダにパスが通っていないことが原因でした。
まず、Python3-pipでインストールしたフォルダを確認します。

$ pip3 show awscli  
Name: awscli  
Version: 1.18.0  
Summary: Universal Command Line Environment for AWS.  
Home-page: http://aws.amazon.com/cli/  
Author: Amazon Web Services  
Author-email: UNKNOWN  
License: Apache License 2.0  
Location: /Users/{user}/Library/Python/3.8/lib/python/site-packages  
Requires: botocore, PyYAML, docutils, s3transfer, rsa, colorama  
Required-by:   

ここにはないようです…
こちらの記事を参考に…

AWS CLI の パス を通す
https://qiita.com/plum_shiga/items/5214510f9786898c987f

私のはここにありました。

$export PATH=/Users/{user}/Library/Python/3.7/bin:$PATH  
$aws -help  
usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]  
To see help text, you can run:  
  
  aws help  
  aws <command> help  
  aws <command> <subcommand> help  
aws: error: the following arguments are required: command  
  

(詰まった)Could not connect to the endpoint URL: "https://dynamodb.hashito.amazonaws.com/"って出る。

雑に設定しすぎてaws configureで設定したリージョンが異なっていたようです。

  
AWS Access Key ID [****************]:   
AWS Secret Access Key [****************]:   
Default region name [hashito]: ap-northeast-1  
Default output format [hashito]: text  

設定し直しました。

Dockerを使って数分でOpenCV&Python環境を構築して試す

#コード

下記のコマンドを指定して完了。
/mygit/appdir/は実行したいpythonファイルが有るフォルダを指定してください。

docker run -it --rm --name pythoncv -w /mygit/appdir/ -v "$PWD":/mygit/appdir/  jjanzic/docker-python3-opencv python index.py  

#各オプション

-w

作業フォルダ指定

##-v
マウントディレクトリ指定

"is not shared from OS X and is not known to Docker."というエラーが出る場合があります。  
こちらの記事を参照して回避してください。  

【Docker For Mac】Error response from daemon: Mounts deniedの対応
https://qiita.com/nishina555/items/a75ce530d9382aa09511

#感想
環境構築で時間が取られなくて最高。

[原因不明]一つのUSB to LANを複数のパソコンで共有してネットワークが不安定になった話

概要

家で作業するようになって、表題のような事が発生したので備忘録
というかよく考えると原因不明だ…
完全に個人的なメモ…解決したら更新します。

背景

そもそも、共有するつもりはなかったが、自分が新しいMACBOOKを購入した時にUSB-CハブでHDMIとRJ45に変換するアダプタを買ったので、「これを共有すればそんなに抜かなくても色々共有できて便利やん!」とか思って、失敗しました。

現象

  1. [パソコンA]-[USB2LAN]-[ハブ]-[家庭内ネットワーク]
  2. [パソコンB]-[USB2LAN]-[ハブ]-[家庭内ネットワーク]
    [パソコンA]-[無線ラン]-[家庭内ネットワーク]

1を行ったあと、2の状態になるとパソコンAがネットワークに繋がらなくなる。

解決

ハブを再起動すればネットワークが復旧する。

原因(予想)

USB2LANはMAC Addressが変わらないため、これとIPアドレスの紐付けが更新されない。
(個人的には一旦パソコンから外しているので、更新されているような…)
(ネットワークハブはMAC Addressを記憶する機能があるのでそこにキャッシュされている?)

Heroku入門

概要

個人的にFirebaseは使っているのですが、他の似たシステムも試してみたいなと思い
Herokuに入門してみました。

こちらを動画にしてみています。
興味ある方はどうぞ。

IMAGE ALT TEXT HERE

IMAGE ALT TEXT HERE

最初の気持ち

正直、Firebaseっぽいものという印象しかなかったので、何かしらCLIをインストールして、
これをdeployすると動くんだと思っていました。

手順

Herokuへ登録

こちらのページでユーザ登録を行います。
https://jp.heroku.com/
基本的な情報を入力すると確認メールが送られてくるのでそれで認証する形です。

スクリーンショット 2020-03-12 6.17.42.png

その後、私は「AccountSetting」>「Billing」でクレジットカードを登録しました。
登録しなくてもフリープランである程度使用できると思いますが…

スクリーンショット 2020-03-12 6.21.32.png

環境構築

次にcommandで操作可能なCLIをインストールしました。

下記のページに詳細なやり方はかいてありますが…
https://devcenter.heroku.com/articles/heroku-cli

私はbrewでインストールしたので手順をメモっておきます。

下記のcommandを入力するとインストールが完了します。

brew tap heroku/brew && brew install heroku  

その後、先程作ったアカウントと紐付けるためにログインcommandを入力します

heroku login  

メッセージが現れるのでなにかのキーを押すと
スクリーンショット 2020-03-12 6.38.34.png

ログイン用のウェブページが表示されます。
スクリーンショット 2020-03-12 6.39.18.png

このウェブページでログインを選択すると、cliへのログインは完了です。
最後に、自分の登録したメールアドレスが表示されると思います。
スクリーンショット 2020-03-12 6.40.01.png

アプリテスト

cliを利用してアプリケーションをテストしてみます。

こちらのサイトを参考に勧めます。
https://devcenter.heroku.com/articles/git

最初に、作業フォルダの作成を行い。
フォルダ内に簡単なindex.phpのデモファイルを作成します

mkdir heyhashito  
cd heyhashito  
nano index.php  
<?php echo "test page!" ?>  

フォルダをgitで初期化、ローカルコミットを行います。

git init  
git add .  
git commit -m "commit!"  

次に、heroku内にプロジェクトを作ります。

heroku create  

コードをデプロイします。

git push heroku master  

最後に、実際に動いていることを確認します。
先程heroku createで表示されたアプリケーション名を参考にopenコマンドを入力します。

heroku open -a {aap name}  
  

このように確認できます。
スクリーンショット 2020-03-12 7.36.51.png

最後に

最後の気持ち

gitとの依存性が高いので、雑にしか使ったこと無い私は詰まりました。
また、サーバサイド側の言語が最初のページにある通り、サーバサイド側も基本的に構築する必要があります。
データベースとか価格は安いそうなので、もう少し勉強して使ってみたいと思いました。

あと、動画を撮影したあとに記事を書いているのですが…こっちの方が簡素にかけていますね。

必要だった知識

Herokuを扱う場合は下記は最低勉強したほうが良い
npmComposerなどのファイル管理システム
git!!!

Riot.jsでif={v}入れてeachすると自動的にFilterされる

始めに

最初に、下記のようなロジックを組んで実行したところ結果がおかしかった

<test>  
  <div each={v,i in test} if={v}>index:{i},val:{v}</div>  
  <script>  
    var self     = this;  
    self.test    = [1,0,1,1];  
  </script>  
</test>  

想定していた出力

index:0,val:1  
index:2,val:1  
index:3,val:1  

出力されたもの

index:0,val:1  
index:1,val:1 ←indexが1になってしまっている…  
index:2,val:1  

存在するはずのindex1の値が消えてしまっている。
挙動からすると、each内にif={}があるとその条件でFilterされたものを回しているっぽい…

対策

どうしても理想を叶えたいならこうとかすれば良いと思います

<test>  
  <div each={v,i in test} class={non:!v}>index:{i},val:{v}</div>  
  <style>  
    .non{  
      display: none;  
    }  
  </style>  
  <script>  
    var self     = this;  
    self.test    = [1,0,1,1];  
  </script>  
</test>  

こんな感じでif={}を使わずにstyleで消す。

対策2

@clown0082 さんから頂いたご意見。
こちらのほうがスマートですね。
ありがとうございました!

<test>  
  <div each={v,i in test} show={v}>index:{i},val:{v}</div>  
  <script>  
    var self     = this;  
    self.test    = [1,0,1,1];  
  </script>  
</test>