OmniAICreator/Qiita-1.07M huggingface dataset:
PostmanでLINEにメッセージを送る

# はじめに

自分のスマホにLINE Notifyを使ってメッセージを送信した備忘録です。
LINEログイン時のPW忘れや、ソフトのインストール時間を加味しても、30分くらいで終わります。

ゴールイメージ
![0112-21.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/626942a7-1eb1-071e-379f-09b830a14576.png)

## 必要なもの

- LINEアプリがインストールされた自分のスマホ
- LINEアカウント
- PC

APIのテストをするために、[Postman](https://www.postman.com/)を使いました。

Postmanの導入方法については、マイクロソフトのチュートリアルが参考になります。
→[Web API の作成](https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/first-web-api?view=aspnetcore-5.0&tabs=visual-studio#install-postman)

# 手順１　LINE Notifyのアクセストークンを取得する

[LINE Notify](https://notify-bot.line.me/ja/)にログインします。

PCからLINEを使用する頻度は低いため、PWを忘れがちですが
**以降PCから操作せねばならないため**、がんばって思い出します。

![0112-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/ec625bff-5dfb-7471-d8b1-5842b8d8aa67.png)

トークンを発行します。

![0112-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/7b8ffcdf-0d1c-c822-ba02-94931f6b9749.png)

通知の際に表示される**トークン名**を決めます。
**「1:1:でLINE Notifyから通知を受け取る」**を選択し、「発行する」を押します。

![0112-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/53ea272d-25a6-3788-ac8a-55c9010e4f55.png)

トークン文字列をメモします。

この文字列は、自分だけが知っているべきものなので、他人に知られないように注意します。

![0112-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/19d0d611-a316-12b0-46e2-8e3662d4a8bf.png)

LINE Notifyからログアウトして終わりです。

# 手順２　PostmanからAPIをたたく

APIはたたくものです。

## インストール

[Postman](https://www.postman.com/)をインストールします。
Googleアカウントがあるとスムーズです。

Postmanのバージョンは**7.36.1**です。

![0112-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/7c9fbcc3-2c3b-358e-0066-d92325bd51db.png)

## POST設定

### Params

[Line LINE Notify API Document](https://notify-bot.line.me/doc/ja/)の通知系APIを参照します。

```
POST https://notify-api.line.me/api/notify
```

- DocumentからURLをコピーして、Postmanのアドレス窓にペーストします。
- URLの左のプルダウンは***POST***を選択します。
- ***Params***タブの***KEY***に`message`と入力します。
- ***VALUE***には自分のスマホのLINEに送るメッセージを書きます。例では`Hello Line API !!`と書いてます。
    - URLの`...notify?`以降に入力した文字列が自動的に反映されます。
    - クエリパラメーターに機微な情報を載せることは避けます。POST履歴にも残るので・・・。

![0112-12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/92b99020-23dc-d4c4-f446-70be345e28b8.png)

### Headers

Headersタブに移動し、2つの値を設定します。

|***KEY***|***VALUE***|
---|---
`Content-Type`|`application/x-www-form-urlencoded`
`Authorization`|`Bearer <access_token>`

`<access_token>`は、先にコピーしておいたアクセストークンで置き換えます。
（`Bearer`とアクセストークンの間に半角スペースを忘れずに！）

![0112-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/58c7b57f-8c91-ae78-4070-301d61b6f4ec.png)

### 送信する

`Send`ボタンを押すと、自分のスマホのLINEへメッセージが送られます。

正常に通知されると、レスポンスの`status`が`200`になります。
この数字が400番台である場合は、何かしらの入力ミスが考えられます。

![0112-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/8a37cd31-3635-fc97-e11e-e24ca1254244.png)

# スマホのLINE画面

無事に**MyPrivateNotify**さんから**「Hello Line API!!」**という文字列が送られてきました

![0112-21.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/626942a7-1eb1-071e-379f-09b830a14576.png)

[EOF]
【flutter】mlkit API 変更に伴うエラー対応

エラー内容

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:checkDebugDuplicateClasses'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.CheckDuplicatesRunnable
   > Duplicate class com.google.android.gms.internal.vision.zzbl found in modules jetified-play-services-vision-common-19.1.0-runtime (com.google.android.gms:play-services-vision-common:19.1.0) and jetified-play-services-vision-face-contour-internal-16.0.0-runtime (com.google.android.gms:play-services-vision-face-contour-internal:16.0.0)


このエラーは2020年3月mlkit API 変更に伴うエラー


    dependencies {

        api 'com.google.firebase:firebase-ml-vision-image-label-model:20.0.2'  // 追記
        api 'com.google.firebase:firebase-ml-vision-face-model:20.0.2'  // 追記
    }
APP/build:gradleのdependenciesを↓に変更

    dependencies {
        api 'com.google.mlkit:image-labeling:17.0.1'  // 追記
        api 'com.google.android.gms:play-services-mlkit-face-detection:16.1.2'  // 追記
    }

各種mlkitに関するAPI変更内容については下記url参照
https://developers.google.com/ml-kit/migration/android
[CSS]テキストの表示プロパティに関して(overflow,white-space,text-overflow)

今回は、テキストが長い（多い）場合のCSS対応。
下記の3つを学習しました。


**・overflow
・white-space
・text-overflow**


#overflow
**・役割**
枠内に収まらない場合、はみ出し部分の表示方法のプロパティ

**・一覧表**

|値|機能|
|:-:|:-:|
|visible |  デフォルトでそのまま |
|hidden   | 非表示にする  |
|scroll|  スクロール表示される |


#white-space
**・役割**
改行やスペースの扱いを指定するプロパティです。

**・一覧表**


| 値 | 機能 |
|:-:|:-:|
|normal   |自動で折り返し  |
|nowrap   |折り返しなし。まとめて表示   |
|pre   |折り返しなし。そのまま表示  |
|pre-wrap   | 折り返しあり。そのまま表示  |
|pre-line   | ソースで改行してる箇所は改行表示。自動折り返しあり。  |


**・参考例**

#text-overflow
**・役割**
　隠れた内容をどのように表示させるか 
  ※テキストが隠れている場合のみ使用出来ます。
　※overflow：hidden、white-space:nowrap上記も合わせて使用すると使用できる？？？
　　
**・一覧表**


| 値 | 機能 | 
|:-:|:-:|:-:|
|clip|末端でテキストを切り取る|  
|ellipsis|...と表示する　3点リーダー   |   

#参考にしたサイト

・https://developer.mozilla.org/ja/docs/Web/CSS/text-overflow
・http://www.tohoho-web.com/css/prop/text-overflow.htm
・http://www.htmq.com/css/overflow.shtml
.http://www.htmq.com/style/white-space.shtml

以上、たにーでした。
【Laravel】エラー：Target class [コントローラ名] does not exist.の発生原因と対処法。

Laravelでページを表示したときに、以下エラーが出た場合の対処法。

```エラー例：
Illuminate\Contracts\Container\BindingResolutionException
Target class [ContactController] does not exist.
http://127.0.0.1:8001/contact
```


ルーティングで指定されたコントローラが存在しない。というエラー。

**▼ルーティング例**

```php:web.php
Route::get('contact', 'ContactController@index');
```

コントローラ名を省略表記してる場合に発生する。


<br>
##対処法

**1. コントローラ名があっているか確認**
**2. RouteServiceProvider.phpのコメントアウトを解除する**
**3. 完全な名前空間を記載する**

ファイル名（名前空間）が正しい場合は、No2を実行すれば解決する可能性が高い。

No.3でやっていることはNo.2と同じ。


<br>
##RouteServiceProvider.phpのコメントアウトを解除する
Laravel7までは、`App\Http\Controllers\`が省略できたが、Laravel8からは省略するとエラーが表示されるようになった。

以下ファイルのコメントアウトを解除することで、Laravel7と同じ環境にできる。


`app > Providers > RouteServiceProvider.php`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/00d1dd3f-7b55-7635-f877-4b6927ca9a45.png)


```php:解除するコメントアウト
//protected $namespace = 'App\\Http\\Controllers';
```


```php:RouteServiceProvider.php
    protected $namespace = 'App\\Http\\Controllers';  //コメントアウトを解除

    /**
     * Define your route model bindings, pattern filters, etc.
     *
     * @return void
     */
    public function boot()
    {
        $this->configureRateLimiting();

        $this->routes(function () {
            Route::prefix('api')
                ->middleware('api')
                ->namespace($this->namespace)
                ->group(base_path('routes/api.php'));

            Route::middleware('web')
                ->namespace($this->namespace)
                ->group(base_path('routes/web.php'));
        });
    }
```



<br>
##完全な名前空間を記載する
Laravel8のデフォルト状態でも、完全な名前空間を指定すれば問題なく機能する。


**▼ルーティング例**

```php:web.php
Route::get('contact', 'ContactController@index');
```

　↓修正

```php:web.php
Route::get('contact', 'App\Http\Controllers\ContactController@index');
```


<br>
##まとめ
コメントアウト解除が超簡単なのでおすすめ。
notistack で複数のポップアップを同時に表示する

# はじめに
[notistack](https://iamhosseindhv.com/notistack/) は [Material UI](https://material-ui.com/) の `Snackbar` コンポーネントをラップしたライブラリでうす。
![Screen Shot 2021-01-20 at 13.39.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43625/094ce505-bd72-9269-a645-f93e59907f51.png)
![Screen Shot 2021-01-20 at 13.38.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43625/d2c2793c-b2a6-f1fa-e665-aa36be67fc11.png)
![Screen Shot 2021-01-20 at 13.38.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43625/f7962b80-dffb-fbfe-b977-abe15e1077f7.png)
添付した画像のように、いくつかのカラーパターンを出し分けることができます。
また、notistack の最大の特徴は、ポップアップを積み重ねて表示できることです。
![Screen Shot 2021-01-20 at 13.43.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43625/e5c1e00c-6c33-f3d6-9368-d28104cb2e7d.png)

# スタイルをカスタマイズする
`notistack@1.0.0` でいくつかの breaking change がありましたが、私の環境は `notistack@0.9.17` を利用しています。

`notistack` からプロバイダーと Custom Hooks をインポートします。

```typescript
import { SnackbarProvider, useSnackbar } from 'notistack';

... 
```

`SnackbarProvider` は下記のように使います。

```typescript
<SnackbarProvider
  iconVariant={{
    success: <SuccessIcon />
    error: <ErrorIcon />
  }}
  anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
  ContentProps={{
    style: { minWidth: 0, height: 33, alignContent: 'center' }}
    className: useCustomStyle().variantDefault,
  }}
  classes={useStayle()}
>
  {children}
</SnackbarProvider>
```

スタイルは `@material-ui/core` の `makeStyles` を用います。

```typescript
import { makeStyles } from '@material-ui/core';

...

const useCustomStyles = makeStyles((theme) => ({
  variantDefault: { backgroundColor: 'black' },
}));

const useStyles = makeStyles((theme) => ({
  variantSuccess: { backgroundColor: 'green' },
  variantError: { backgroundColor: 'red' },
  containerAnchorOriginTopCenter: {
    top: 12,
  },
  collapseWrapper: {
    marginTop: 4,
    marginBottom: 4,
  },
}));
```

今回の例では 

* variantSuccess, variantError で `variant` の値によってスタイルを変えています
* `containerAnchorOriginTopCenter` で上からの余白を設定しています
* `collapseWrapper` で、個々の `Snackbar` に余白を設定しています

注意すべき点として、`classes` には `variantDefault` が存在しません。
→ [参考](https://github.com/iamhosseindhv/notistack/issues/95)
そのため、`className` として設定してあげる必要があります。
このようにして、`Snackbar` を自分が使いやすいようにカスタマイズできました。

※ 1.0.0 からは `ContentProps` がなくなっているので設定方法が異なります。

# ポップアップを表示する

`Snackbar` を表示させる際は、Custom Hooks を利用します。

```typescript
const { enqueueSnackbar, closeSnackbar } = useSnackbar();

...

const key = enqueueSnackbar(message, options);
closeSnackbar(key);
```

`enqueSnackbar` で取得した `key` を渡すことで対象のポップアップを消すことができます。
表示の際には個別にオプションを渡すことも可能です。
これにより、個々のポップアップに違いを出すことができます。

# おわりに
ユーザの目を引くポップアップを出すシーンは多いと思います。
例えばエラーですが、複数のエラーが出た場合にはすべてを一度に見せてあげたほうがユーザフレンドリーかもしれません。

Material UI の Snackbar をきれいに整列して表示することができる `notisnack`。
もし良ければ使ってみてください。
CloudWatch Alarmが氾濫しているので停止する。

# （備忘録）CloudWatch Alarmがうるさいので、停止した。

## 目的
わが社ではCloudWatchAlarmを設定し、アラート内容をタスクとしてチケット化するシステムを作っているのですが、不要なアラート（テスト等によるもの）のチケットが氾濫し始めたので、停止する方法を調べました。備忘録です。

## 手順
CloudWatchの権限を持ったユーザでCloudShellからCLIをたたくだけ。

``` sh
$ aws cloudwatch disable-alarm-actions --alarm-name 【Alarm名】
```

再開は↓

``` sh
$ aws cloudwatch enable-alarm-actions --alarm-name 【Alarm名】
```

アラームが停止していることを確認する際は、CloudWatchAlarmのコンソールで、表示設定をいじいじして「アクションが有効になっています」を表示させる。
無効になっていれば停止完了。

以上。
さて、驚くほど簡単にreCapthca認証でBOT、スパム対策を行おう！！（フロントエンド偏）

ログインフォームや会員登録を行うフォームにて、色々対策したいなと思い調べていると、Googleが提供しているreCaptchaというものを使うことで対策が出来るらしい。

誰しもが１回は見たことのある、「私はロボットではありません」てきなやつ。

ただ、画像をクリックしたりあの分かりづらい文字列を入力したり色々と面倒。。。

そこで、GoogleはこれらをやらなくてもユーザーがBotやスパムではないと判断する最新「v3」を今提供している。

イメージとしてはこんな感じ

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954754/03112800-f0da-92e6-fdd9-61c5672a8e21.png)

ページの右下にこのようなマークが表示され常にユーザーが人間らしい動きをしているかを確認している。

流石Googleさん！

今回はこのreCaptchaの簡単な使い方を説明していこうと思います！！

調べてみてわかったことが、割とドキュメントが少なく初めての人にとって分かりやすい記事がまりなあったので、書いてみようと思いました。

初めての人に向けて、書いていくのであまり詳しい説明は致しません。（詳しいことは分からない）

なので、reCaptchaを搭載したいという方はぜひ見て下さい！

それでは、一緒に説明を見ていきましょう！！！

#Google reCaptchaの登録#

まずは、「Google reCaptcha」に登録します。

詳しいやり方は、他の方が説明しているのでそちらを参考にして頂くと良いかと。

ちなみに僕は下記の記事を参考にして登録を行いました。

[Google reCAPTCHAのWEBサイト登録とAPIキーの取得方法](https://web.runland.co.jp/blog_cate2/post-3748)

#jsファイルの読み込み#

次に、サイトキーをコピーして、``head``タグに以下のスクリプトファイルの読み込みを行ってください。

<font color="red">※注意</font> ``body``タグではなく``head``タグです！！！間違えないように！

```
<script src="https://www.google.com/recaptcha/api.js?render={SITE_KEY}" async defer></script>
```

``{SITE_KEY}``にコピーしたサイトキーをペーストしてください。

#トークンの呼び出し#

最後に、認証を行いたいページにてTokenの発行を行います。

トークンの有効時間は**２分**であるため、入力フォームで多くの入力事項を記載する際は、ページに訪れた時ではなく、例えば「次へ」のボタンを押したときなどにトークンを発行してください。

トークンを呼び出す関数は以下のようになります。

```index.js
     window.grecaptcha.ready(() => {
        window.grecaptcha.execute(process.env.VUE_APP_SITE_KEY, { action: '/signup' }).then(async (token) => {
          console.log('token')
        })
      })
```

このようにして、Tokenを発行することができます！

#ロゴの消去（番外編）#

ページ右下の認証ロゴって結構邪魔ですよね。

なので、ロゴを消去したいページでは以下のようなCSSを設定してあげてください。

```
.grecaptcha-badge {
  display: none
}
```

また、ページによってロゴを消したり表示する場合はこちらの記事に[VueRouterで動的にpathを取得（検知）する方法](https://qiita.com/akki-memo/items/ee9661fa4ed7e0fe0af3)詳しく書いてあるので、ぜひ興味のある方はご覧ください。

今回はこの辺で終わりにしたいと思います。

reCaptchaはまだこれで終わりではないです。

ここで発行したトークンが本当に正しいのかの判断を行わなければいけません。

そして、例えばトークンが正しかったらログインを実行し、正しくなければエラーメッセージを表示するといった形になります。

ただ、これを一気にやってしまうと頭がパンクしてしまうので、まずはこのトークンがちゃんと発行できているかを確認してから次の段階に進んでください。

近々、Laravelでトークンの認証を行う記事を書くのでぜひそちらもご覧ください。

以上、「さて、驚くほど簡単にreCapthca認証でBOT、スパム対策を行おう！！」でした！

良かったら、LGTM、コメントお願いします。

また、何か間違っていることがあればご指摘頂けると幸いです。

他にも初心者さん向けに記事を投稿しているので、時間があれば他の記事も見て下さい！！

Thank you for reading
WijimoをNuxtで利用しようとするとwindow is not definedになってしまう件の対処法

Vue & Wijmoクイックスタート【2019年版】
https://devlog.grapecity.co.jp/entry/2019/03/12/wijmo-vue-quickstart

こちらを参考にいま開発しているプロジェクトにWijimoを導入してみた。

上記の設定通りにNuxt @ v2.14.12で実行すると、「window is not defined」となってしまう。
いろいろ調べたところ、nuxt.config.jsのpluginsにSSR回避の設定をしないとダメなようだ。

https://ja.nuxtjs.org/docs/2.x/configuration-glossary/configuration-build/#ssr

```config
  plugins: [
    {src: './node_modules/@grapecity/wijmo.vue2.grid',mode: 'client'},
    {src: './node_modules/@grapecity/wijmo.cultures/wijmo.culture.ja',mode: 'client'},
    {src: './node_modules/@grapecity/wijmo.styles/wijmo.css',mode: 'client'},
  ],
```
```vue
<template>
  <v-container>
    <v-layout wrap justify-end mb-2>
      <v-flex>
        <wj-flex-grid :itemsSource="gridData">
          <wj-flex-grid-column header="ID" binding="id" :width="60"></wj-flex-grid-column>
          <wj-flex-grid-column header="商品名" binding="product" :width="200"></wj-flex-grid-column>
          <wj-flex-grid-column header="受注日" binding="date" :width="120"></wj-flex-grid-column>
          <wj-flex-grid-column header="金額" binding="amount" :width="100" format="c"></wj-flex-grid-column>
        </wj-flex-grid>
        </v-flex>
    </v-layout>
  </v-container>
</template>
<script>

export default {
  data () {
    return {
      gridData: [
        { id: 15, product: 'ピュアデミグラスソース', date: '2017/01/10', amount: 6000 },
        { id: 17, product: 'だしこんぶ', date: '2017/01/08', amount: 14500 },
        { id: 18, product: 'ピリカラタバスコ', date: '2017/01/12', amount: 4000 },
        { id: 84, product: 'なまわさび', date: '2017/01/21', amount: 8000 }
      ]
    }
  }
}
</script>
<style>

</style>
```


無事動作。
PHPカレンダー

前回の続きです。
ポートフォリオの概要：https://qiita.com/x49_n/items/95da31a5affd9f9aa9fb
#ポートフォリオ名
前回の記事で説明し忘れていましたね。
ポートフォリオの名前は**Today'sMissionList**略して**TMList**としています。
開発理由にも記載しましたが、予定をミッションとして考えているのでこのように名付けました。

#カレンダー作成
まず、メインであるPHPでカレンダーを作成しました。

ご参考に：https://codeforfun.jp/php-calendar/

完成したカレンダーがこちら


![スクリーンショット 2021-01-20 13.33.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/934823/1337d9be-6df3-94f2-16a9-460ee2a323f3.png)

予定欄を追加で作成し、jQueryで選択した日にちが予定内容欄に表示されるように追加しました。

次回は、ログイン機能を作成します！
CentOS6にnginx 1.18 を入れてリバースプロキシ設定

## 前提

* 自己署名証明書をすでに作っていること。
* httpサーバーがすでにあること。
* httpsサーバーが今は‘ないこと

## Download

* http://nginx.org/packages/centos/6/x86_64/RPMS/

![nginx.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/1ea7fe56-97f4-1591-90c2-8a0ef6fa367f.png)


## インストール

```sh
# インストール前のテスト
rpm -ivh --test "nginx-1.18.0-2.el6.ngx.x86_64.rpm"

# インストール
rpm -ivh "nginx-1.18.0-2.el6.ngx.x86_64.rpm"

# インストールされたファイル一覧の表示
rpm -qal nginx
```

## 設定

* /etc/nginx/conf.d/default.conf


```nginx
server {
    listen       443 ssl;
    server_name  server.local;

    # hide nginx version.
    server_tokens off;

    # ssl_verify_client      on;
    ssl_verify_client      off;
    ssl_certificate        /etc/nginx/wildcard_local/wildcard_local.crt;
    ssl_certificate_key    /etc/nginx/wildcard_local/private/wildcard_local.key;
    ssl_client_certificate /etc/nginx/wildcard_local/ca.crt;
    ssl_ciphers            'HIGH:!aNULL:!MD5';
    ssl_protocols          TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;

    proxy_set_header    Host		server.local;
    proxy_set_header    X-Real-IP	$remote_addr;
    proxy_set_header    X-Forwarded-Host	$host;
    proxy_set_header    X-Forwarded-Server	$host;
    proxy_set_header    X-Forwarded-For	$proxy_add_x_forwarded_for;

    location / {
        proxy_pass      http://server.local;
    }

}
```

```sh
# 起動
service nginx start
```

## 動作確認

https://server.local にアクセスすると
http://server.local の内容が表示されることを確認。
【Django】メモリを節約しつつ大容量ファイルをダウンロードする。

Django で大容量ファイルをダウンロードする際にメモリエラーを回避する方法。
`StreamingHttpResponse`と`wsgiref.util.FileWrapper`を使う。

※関数ベースのviewの実装例を記載

# `HttpResponse`を使う場合

```python
from django.http import HttpResponse

def download_view(request, *args, **kwargs):
    with open('path/to/dir/small.csv', 'rb') as f:
        response = HttpResponse(f.read(), content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename=small.csv'
    return response
```

`f.read()`の部分でファイルの全容量をメモリに読み込んでしまう。

# `StreamingHttpResponse`と`FileWrapper`を使う場合

```python
import os
from wsgiref.util import FileWrapper

from django.http import StreamingHttpResponse

# 8MB ずつ読み込む
chunksize = 8 * (1024 ** 2)

def streaming_download_view(request, *args, **kwargs):
    path = os.path.join('path/to/dir', 'large.csv')
    response = StreamingHttpResponse(
        FileWrapper(open(path, 'rb'), chunksize),
        content_type='text/csv'
    )
    response['Content-Length'] = os.path.getsize(path)
    response['Content-Disposition'] = 'attachment; filename=large.csv'
    return response
```

なお `FileWrapper` の第一引数には"filelike-object"を指定するが、コンテキストマネージャを使うと（なぜか）エラーが発生する。

~~あんまり調査していないが、~~[ドキュメントの使用例](https://docs.python.org/ja/3/library/wsgiref.html#examples)と同じように`open()`を使うのが無難である。

```python:失敗する例(コンテキストマネージャを使用)
...
def streaming_download_view(request, *args, **kwargs):
    path = os.path.join('path/to/dir', 'large.csv')
    with open(path, 'rb') as f:
        response = StreamingHttpResponse(
            FileWrapper(f, chunksize),
            content_type='text/csv'
        )
        ...
        return response
```

```python:エラー出力
Traceback (most recent call last):
  File "/home/ec2-user/.pyenv/versions/3.7.7/lib/python3.7/wsgiref/handlers.py", line 138, in run
    self.finish_response()
  File "/home/ec2-user/.pyenv/versions/3.7.7/lib/python3.7/wsgiref/handlers.py", line 183, in finish_response
    for data in self.result:
  File "/home/ec2-user/.pyenv/versions/3.7.7/lib/python3.7/wsgiref/util.py", line 30, in __next__
    data = self.filelike.read(self.blksize)
ValueError: read of closed file
```

# 応用: ダウンロード後にファイルを削除する

ダウンロードするファイルを一時ファイル的に扱いたい場合には`TemporaryDirectory`と組み合わせることで実現できる。

```python
import os
from tempfile import TemporaryDirectory
from wsgiref.util import FileWrapper

from django.http import StreamingHttpResponse

# 8MB ずつ読み込む
chunksize = 8 * (1024 ** 2)


def generate_return_file(target_dir):
    # ダウンロード対象のファイルを指定ディレクトリ配下に作成する何らかの処理
    pass


def streaming_download_view_with_tempdir(request, *args, **kwargs):
    with TemporaryDirectory() as tempdir:
        path = os.path.join(tempdir, 'large.csv')
        # tempdir 配下に対象ファイルを作成する
        generate_return_file(tempdir)

        response = StreamingHttpResponse(
            FileWrapper(open(path, 'rb'), chunksize),
            content_type='text/csv'
        )
        response['Content-Length'] = os.path.getsize(path)
        response['Content-Disposition'] = 'attachment; filename=large.csv'
        return response
```
M1 MacBookでpuppeteerが動かない時の解決策

端的にいうと、条件分岐で弾かれているからということのようです。
今後パッチで解決される可能性があります。公式で改善された場合は、この記事での対処は不要です。

# puppeteerをインストールします

```
yarn add puppeteer
```

# puppeteerのコードを変更します。
https://github.com/joshuajung/puppeteer/commit/7987b91069adafa260c8b795eab3b901847240f7
上記GitHubの記述を頼りに赤くなっている部分を消します。

```
vim [インストールしたフォルダ]/node_modules/puppeteer/lib/cjs/puppeteer/node/BrowserFetcher.js

vim [インストールしたフォルダ]/node_modules/puppeteer/lib/cjs/puppeteer/node/Launcher.js
```

# Chroniumを入れる
https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Mac/818858/
のchrome-mac.zipをダウンロードし、アプリケーションフォルダに入れます。

# 自分が作ったスクリプトを変更する
puppeteerを起動する処理にexecutablePathの記述を追加します。

```diff
const browser = await puppeteer.launch({ 
            headless: false, 
            defaultViewport: {width: 1400, height: 2000 },
++          executablePath: '/Applications/Chromium.app/Contents/MacOS/Chromium',
        });
```

# セキュリティの問題でChroniumが弾かれるので許可する
システム環境設定→セキュリティとプライバシーからChroniumを許可します。

# puppetterが動くのを確認する
しっかりキャプチャできました！
![PageSpeedInsights_1.sp_20210120134800.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247390/a4a65b7c-21ee-4933-bacd-b369040a9bf5.png)
Rails バリデーション書き方

アウトプットでRailsでのバリデーションの書き方を載せます。

データが正しいかどうかを検証するのがバリデーションになります。

まずモデルにて

```ruby:user.rb
class User < ApplicationRecord

  validates :nickname, presence: true

            :nickname  #カラム名

                       presence: true  #空でない事
```


次にコントローラ

```ruby:user_controller.rb

class UsersController < ApplicationController

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if
      @user.valid?   #ここ！！ここ！！！
      @user.save
      redirect_to root_path
    else
      render 'new'
    end 
  end

    private

  def user_params
    params.require(:item).permit(
      :nickname
  end
end
```
valid?メソッドでバリデーションが実行。バリデーションが通ればtrueを返します。

流れとしてはnewアクションで生成したものをcreateアクションで保存する時に値が入ってるのかをバリデーションで確認します。
if文を使い入っていれば@user.saveで保存。空ならrender 'new'でアラートを出す。
,
,

```ruby:user.html.haml
= f.text_field :nickname, class: "nickname"
.error-messages
  = @user.errors.full_messages_for(:nickname)[0]
```

ビューには、保存するnicknameと、エラー文の表示の = @user.errors.full_messages_for(:nickname)[0]書けば完成。
「継続的に進化する組織」を目指す！VPoEの胡氏のエンジニアチーム紹介インタビュー

こんにちは。アルファアーキテクト株式会社（以下、「アルファアーキテクト」「当社」）の人事・広報の藤坂です。

今回は2020年5月に始動したEngineer Unit、半年経過し今の組織について、今後どんな組織にしていきたいかについてVPoEの胡 恩召（Ethan Hu）にお話しを伺いました。

## インタビュイープロフィール

[胡 恩召（Ethan Hu）](https://www.linkedin.com/in/ethanhu/?locale=ja_JP)

* 2011年7月、北京交通大学（Beijing Jiaotong University）大学院 Computer Science専攻 卒業。新しい環境・異なる文化でのチャレンジを目指し、日本での就職を希望。
* 2011年10月、株式会社VOYAGE GROUP に新卒入社。ソフトウェアエンジニアとして会員行動履歴データを活用し、新規[レコメンドシステム](https://techlog.voyagegroup.com/entry/2016/08/22/080000)の設計・開発・効果検証などに従事。
* 2017年9月、Supership株式会社へ転職。プロダクトマネージャーとしてデータマイニングチームをリードし、広告プロダクト[ScaleOut DSP](https://supership.jp/business/scaleout/)開発・[配信最適化](https://qiita.com/AA_Engineer/items/ffe38f2f31a00a2a25bf)・チームマネジメントなどの業務を担当する。
* 2020年5月より、アルファアーキテクトのVPoE（Vice President of Engineering）に就任。

入社インタビュー：[VOYAGE GROUP、Supershipを経て、次はVPoEとして動画広告市場を切り拓く新たな挑戦へ](https://alpha-architect.co.jp/1069/)

## 全員がフルスタックエンジニアとして活躍。一人ひとりのカラーを活かして働ける環境づくりを

「VeleT」の動画広告配信システムは、主に「管理画面」、「配信エンジン」、「バッチ処理」、「レポート」で構成されており、業務内容としては、大きくふたつに分類されます。

1つ目は、メイン業務となる動画広告マーケティングソリューション「VeleT」の開発・改修・運用。主に、ビジネスのニーズに応じたシステム機能追加開発、外部サービスとの連携や、新規事業立ち上げにおける技術面の支援・検証・開発を行っています。

2つ目は、将来の事業における開発リソースの準備や調査です。主にAI（人工知能）などの新技術の検討や取り組みを行っています。

チーム体制としてはエンジニアユニットは正社員5名、業務委託1名で構成されています。私が全体統括を担当、テックリード2名が配信エンジンや管理画面の統括、その他のメンバーがレポート系や管理画面の運用を担当しています。

ポジションによって明確に業務を分担しているわけではなく、各機能によってチケット制で振り分けています。メンバーそれぞれの担当している業務範囲が広く、全員がフルスタックエンジニアとして動けるのはベンチャー企業ならではの魅力ですね。

また、担当業務を決めるときにもっとも重視しているのは、メンバーのやりたいことや得意分野に合わせて業務を割り振ることです。指示された作業を機械的にこなすのではなく、一人ひとりのカラーを活かして、メンバーが能動的に働ける環境づくりを意識しています。

また開発手法としてはスクラム開発を取り入れており、開発エディタは自由。

今後、5G・４Kの時代が到来する中で、動画広告配信システムは、高トラフィックや大規模データや低レイテンシーと厳しい要件が求められるため、エンジニアとしてのスキルアップ・レベルアップとして大きな成長ができることも魅力だと思います！

* 参考記事：[動画広告配信システムVeleTの紹介](https://qiita.com/AA_Engineer/items/e6b3d260a7a6ea654c02)


## 「既存システムの効率化」と「レポートシステムの刷新」を重点的に、今後はAI（人工知能）を取り入れたサービス開発も

現在、重点的に取り組んでいるのは「既存システムの効率化」と「レポートシステムの刷新」です。既存システムをより使いやすくするため、管理画面の機能改善や入稿コスト削減のための機能面の充実化・効率化・改善に取り組んでいます。

レポートシステムに関しては、クライアント様向けのレポートのクオリティを高めるために、これまで週次だったものを一新し、デイリーでチェックできるような体制を整えています。日々のレポートをタイムリーにキャッチすることによって、より情報を効率的に可視化できると見込んでいます。AI（人工知能）なども取り入れながら、より高精度のサービスを提供していきたいですね。


## VPoEとしてのミッションは、メンバーの中長期キャリアに寄り添いサポートすること

会社としての目標を達成するのはもちろんですが、エンジニアユニットのGM（ゼネラルマネージャー）としては、メンバーが成長できる環境を作ることが自分のミッションだと考えています。

ただ作業を指示するだけでは、GM（ゼネラルマネージャー）として不十分だと思っていて。それぞれがキャリアアップするためにも、一人ひとりが描いている中長期のキャリアをしっかりヒアリングし、マネジメントに興味があるメンバーはエンジニアリングマネージャーに、技術を磨きたいメンバーには新技術や高難度の案件を任せるなど、可能な限り希望にマッチしたポジションにアサインしていきたいですね。


## 目指すは”継続的に進化する組織”。「セルフモチベーション」を重視して、チームの文化を築きたい

エンジニアユニットが目指すのは、“継続的に進化する組織”になること。外部環境や技術がめまぐるしく変わる業界の中で、変化やトレンドにも柔軟に適応し、会社全体としてはもちろん、個人としても成長と進化し続けられるようなチームを目指したいですね。

また、チームバリューや文化の構築も注力したいポイントのひとつです。理想は、各メンバーが自主的に思考・行動して「セルフモチベーション」を発揮できること。弊社が大事にしているAAWayにもあるように、常に情報を共有し、オープンマインドで建設的に議論できるチームを目指していきます！

![EU - MTG - 1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641596/f6ae1e7c-54cc-7ecd-5d69-2c3a41699f9e.jpeg)


## 最後に

エンジニアユニットでは、一緒に働く仲間を募集中です！

現在は新規事業の開発も控えているフェーズで、好奇心が強くチャレンジ精神のある方が活躍できる環境だと思います。開発スピードだけではなく、システムの品質や新技術のキャッチアップも重視できる方をお待ちしております。

[中途採用募集要項](https://alpha-architect.co.jp/recruit/entrylist_h/)
Git Bash で 文字コードを変換する方法（Windows）

Git Bashで文字コードを変換する方法のメモ

```
# 現在の文字コード確認
$ chcp.com
現在のコード ページ: 932

# UTF-8に変更
$ chcp 65001
Active code page: 65001

# Shift-JISに変更
$ chcp.com 932
現在のコード ページ: 932
```

#参考
https://stackoverflow.com/questions/29279304/git-bash-chcp-windows7-encoding-issue
Jenkinsのsaveとapplyボタンの違い




![Screen Shot 2021-01-20 at 12.56.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/650287/a8aa32ba-b50d-37a1-0d6c-ae8975eb21b9.png)

Jenkinsの設定画面に「Save」と「Apply」のボタン二つありますよね？

これって何が違うんだろうとふと疑問に思ったのでメモしておきます。

[joomla1.7 - Difference between save and apply button? - Stack Overflow](https://stackoverflow.com/questions/9923531/difference-between-save-and-apply-button)

によると

>"Save" saves your changes and forces you out of the current screen
"Apply" saves your changes but keeps you on the current screen

と書いてあります。

つまり「Save」も「Apply」も設定内容を保存するが「Save」を押すと設定画面から遷移され親ページに戻るのに対し、「Apply」は遷移されずに設定画面に止まるという挙動のようですね...


# 所感

分ける必要あったのかな？
CSSで要素・背景を透過させる方法

よく忘れたりごっちゃになるので、備忘録として書いておきます。

# 要素自体を透過させる
opacityプロパティを指定する。

```css
.header {
  opacity:0.7;
}
```

要素自体を透過するので、背景色・文字・ボタンなど、`header`クラスの要素とその子要素全てが透明になります。
こんな感じ。
![スクリーンショット 2021-01-20 12.48.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/312956/96a8e249-5dfd-3435-0a16-74be5795b497.png)


# 背景のみ透過させる
backgroundプロパティに`rgba()`を指定する。

`rgba(red,green,blue,alpha)`
のalphaが透明度指定なので、以下のような感じで書きます。

```css
.header {
  background-color: rgba(255,255,255,0.8);
}
```

表示するとこんな感じ。
![スクリーンショット 2021-01-20 12.47.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/312956/e2d97e55-26d9-4948-b676-5cb4b3309062.png)



## 参考
[opacity - CSS: カスケーディングスタイルシート | MDN](https://developer.mozilla.org/ja/docs/Web/CSS/opacity)
PyPIにパッケージをトークンを用いてアップロードする


# はじめに

Pythonではよりお手軽に`pip`でインストールするために`PyPI`に作成したライブラリをアップロードすることができます。

このとき、通常はユーザー名・パスワードをアップロード時に手動でコンソールに入力する必要がありますが、APIトークンを発行すればこれらユーザ名・パスワードを省略することができます。

# PyPIへのアップロード (トークンを使用しない)

```bash
pipenv install --dev wheel twine
```

パッケージ化とアップロードのために`wheel`と`twine`をdevで入れます。
wheelはパッケージの1形式であり、かつその形式を作成するためのライブラリです。 (gemみたい)
twineはPyPIにアップロードをするためのライブラリです。
パッケージマネージャは`pip`でも`poetry`でも大丈夫です。


アップロードするときは、以下のシェルスクリプトを自分は利用しています。

```shell
#!/usr/bin/env bash

rm -f -r {your-library-name}.egg-info/* dist/*
python setup.py bdist_wheel
twine upload dist/*
```

このとき、ユーザー名とパスワードをtwineを利用時に打つ必要があります。
これはとても面倒なので、APIトークンを利用することにします。

# APIトークン


[Add API token](https://pypi.org/manage/account/token/)から発行できます。
APIトークンを発行したら、以下の内容をホームディレクトリに`~/.pypirc`として置いてあげます。

```toml:.pypirc
[pypirc]
servers =
    pypi
[pypi]
username: __token__
password: your_token
```

`__token__`は、いかにも別の名前のトークン入れる感じみたいな名前ですが、そのままプレーンテキストで`__token__`とそのまま打ってあげればいいです。
passwordの方に関しては設定が必要で、先程発行したAPIトークンを書く必要があります。



# 参考リンク

- https://blog.n-t.jp/tech/python-wheel-bdist-sdist-pip/
AWS概要　セキュリティ、ID管理について

#概要
もはや何番煎じているか分かりません。
1月から個人的に始めている未経験AWSチャレンジの一環として、CP試験に向けての個人的なメモとして記述します。

※は書き方を模索中ですが、問題を通して思った感想になります

#セキュリティ、ID管理

##AWS　Identity　and Access Management(AWS IAM)
AWS利用者に対して、AWSのサービス範囲を制御するサービス
・識別：ユーザーの発行（登録）
・認証：登録されたユーザーかの確認
・認可：登録されているユーザーは何が出来るのか制御
  

・IAMユーザー：個人
・IAMグループ：チーム開発
・IAMロール　：サードパーティのIdP（SAML認証）に権限を委任する場合の仕組み
→他のサイトでも個人情報を提供する仕組みのこと（SAML認証があれば、他のサイトで使いまわせる）

・IAMポリシー:サービス（リソース側）が使用者を判断する　
「どのAWSサービスの」「どんな操作を」「許可する」をJSON形式で記述
”物”側で認証するという考え方

##AWS Certificate Manager(ACM)
AmazonRoute53でも記述した証明書を発行することが出来る
ELB（ALB）に適用させることで、アプリケーションをHTTPS通信に対応することが出来る
 
※　AWS経験者のPFだとよく取り入れられているのをみます
Djangoのテンプレートでパラメータの値を取得

## やりたいこと
`https://example.com/?year=2021&month=1`

でアクセスしたときにパラメータの`year`と`month`の値をテンプレート側で取りたい。

## 解決方法
`year`の値を取る場合は
`{{ request.GET.year }}`
で取得。

`month`の値を取る場合は
`{{ request.GET.month }}`
で取得。

### 備考
```
{% for key, value in request.GET.items %}
    {{ key }} = {{ value }}
{% endfor %}
```

こんなふうに回しても取れる。

```
year = 2021 month = 1
```
[Jenkins]API経由でファイルのパラメータ付ビルドしよう

以下の記事を参考に、curlコマンドからJenkinsジョブをビルドすることは出来た。
[JenkinsジョブをAPI経由でパラメータ付きビルドする](https://qiita.com/kentana20/items/5dd1111f9f31fefbccf4)
が、パラメータにファイルがあるときにどう実行すればいいかわからなかった。

動作環境

```
Windows10
console2
curl version curl 7.55.1 (Windows)
```

## やりたいこと
ファイルと文字列をそれぞれパラメータにもつジョブを、curlコマンドで実行する。
- file_parameter : `test.txt`
- string_parameter : `test`（文字列）

```text:test.txt
パラメータとして渡せたよ！！！
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/471646/1bede253-0458-506a-1a33-28e10765babf.png)

## 結論

```
curl -X POST {JenkinsのジョブURL}/buildWithParameters?string_paramter=test \
    --user {実行ユーザー}:{API_TOKEN} \
    --form file_parameter=@test.txt
```

**Jenkins画面からパラメータの確認した結果**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/471646/2ccf4f40-3e74-8f74-8bcc-1e0f001eb398.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/471646/dd5445e6-aa37-de51-de21-3c596c907681.png)



文字列は冒頭の記事を参考に。fileは `--form` で指定可能でした。

[公式リファレンス](https://www.jenkins.io/doc/book/using/remote-access-api/)には

>The symbol '@' is important in this example. Also, the path to the file is absolute path. 

って書いてあったけど、絶対パスじゃなくても行けた。
【008_トポロジー】コマ大数学科

# 【008_トポロジー】コマ大数学科

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017176/e92a0f16-6f97-981c-fb09-34db52fe2960.png)

```latex
\begin{tikzpicture}
  \fill [color=green!50!white,rounded corners=5pt] (-0.5,-0.5) rectangle (6.5,3.5);
  \draw [line width=10pt,->,red](3,-1)--(3,1);
  \draw [line width=10pt,->,red](3,2)--(3,4);
  \draw [line width=10pt,->,blue](1,1.5)--(-1,1.5);
  \draw [line width=10pt,->,blue](7,1.5)--(5,1.5);

\end{tikzpicture}
```
微分方程式

# 微分方程式

## 目次

1. [参考](#参考)
1. [微分方程式とは](#微分方程式とは)
1. [記法](#記法)
1. [解き方](#解き方)
    1. [簡単な微分方程式](#簡単な微分方程式)
    1. [変数分離法](#変数分離法)
    1. [同次形](#同次形)


## 参考

- [微分方程式入門１](https://www.youtube.com/watch?v=po97dnBfoco&list=PLDJfzGjtVLHnmhT1AhMx7bSt0ZOGbIP3c&index=1)
- [微分方程式入門２](https://www.youtube.com/watch?v=po97dnBfoco&list=PLDJfzGjtVLHnmhT1AhMx7bSt0ZOGbIP3c&index=2)
- [微分方程式入門３](https://www.youtube.com/watch?v=QeYOiFU6UNs&list=PLDJfzGjtVLHnmhT1AhMx7bSt0ZOGbIP3c&index=3)
- [微分方程式入門４](https://www.youtube.com/watch?v=QeYOiFU6UNs&list=PLDJfzGjtVLHnmhT1AhMx7bSt0ZOGbIP3c&index=4)
- [微分方程式入門５](https://www.youtube.com/watch?v=QeYOiFU6UNs&list=PLDJfzGjtVLHnmhT1AhMx7bSt0ZOGbIP3c&index=5)
- [微分方程式入門６](https://www.youtube.com/watch?v=QeYOiFU6UNs&list=PLDJfzGjtVLHnmhT1AhMx7bSt0ZOGbIP3c&index=6)
- [微分方程式入門７](https://www.youtube.com/watch?v=QeYOiFU6UNs&list=PLDJfzGjtVLHnmhT1AhMx7bSt0ZOGbIP3c&index=7)
- [微分方程式入門８](https://www.youtube.com/watch?v=QeYOiFU6UNs&list=PLDJfzGjtVLHnmhT1AhMx7bSt0ZOGbIP3c&index=8)
- [微分方程式入門９](https://www.youtube.com/watch?v=QeYOiFU6UNs&list=PLDJfzGjtVLHnmhT1AhMx7bSt0ZOGbIP3c&index=9)

## 微分方程式とは

通常の方程式は、x や y などの **値（数）** を求めることだったが、
微分方程式は、x や y で表される **方程式** を求めることになる。

- 方程式

  - ex)  
    $ x^2 + x - 1 = 0　\Rightarrow　x = \frac{-1 \pm \sqrt{5}}{2} $

- 微分方程式

  - ex)  
    $ \frac{dy}{dx} = y　(微分すると自分自身になる関数)\Rightarrow 　 y = Ce^x (Cは任意の定数)$

## 記法

$ 1階微分　y' = \frac{dy}{dx} $
$ 2階微分　y'' = \frac{d^2y}{dx^2} $

## 解き方

### 簡単な微分方程式

- ex1)　$ y' = 2x + 3 \Rightarrow y = x^2 + 3x + C $ **(一般解)**
    - 初期条件が与えられると特殊解が求まる。
    - $ 初期条件: y(0) = 0 を与えると $
    - $ y(0) = 0 より、C = 0　\therefore y = x^2 + 3x $ **(特殊解)**

- ex2)　$ y'' = e^x + 1,　y(0) = 0,　y'(0) = 1 $
    - $ y' = e^x + x + C_1  $ （積分する）
    - $ y = e^x + \frac{1}{2}x^2 + C_1x + C_2  $ （積分する）
    - $ y(0) = 0 より、1 + C_2 = 0　\therefore C_2 = -1 $
    - $ y'(0) = 1 より、1 + C_1 = 1　\therefore C_1 = 0 $
    - $ y = e^x + \frac{1}{2}x^2 -1 $

### 変数分離形

$ y' = f(x)g(y) $

- 右辺が、(xだけの式) x (yだけの式)になっている

[解法と例題](/items/d2fd46abb91c5456391c)

### 同次形

$ y' = f \left( \frac{y}{x} \right)　　\cdots (*)$

[解法と例題](/items/31c30c9841e96c20ad2f)

### 一階線形微分方程式

### ベルヌーイの微分方程式

### 完全微分方程式

### クレローの微分方程式

### 二解線形同次微分方程式
【読書感想】アプリケーションコンフィグの設定パターン 銀座Rails #27

こちらを読んだ感想。
https://speakerdeck.com/morimorihoge/apurikesiyonkonhuigufalseshe-ding-patan-yin-zuo-rails-number-27

# 詳細

> "12 Factor App"
> 
> コンテナ化されたモダンなインフラ環境でまさに参考にできることが多い

これは普段から実感することが本当に多い。12 Factorから外れてるRailsアプリは、コンテナ化がしんどいとも言える。


> 環境変数

便利だけど、数増えてくると辛い。サービスを分ける指標にもできそう。

> デフォルト値問題

いい感じに開発環境のデフォルトを設定できていると、皆幸せ。

# まとめ

"設定変更方法による違い"を見るとどれを選択すべきかわかりやすい。
頻繁に変わったり、環境ごとに変わるものは構成管理からは外すの良いと思う。
Azure DataFactoryを任意のタイミングで起動する

#やりたかったこと。
+ CSVファイルが置かれると、それを加工して、自動的にSalesforceやSQLServerにインポートしたい。
+ 定期実行ではなく、おかれたタイミングで加工とインポートを行いたい。
+ プログラム書かずにやれると（後々、引き継ぎが容易になりそうで）尚良し。

#自動化に使ったもの。
+ Azure LogicApps / CSVの転送、Azure DataFactoryの起動に使用。
+ Azure DataFactory / CSVの加工やSalesforce、SQLServerへのインポートに使用。

#考えたこと。
+ Azure DataFactory自体は、PipelineをRESTにより、任意のタイミングで呼び出すことも可能（っぽい）
+ しかし、[リファレンス](https://docs.microsoft.com/ja-jp/azure/data-factory/quickstart-create-data-factory-rest-api)見るとトークン取得までなかなか面倒。
+ なんかいい方法ないかなと思っていたら、LogicAppsにDataFactoryコネクタがあった。
+ 起動時に変数も与えられる。

#設定した内容。
LogicAppsの設定UIはこんな感じ。
![スクリーンショット 2021-01-20 12.01.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43829/1c669dd8-cab9-2077-81d0-1cf8f6636d02.png)

1. Sharepointにファイルが作られると発火。
2. 作られたファイルの内容を取得
3. 作られたファイルのパスから識別子を取得
4. Blobを作成
5. オリジナルのCSVファイルを退避
6. Pipelineをキック。
7. 結果を、Chatworkに投稿。

CSVファイルが作られた場所によって、DataFactoryの処理を変えたかったので、３の中でコネコネしている。
pipelineキック時の引数は以下Parametersでjson形式で指定する。
![screen2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43829/41081ad8-7900-bd1a-2ee9-3959cb9a2e1d.png)

受け取る側のDataFactory pipelineは、以下のように変数CsvModeを定義して待っておく。
![スクリーンショット 2021-01-20 12.14.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43829/80df0103-f8e3-160b-f288-6761b363edb0.png)

Switchアクティビティでは、以下のように、CsvMode変数の値によって後続するアクティビティを指定する。
![スクリーンショット 2021-01-20 12.14.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43829/e79a2ecd-d709-cf97-d833-314c1fcbf22e.png)

以上。
Rails-tutorial〜リスト1.10　SSH鍵を追加〜



<h2>githubにSSH鍵の追加</h2>

こんにちは。今日はRails-tutorialでSSH鍵を追加でつまづいて解決できたので記事を書きました。
同じところで躓いたら参考にどうぞ。

SSH鍵を設定することの意味　参考サイト
https://knowledge.sakura.ad.jp/3543/

１.まず、アプリの階層に移動
```$ cd hello_app/```
2.コマンドを順番に入力
```$ cd ~/.ssh```
```$ ssh-keygen```

3.```Enter file in which to save the key (/home/ec2-user/.ssh/id_rsa): ```という具合で出てきたら何も考えずエンターキーを３回位おす。押したら
```Your identification has been saved in /home/ec2-user/.ssh/id_rsa.
Your public key has been saved in /home/ec2-user/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:3J/yLUavOIHKlOuvb8Bud6vUfzfDDRZTOqdLuX+poc0 ec2-user@ip-172-31-42-80
The key's randomart image is:
+---[RSA 2048]----+
|                 |
|                .|
|               o |
|       . .    = .|
|     . .S..    B |
|      = ......*  |
|     + +. ooo=.+o|
|      *.o o=*.*=+|
|     oo*+oo=+Eoo=|
+----[SHA256]-----+
```
こんな感じで出てくるはず。

4.コマンド入力
```$ cat ~/.ssh/id_rsa.pub```
コマンド入力したら下にたくさんのアルファベットが出てくるのでそれをコピー

5.githabの右上のアイコン(profile picture)をクリック。


6.「settings」をクリック

7.SSH and GPG keysをクリック

8.「new SSH key」をクリック

9.キーの名前を入力とさっき4でコピーしたのを大きいテキストフィールドに貼り付け

10.githubでリポジトリ新規作成。
```$ git remote add origin git@bitbucket.org:ユーザー名/hello_app.git```


ここまでできたら完成です。

また僕はRails-tutorialの通りBitbucketでやっていたが途中でgithubに登録するようにおすすめされたので
```$ git remote add origin git@bitbucket.org:ユーザー名/hello_app.git```
がうまくいきませんでした。
そこで
```$ git remote -v```
で確認。

```origin  git@bitbucket.org:railstutorial/hello_app.git (fetch)
origin  git@bitbucket.org:railstutorial/hello_app.git (push)```
と結果が出たのでgithubに変更。


```git remote set-url origin https://github.com/ユーザー名/hello_app.git```

もう１度できているか確認

```$ git remote -v```
origin  https://github.com/hiroto-ishida/hello_app.git (fetch)
origin  https://github.com/hiroto-ishida/hello_app.git (push)


これで完成です。

ほぼ自分でわかればOKみたいな記事なので
質問があればお願いします。
Google App EngineにPythonアプリをデプロイしGitHubと連携させる

## 動機
Heroku、AWS Beanstalk、Azureに同じPythonのアプリをデプロイしてみて、ここまできたらGoogle Cloud Platformでも同じことをやってみるかと思いやってみた。が、他のサービスに比べて圧倒的にややこしかった。
GitHubと連携させるところで随分悩んだが、最終的にとても簡単にできることがわかったので、その顛末をここに記す。

##前提
- ローカル、あるいは他のPaaS, IaaSなどで動くことを確認済みのPythonアプリケーションがあること
- 上記アプリがGitHubのリポジトリに上がっていること
- Google Cloud Platformのアカウントがあること
 
##手動でデプロイ
最初はGitHubとの連携はさせず、ローカルから手動でデプロイしてみようと思った。<a href=https://cloud.google.com/appengine/docs/standard/python3/quickstart?hl=ja>公式のチュートリアル</a>通り、Google Cloud SDKをインストールし、コマンドラインからgcloud app deployでデプロイ。初めはapp.yamlがなくて動かなかったり、app.yamlを追加した後もentrypointのアプリケーション名がappじゃなくてmainになっていてエラーになったりしたが、そのあたりはわりとすぐに解決できた。（エラーログを見つけるのに少々時間がかかったが。）

##GitHub連携〜ハマる
じゃあ次はGitHubと連携させてみるかとやってみるが、まずネットでググるとGoogle Cloud RunとGoogle Cloud Buildを使ってGitHubと連携させる方法が出てくる。これがいけなかった。
とりあえず、Cloud Runのサービス作ってGitHubと連携するCloud Buildのトリガーを作ったら、pushのたびにちゃんとトリガーが動いて、正常にデプロイされるんだけど、App Engineの方でWebページを開いてみても一向に反映されず、？？？となる。Cloud Runが何なのかよくわかっていなかったので、App Engineとは別個のものとして動いていることに気づいていなかったのだ。
Cloud Runのサービス詳細ページを見ていて、URLというリンクがあることに気づき、クリックしたら最新のGitHubリポジトリの内容が反映されたページが表示された。ああ、そういうことかとようやく理解する。

##公式ドキュメントを見よ
結論としては公式ドキュメントに全て書いてあった。
Cloud Runなんて最初からいらなかったんだ。
https://cloud.google.com/source-repositories/docs/quickstart-triggering-builds-with-source-repositories?hl=ja

必要なのは

1. Cloud Buildの設定でGAEとの連携を許可、

1. Cloud Buildでデプロイするための構成情報を記述したcloudbuild.yamlをプロジェクトに追加、

1. ビルドトリガーを作成し、[ビルド構成] - [Cloud Build 構成ファイル] に上記で作成したcloudbuid.yamlを指定する。

これであとはGitHubのリポジトリにpushするたびに自動的にApp Engineの方にデプロイされる。
なぜ初めからこのページにたどり着けなかったのか・・・。

##残る疑問
GitHubにあるソースを動かすんならCloud RunとCloud Buildだけでよくね？という疑問が湧く。
App Engineは何のためにあるんや？他のPaasと同じイメージで使うんならApp EngineとCloud Buildなのかな？
使い分けがわからんです。
M5PaperをVSCodeで開発する設定

#PSRAMを使う設定

**Hello Worldでいきなりコケた件**
プロだったら、最初に仕様確認してから開発に入れよって感じですが
在庫があることで即ポチりして嬉しかったんで、開封即ビルドで**<font color="OrangeRed">メモリーエラー</font>**

私はPlatformIOで開発しているのでplatformio.iniの設定が必要でした。

platformioのページにちゃんと書いてあるのですが
https://docs.platformio.org/en/latest/platforms/espressif32.html#external-ram-psram
PSRAMを使う場合はplatformio.iniに

```cpp:platformio.ini
build_flags =
    -DBOARD_HAS_PSRAM
    -mfix-esp32-psram-cache-issue
```
このように書けと指示があります。
当たり前ですが追記したら問題なしでした。
RocketChatで保存期間を超過したMSGを検出する

RocketChatで長期間メッセージを保管せず運用したいケースがあります。チャットメッセージが溜りまくってメールと同じような状態は避けたいしチャット結論をwikiにまとめるよう促す意味もあります。

## REST

`/api/v1/channels.messages`を使用します。
ゴッそり持って来るには便利です。

## 出力はdataframe
RocketChat投稿用ヘルパー関数を別途作っていますのでDataFrameで返すようにしています。


## ちょっとだけ注意
RocketChatでのAPI取得件数はデフォルトで上限設定があります。この緩和を行うかoffsetでループするかといった対応が必要となります。

```python
import requests
import pandas as pd
import datetime
import dateutil.parser

from pprint import pprint

# API パラメータたち
HEADERS ={
    'X-Auth-Token': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    'X-User-Id': 'xxxxxxxxxxtZDz',
    'Content-Type': 'application/json',
}

params = (
    ('roomId', 'GENERAL'),
)

# メッセージ保管期間
LIMIT = 1

# ヘルパー関数定義
'''ISO -> datetime型 '''
def ISOtimeToDatetime(target):
    JST = datetime.timezone(datetime.timedelta(hours=+9), 'JST')
    return dateutil.parser.parse(target).astimezone(JST)

def judgeRocketChatMessage(target_date, limit):
    '''保存期間判定 '''
    today = datetime.date.today()
    diff_date = datetime.timedelta(limit)

    __DEBUG__ = False    
    if __DEBUG__:
        print(target_date.date())
        print(today)
        print(diff_date)
        print(today - target_date.date())
    
    return (today - target_date.date() > diff_date)

# リクエスト実行
## TODO try〜except処理
response = requests.get('http://xxx.xxx.xxx.xxx:3000/api/v1/channels.messages', 
                         headers=HEADERS, 
                         params=params)
# 結果確認
pprint(response)
pprint(len(response.json()['messages']))

# 削除対象判定結果をDataFrameで返す
_list = []
for _ in response.json()['messages']:
    # TODO _['_updatedAt']と今時刻との比較を
    # このタイミングで行い削除対象を確定する方が効率が良い
    _list.append([_['rid'],
                  _['_id'], 
                  ISOtimeToDatetime(_['_updatedAt']),
                  judgeRocketChatMessage(ISOtimeToDatetime(_['_updatedAt']), LIMIT),
                  _['msg']])
# DataFrame化
df = pd.DataFrame(_list)
df.columns = ['チャンネル','MSG_ID','更新時間','削除対象','MSG']
```

## 結果はこちらから
```python
df.head(5)
df.query('削除対象 == True').head(5)
```
freee請求オブジェクト設定における、収入取引設定のエラー

freee fo salesforce

カスタムオブジェクトから収入取引を連携させようと設定していると
エラーメッセージがブランクで表示されて保存できません。

何のエラーか分からん。

回避策
freee取引オブジェクトリンクにカスタム対象のカスタムオブジェクトを参照項目として作成すると
このエラーは解消されました。
【マウスカーソルの初期化】FPSゲームのエンドSceneでマウスカーソルを有効化する【テンプレスクリプト】

下記スクリプトがアタッチされたSceneでは、
マースカーソルの状態が初期化されて表示されます。
主に、FPSゲームなどの「マウスカーソルが非表示で、
マウスでプレイヤーの首振り」をしているゲームなどで、その後のScene遷移の際に使われる機会が多いと思います。

```cursorFormat.cs
using UnityEngine;

public class cursorFormat : MonoBehaviour
{
    void Update()
    {
        Cursor.lockState = CursorLockMode.None; //マウスカーソルの設定を初期化して、
        Cursor.visible = true; //マウスカーソルを表示する
    }
}
```

---

# こちらの記事もどうぞ
- [【Unity】Sceneを切り替えるコード](https://qiita.com/sanpeita/items/912bf1fbaab975c9b7d4)
- [unity2019LTSでスタンダードアセットのFPSコントローラだけインポートする方法](https://qiita.com/sanpeita/items/053f0ed2d19c5ad11bb9)
ラズパイ4のマウスの動きが悪いときの対処方法

ラズパイ4で`Raspberry Pi OS`を入れたのですが、マウスの動きが悪く非常に使いにくかったので、その解決策をメモとして残します。

#設定ファイルの追記

設定ファイルを下のコマンドで開きます。

```console:
$ vi /boot/cmdline.txt
```

このファイルの最後に下の文字を追加します。

```console:
usbhid.mousepoll=0
```

この後、再起動します。これだけです。
[Heroku] エラー： ! [remote rejected] master -> master (pre-receive hook declined) error: failed to push some refs to 'Git URL' [Ruby]

#概要
筆者のver：ruby 2.6.5

git push heroku masterでHerokuへコミットをプッシュしたところ、エラーが発生しました。

エラーメッセージ：
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'Git URL'
[![Image from Gyazo](https://i.gyazo.com/43effcc23a7031adf8689f5de1b41a3a.png)](https://gyazo.com/43effcc23a7031adf8689f5de1b41a3a)

#結論
% heroku stack:set heroku-18 -a アプリケーション名

を実行してから再度git push heroku masterすると解決しました。

#解説
エラーメッセージを翻訳すると以下になります。
[![Image from Gyazo](https://i.gyazo.com/c5ce53036319d5798e7098409e703966.png)](https://gyazo.com/c5ce53036319d5798e7098409e703966)
 2021年1月にHerokuのstackと呼ばれるサービスのverが18→20に更新されたため、
rubyのverと噛み合わないよと言われています。なので

% heroku stack:set コマンドでstackのverを指定してあげると解決する　というのが今回の概要になります。

他の解決策としてrubyのバージョンアップ　が考えられるかと思いますが、
現役エンジニアの方にお聞きしたところ
「別のアプリケーションにも影響が及ぶ可能性があるためオススメできない」とのことでした。

仕事に必要な場合、もしくはPCを買い替えて環境構築する際などにバージョンアップする方が安全だそうです。
クイックソートをVBSで実現したかった

D&Dした単一のテキストファイルを読み込み、行単位でクイックソート(昇順)した結果ファイルを得るスクリプト。
メインで使っているテキストエディタに昇順／降順ソート機能がなかったので自作してみたやつ。
今にして思えばサクラエディタとか使えば標準機能でこれあるじゃんっていう・・・。（しかも選択範囲をAlt＋aで昇順ソートっていうかなり使いやすいショートカットまで付いてる→使うしかなくね？）

# QuickSort.vbs
```
Option Explicit

Dim cArguments
Set cArguments = WScript.Arguments

If cArguments.Count <> 1 Then
    msgbox "単一ファイルをD&Dしてください。", vbCritical, "Err01"
    WScript.Quit
End If

If Right(cArguments(0), 4) <> ".txt" Then
    msgbox "テキストファイルをD&Dしてください。", vbCritical, "Err02"
    WScript.Quit
End If

Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

Dim oFile
Set oFile = fso.OpenTextFile(cArguments(0), 1) 'ReadOnly

Dim sText
sText = oFile.ReadAll

Set oFile = Nothing

Dim Arr
Arr = Split(sText, vbCrLf)

QuickSort Arr, 0, UBound(Arr)

Set oFile = fso.CreateTextFile(Left(cArguments(0), Len(cArguments(0))-4) & "_Sorted.txt")

Dim i
For i = 0 To UBound(Arr)
    oFile.WriteLine Arr(i)
Next

oFile.Close
Set oFile = Nothing
Set fso   = Nothing

msgbox "End of Script"

'*** クイックソート関数
Public Sub QuickSort _
    (ByRef vntArray, _
     ByVal vntStart, _
     ByVal vntEnd)

 Dim vntBaseNumber                                      '中央の要素番号を格納する変数
 Dim vntBaseValue                                       '基準値を格納する変数
 Dim vntCounter                                         '格納位置カウンタ
 Dim vntBuffer                                          '値をスワップするための作業域
 Dim i                                                  'ループカウンタ

    If vntStart >= vntEnd Then Exit Sub                 '終了番号が開始番号以下の場合、プロシージャを抜ける
    vntBaseNumber = (vntStart + vntEnd) \ 2             '中央の要素番号を求める
    vntBaseValue = vntArray(vntBaseNumber)              '中央の値を基準値とする
    vntArray(vntBaseNumber) = vntArray(vntStart)        '中央の要素に開始番号の値を格納
    vntCounter = vntStart                               '格納位置カウンタを開始番号と同じにする
    For i = (vntStart + 1) To vntEnd Step 1             '開始番号の次の要素から終了番号までループ
        If vntArray(i) < vntBaseValue Then              '値が基準値より小さい場合
            vntCounter = vntCounter + 1                 '格納位置カウンタをインクリメント
            vntBuffer = vntArray(vntCounter)            'vntArray(i) と vntArray(vntCounter) の値をスワップ
            vntArray(vntCounter) = vntArray(i)
            vntArray(i) = vntBuffer
        End If
    Next
    vntArray(vntStart) = vntArray(vntCounter)           'vntArray(vntCounter) を開始番号の値にする
    vntArray(vntCounter) = vntBaseValue                 '基準値を vntArray(vntCounter) に格納
    Call QuickSort(vntArray, vntStart, vntCounter - 1)  '分割された配列をクイックソート(再帰)
    Call QuickSort(vntArray, vntCounter + 1, vntEnd)    '分割された配列をクイックソート(再帰)

End Sub
```
[TypeScript]高階関数の書き方

高階関数(map等)はただ関数を求めているだけなので、引数・戻り値が合うなら直接関数を与えれば良い

```typescript
// 以下2つの書き方は同じ結果を得られる

const list:Hogehoge[] = array.map(item => function(item));

const list:Hogehoge[] = array.map(function);

```
通信とネットワーク

# 勉強の記録
通信とネットワーク 1/20
## 勉強した内容
- 通信方法について（回線交換方式・パケット交換方式）
- tcpdump コマンド（パケットの内容を見るコマンド）
- ping コマンド
- IPアドレスについて

## 何をベースに勉強してるか
- [N予備校 プログラミング入門](https://www.nnn.ed.nico/courses/668/chapters/9515)

## 内容の詳細
- インターネットの仕組み？ 実際どのように通信が行われているか
- TCP・UDPやIPアドレスなどなど

### わかったことについて
- ネットゲームでpingって知っていたけど、より一層分かった気がする。
- IPアドレスがバージョン移行していこうとしてると知りました。
- ただ単語として知っているだけだったものが、もう少し深く知れたような気がします。

### むずかしかったよ
- 難しいというより、知ってる言葉でも知らないことだらけでした。

## 次回やる予定のこと
- 次回もネットワーク関連の授業みたいです！
未経験から第二新卒でエンジニアになる記録

初めまして、koseiです。
未経験からエンジニアを目指す23歳です。

2020年12月よりProgateで独学を開始し、これまでHTML＆CSS、JavaScript、Rubyを学習してきました。
アウトプットの場としてQiitaで発信していきたいと思います。

現在はデータベースを活用できるSQLを学習しております。
文法は一通り学びました。



SERECT カラム名、関数、DISTINCT、等
FROM　テーブル名
JOIN　他のテーブルを結合
ON　　各テーブルのどこで結びつけるか
（LEFT JOIN　NULLも含むレコードの取得）
WHERE　条件
GROUP BY　グループ化
HAVING　グループ化したデータをさらに絞り込む
ORDER BY　ASC（昇順）、DESC(降順）
LIMIT　取得データ件数の制限



ここまで学んだ基礎知識を基に、今日は道場コースに取り組みたいと思います！:fist:
fishでコマンドからgithubを開きたい

# やりたいこと
コマンドから直でgithubを開けたら便利だなと思って調べていたら参考記事をみつけた
fishの場合をメモ

~.config/fish/config.fishに下記のように書き込む

```
alias gh "open https://github.(git config remote.origin.url | cut -f2 -d. | tr ':' /)"
```

## 参考資料
https://qiita.com/ucan-lab/items/56502f28ed30981d449a
直近のUnity開発で困ったことの逆引きメモ

メモ書きですが、どなたかのお役に立てれば幸いです。

##NavMesh

####NavMeshAgentのキャラクターの動きを改善する
こちらを使わせていただくとイイカンジに動きます。感謝！！
[NavMeshAgentでよい感じにキャラクターを歩かせる - tanaka's Programming Memo](https://am1tanaka.hatenablog.com/entry/2018/08/20/133619)

####NavMeshをランタイムで動的に生成(Bake)する
[NavMesh Components](https://github.com/Unity-Technologies/NavMeshComponents)を入れるとNavMesh Surfaceが使える。
これをNavMeshを生成させたいオブジェクトに入れ、任意のタイミングで定期的にNavMeshをBakeさせればよい。
しかし、定期的にBakeすると、その都度Agent(キャラクター)の座標が変わってしまうことがあるので注意。

[Unity:動的NavMeshの確認 - simplestarの技術ブログ](https://simplestar-tech.hatenablog.com/entry/2019/01/05/193136)

####NavMeshAgentで浮いてしまう問題
> [Navigation]ウィンドウの[Bake]→[Advanced]→[Height Mesh]のチェックをオンにする

[Dynamically Fixing NavMeshAgent Base Offset? - Unity Answers](https://answers.unity.com/questions/439309/dynamically-fixing-navmeshagent-base-offset.html)

また、モデルの配置時は最低でもNavMeshが生成された地面等が必要。
地面がないと空中に浮いたまま移動してしまう。

##UI

####UIを貫通してRaycastしてしまうのを防止する
下記はARRaycastmanager向けのものだが、汎用的に使えそう。
なおPhysics.Raycastは常にUIを貫通するので注意。

[AR Foundation ARRaycastmanager ray passing through UI,AR Foundation - ARRaycastmanager ray passing through UI - Unity Answers](https://answers.unity.com/questions/1676963/ar-foundation-arraycastmanager-ray-passing-through.html)
アーカイブログの生成量を確認するには

1日あたりのアーカイブログの生成量を知りたいときがあるので方法をまとめます。

# どこを確認？

動的パフォーマンスビューの[v$archived_log](https://docs.oracle.com/cd/E16338_01/server.112/b56311/dynviews_1016.htm)に対するクエリ発行で確認できます。

# 確認方法

## 事前に

SQL*Plusでデータベースに接続して、REDOブロックサイズ確認を確認します。
この出力結果により後に記載する「BLOCKS*512」の数字部分を変更します。

```sql
select blocksize from v$log;
```

## アーカイブREDO生成量の確認

```sql
set lines 200 pages 10000
select
    to_char(COMPLETION_TIME,'yyyy/mm/dd hh24:mi:ss') comp_time
  , trunc(BLOCKS*512/1024/1024) mb
from v$archived_log
order by 1;
```

## 日単位で確認するには

```sql
select
    to_char(trunc(COMPLETION_TIME),'yyyy/mm/dd') comp_time
  , trunc(sum(BLOCKS*512/1024/1024)) mb
from v$archived_log
group by trunc(COMPLETION_TIME)
order by 1;
```

以上