OmniAICreator/Qiita-1.07M huggingface dataset:
【GAS】GoogleアラートをLINEに自動通知して知りたい情報をまとめてた。

![googleArart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2220659/70858e35-a591-1cf3-0f42-9bcb0e7d9f15.png)
Googleアラートをご存知でしょうか？

調べたい検索ワードを登録するとGmailに検索ワードに沿ったニュースが定期的に通知されるサービスです。こちらを使えば自分から検索をする手間が省かれます。

しかし、Gmailを開くのが面倒で、利用をやめた方は多いのではないでしょうか？

より簡単に見られるようにするため、GASを用いてLINEグループにも通知されるようにしてみたので良ければご参考下さい。
#使うもの
・Googleアラート
・Gmail
・GoogleAppScript
・LINENotify
#完成
#Googleアラート:調べたい検索ワードを設定
![70E5AB59-CA09-4AAB-9169-35BED1B38B25.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2220659/b9df0e5c-c7c8-764d-a3ff-6f0d1d3d7d4a.jpeg)
#Gmail:検索ワードの関連記事を受信
![S__23109902-1536x956.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2220659/c95fe413-8e27-2558-5881-18791439196a.jpeg)
#グループLINEに通知
![S__23109899.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2220659/0e7004b4-ebce-bd8e-0c9f-9b80ce9c281e.jpeg)


#コード
```javascript:
function getNews() {

  var thds = GmailApp.search("label:inbox is:unread subject:Google アラート");
  var arr = [];
  for (var n in thds) {
    var thd = thds[n];
    var msgs = thd.getMessages();
    for (m in msgs) {
      var msg = msgs[m];
      var body = msg.getBody();  //メール本文
      var parse = Parser.data(body);
      var name = parse.from('"title": "Google アラート - ').to('",').iterate();
      var links = parse.from('u0026url=').to('\\u0026').iterate();
      alldata = [];
      for (i = 0; i <= links.length; i++) {
        if (links[i] == undefined) {
          continue;
        }
        arr[i] = links[i];
        alldata += "\n" + arr[i];
      }
      sendLineMessage(name[1] + "\n" + alldata);
      thds[n].markRead(); //次回実行の検索に引っかからないようにするため、既読にする
      //console.log(alldata);
    }
  }
}


var LINE_NOTIFY_TOKEN = "LINENotifyトークン";
var LINE_NOTIFY_API = "https://notify-api.line.me/api/notify";

//LINEにメッセージを送る
function sendLineMessage(message) {
  var response = UrlFetchApp.fetch(LINE_NOTIFY_API, {
    "method": "post",
    "headers": {
      "Authorization": "Bearer " + LINE_NOTIFY_TOKEN
    },
    "payload": {
      "message": message
    }
  });
}
```

詳細な設定方法は下記URLを参照してください。
https://uneincrea.com/?p=389
Swift Dateをいつでも使える様に

#今回の内容

* よく使う`Date()`について、メモ感覚ですが書いておきます。

#コード

## .dateStyle = .full && formatter.timeStyle = .full

```Swift:
        let formatter = DateFormatter()
        formatter.dateStyle = .full
        formatter.timeStyle = .full
        formatter.locale = Locale(identifier: "ja_JP")
        let date = Date()
        print(formatter.string(from: date))
```
```:Print結果
        2021年10月29日 金曜日 22時32分46秒 日本標準時
```
## .dateStyle = .long && formatter.timeStyle = .long

```Swift:
        let formatter = DateFormatter()
        formatter.dateStyle = .long
        formatter.timeStyle = .long
        formatter.locale = Locale(identifier: "ja_JP")
        let date = Date()
        print(formatter.string(from: date))
```
```:Print結果
        2021年10月29日 22:33:55 JST
```
## .dateStyle = .medium && formatter.timeStyle = .medium

```Swift:
        let formatter = DateFormatter()
        formatter.dateStyle = .medium
        formatter.timeStyle = .medium
        formatter.locale = Locale(identifier: "ja_JP")
        let date = Date()
        print(formatter.string(from: date))
```
```:Print結果
        2021/10/29 22:34:47
```

## .dateStyle = .short && formatter.timeStyle = .short

```Swift:
        let formatter = DateFormatter()
        formatter.dateStyle = .short
        formatter.timeStyle = .short
        formatter.locale = Locale(identifier: "ja_JP")
        let date = Date()
        print(formatter.string(from: date))
```
```:Print結果
        2021/10/29 22:35
```

# 終わり
ご指摘、ご質問などありましたら、コメントまでお願い致します。
初めてのReactのお勉強

## これまでのJavaScript

- レンダリングコストが高い、コードの複雑化
<br>→モダンJSでは仮想DOMを操作し、差分を出してからDOMに反映
- １つのJSファイルにすべての処理を記載していた
<br>→ファイルを分けるようになったが、どこの変数を使っているのかなどわかりにくい
<br>→npm/yarnなどのパッケージマネージャーを使用
- ES2015が機能追加が多くあり、近代JSの転換期と呼べる

## モジュールバンドラーとは
**複数のjs(css/image)ファイルを1つにまとめたもの**
JSファイルは細かく分けたほうが効率はいいが、本番用にビルドする際に1つのファイルにまとめる

## トランスパイラとは（BABEL）
**新しいJavaScriptの記法を古い記法に変換してくれる**
開発は新しい方でやって、実行するときに古い記法に変換してくれる

## SPAとは（Single Page Application）
- モダンJSはSPAが基本
- HTMLは1つのみでJSで画面を書き換える
- メリットは画面遷移がスムーズにできる
- コンポーネント分割が容易になることで開発効率がアップする
東大数学2020第4問(1)

https://twitter.com/ut_ht_shibuki/status/1453348339781488640?s=20

こんなツイートがバズってたので、(1)だけ解いてみた。

> 第四問
$ n,k $ を $ 1\leq k \leq n $ を満たす整数とする。$ n $ 個の整数 $$ 2^m\quad(m=0,1,2,\cdots,n-1) $$ から異なる $ k $ 個を選んでそれらの積をとる。$ k $ 個の整数の選び方すべてに対しこのように積をとることにより得られる $ {\_n}\mathrm{C}\_k $ 個の整数の和を $ a_{n,k} $ とおく。例えば, $$ a_{4,3}=2^0\cdot2^1\cdot2^2+2^0\cdot2^1\cdot2^3+2^0\cdot2^2\cdot2^3+2^1\cdot2^2\cdot2^3=120 $$ である。
>
(1) 2以上の整数 $ n $ に対し, $ a_{n,2} $ を求めよ。


まずは式を立てるところから。
$ 2^0,2^1,2^2,\cdots,2^{n-1} $ から2個選ぶので、
$$ a_{n,2}=\sum_{j=0}^{n-2}2^j\sum_{k=j+1}^{n-1}2^k $$

どうやら、$ 2^n $ の総和と部分和が必要になりそう。
というわけで、総和から求めていきます。
$$ \sum_{k=0}^n2^k=1+2+4+8+16+\cdots+2^n $$

両辺に2を掛けると、$$ 2\sum_{k=0}^n2^k=2+4+8+16+\cdots+2\cdot2^n $$

後の式から前の式を引くと、以下のように総和が求まります。 $$ \sum_{k=0}^n2^k=2^{n+1}-1 $$

部分和は以下のように求まります。
$$
\begin{align}
\sum_{k=j}^n2^k &= \sum_{k=0}^n2^k-\sum_{k=0}^{j-1}2^k \\\\
&= (2^{n+1}-1)-(2^j-1) \\\\
&= 2^{n+1}-2^j
\end{align}
$$

上記の式から $ k=j+1 $ から $ n-1 $ までの $ 2^k $ の部分和は $ 2^n-2^{j+1} $ となるので、$$
\begin{align}
a_{n,2} &= \sum_{j=0}^{n-2}2^j(2^n-2^{j+1}) \\\\
&= \sum_{j=0}^{n-2}2^j2^n-\sum_{j=0}^{n-2}2^{2j+1} \\\\
&= 2^n\sum_{k=0}^{n-2}2^k-2\sum_{k=0}^{n-2}4^k
\end{align}
$$

今度は $ 4^n $ の総和を求める必要がありますね。
$$ \sum_{k=0}^n4^k=1+4+16+64+256+\cdots+4^n $$

両辺に4を掛けると、$$ 4\sum_{k=0}^n4^k=4+16+64+256+\cdots+4\cdot4^n $$

後の式から前の式を引くと、$$
\begin{align}
3\sum_{k=0}^n4^k &= 4\cdot4^n-1 \\\\
\sum_{k=0}^n4^k &= \frac{4^{n+1}-1}{3}
\end{align}
$$

$ 2^k $ と $ 4^k $ の $ k=0 $ から $ n-2 $ までの総和をそれぞれ代入して、
$$
\begin{align}
a_{n,2} &= 2^n(2^{n-1}-1)-2\frac{4^{n-1}-1}{3} \\\\
&= 2^{2n-1}-2^n-\frac{2\cdot4^{n-1}}{3}+\frac{2}{3} \\\\
&= \frac{4^n}{2}-2^n-\frac{4^n}{6}+\frac{2}{3} \\\\
&= \frac{4^n}{3}-2^n+\frac{2}{3}
\end{align}
$$

というわけで、解答は $$ a_{n,2}=\frac{4^n}{3}-2^n+\frac{2}{3} $$ となりました。
PowerPoint VBA 図形の名前の設定/取得、指定名の図形を狙って読み書き



### 実行コード

``` vb
Sub a()
  Call Set選択されている図形の名前("test")
End Sub
Sub b()
  Call 指定された名前の図形にテキストデータ書き込み("test", "内容")
End Sub
Sub c()
  Call 指定された名前の図形にテキストデータ読み込み("test")
End Sub
```

### 図形の名前の設定/取得
``` vb
Sub Get選択されている図形の名前()
  Dim shp As Shape

  With ActiveWindow.Selection

    If .Type = ppSelectionNone Or _
      .Type = ppSelectionSlides Then Exit Sub

    For Each shp In .ShapeRange
      Debug.Print shp.Name
    Next shp

  End With

End Sub
Sub Set選択されている図形の名前(ShapeName)
  Dim shp As Shape

  With ActiveWindow.Selection

    If .Type = ppSelectionNone Or _
      .Type = ppSelectionSlides Then Exit Sub

    For Each shp In .ShapeRange
      shp.Name = ShapeName
    Next shp

  End With

End Sub

```


### 指定名の図形を狙って読み書き
``` vb
Sub 指定された名前の図形にテキストデータ書き込み(ShapeName, 書き込む内容)
  Dim prs As Presentation
  Dim sld As Slide
  Dim shp As Shape
  
  Set prs = PowerPoint.ActivePresentation
  
  For Each sld In prs.Slides
    Debug.Print sld.Name
    For Each shp In sld.Shapes
      If shp.Name = ShapeName Then
        shp.TextFrame.TextRange.Text = 書き込む内容
      End If
    Next
  Next

End Sub
Sub 指定された名前の図形にテキストデータ読み込み(ShapeName)
  Dim prs As Presentation
  Dim sld As Slide
  Dim shp As Shape
  
  Set prs = PowerPoint.ActivePresentation
  
  For Each sld In prs.Slides
    Debug.Print sld.Name
    For Each shp In sld.Shapes
      If shp.Name = ShapeName Then
        Debug.Print shp.TextFrame.TextRange.Text
      End If
    Next
  Next

End Sub
```
Udemy「ネットワークエンジニアを目指す初心者はここから始めよう！「ゼロから学ぶネットワーク基礎」1029 ネットワーク インフラエンジニア

TCP/UDP概要
・トランスポート層に相当する。
　・TCP(Transmission Control Protocol)
　・UDP(User Datagram Protocol)
・複数のアプリケーションからのパケットを適切に管理する。
　・ポート番号を利用する。
・TCPは通信データの品質を維持する機能を有している。
　・コネクション管理、順序制御、再送制御、流星制御、輻輳制御をおこなう。
　・ファイル転送のような大きく連続したデータの送信に向いている。
・UDPはTCPのような品質管理はおこなわない。
　・必要なら上位のアプリケーション側でおこなう。
　・音声通信のような散発的なデータ送信に向いている。


ポート番号
・上位アプリケーションを認識する番号（0〜65535)のこと。
・0〜1023はクライアントにサービスを提供するサーバ側で使用される。
・0〜1023はWell-Knownポートと呼び、IANAで管理され、Webサーバやメールサーバなど広く知られたサービスの用途で使われる。
・クライアント側は1024〜65535の中からランダムに選択されて使用される。


UDPデータグラム
・Source Port
　・送信元のポート番号を示す。送信元がクライアントでサーバからの応答が不要な場合には０が入る。
・Destination Port
　・宛先のポート番号を示す。
・Length
　・UDPヘッダとペイロードの合計サイズをオクテット単位で示す。
・Checksum
　・誤り検査のために使用される。

TCPセグメント（１）
・Source Port
　・送信元のポート番号を示す。
・Destination Port
　・宛先のポート番号を示す。

TCPセグメント（２）
・Sequence Number
 ・送信したデータサイズ（オクテット単位）が値として加算される。加算されていくのでデータの順序もこれで分かる。スタート時の初期値は乱数により決定される。
・Acknowledgment Number
　・データを受信したことを知らせる。受信したデータのSequence Numberデータサイズが入り相手にとって次のSequence Numberになる。

TCPセグメント（３）
・Data Offset
　・32ビット単位でTCPヘッダの長さを示す。通常、オプションが無い場合のTCPヘッダは20オクテットなので５が入る。
・Reserved
　・将来に備えて予約されている。０が入る。

TCPセグメント（４）
・Control Bits(左から順に各１ビットごとにフラグになっている）
　・NS（Nonce Sum)は実験用として割り当てられている。
　・CWR(Congestion Window Reduced)は輻輳のために送信データ量を減らしたことを通知する。
　・ECE(ECN-Echo)はネットワークが輻輳していることを相手に通知する。

TCPセグメント（５）
・URG（Urgent Flag)の時は緊急に処理するデータがあることを意味する。
・ACK（Acknowledgement Flag)は確認応答に使う。最初のSYN以外は１になる。
・PSH(Push Flag)が１の時は受信データアプリケーションに即座に渡すことを意味する。
・RST(Reset Flag)はコネクションを強制的に切断したい時に使う。
・SYN(Synchronize Flag)はコネクションを確立したいことを相手に伝える。
・FIN(Fin Flag)は全てのデータ送信が終了し、コネクションを切断したい時に使う。


TCPセグメント（６）
・Window
 ・受信できるデータサイズをオクテット単位で通知する。
　・Acknowledgment Numberで伝えた数字からWindow分が次回に送信できる。
　・送信側が０で通知を受けた場合はデータサイズ１のWindowプローブを送ることができる。
・Checksum
　・誤り検査のために使用される。


TCPセグメント（７）
・Urgent Pointer
　・Control BitsのURGが１の時に有効なフィールドとなる。
　・データの先頭からこの値の位置までのデータが緊急で処理されることを意味する。
・Option
　・TCPの通信性能を向上させるために使用される。32ビット単位のため不足分は0でPaddinaされる。
　・コネクション確立時にMSSを通知するのに使われる。

MSS
・TCPヘッダを除いたデータサイズをMaximum Segment Sizeと呼ぶ。
・IPでのフラグメントが起きないようにEthernetペイロードから逆算して
1460オクテットとなることが多い。
・他のヘッダを付与するような技術を使うとさらにMSSは小さくなる。
・最近ではEthernetフレームのペイロードを1500オクテット以上扱える技術もある。


コネクションの確立
・3Way Handshakeにより通信に先立って双方の通信準備を整える。
・Control BitsのSYNとACK に注目する。


コネクションの切断
・Control BitsのFINを使う。
・相手の終了＝自分の終了ではない。


順序制御
・Seq Noは送信したデータサイズ（オクテット単位）が加算。初期値は乱数により決定される。
・Ack Noに受信データのSeq No +データサイズの数字が入り、相手の次のSeq Noになる。


スライディングウィンドウ
・ウィンドウは受信できるデータサイズをオクテット単位で通知する。
PowerPoint 表の操作　セルの結合と分割で遊ぶ

なんか試しにいろいろいじってたら妙な表ができたのでなんとなくまとめた

テキトーに表を入れる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/6a8b1fae-d2e4-7c27-ffdc-fc63a3298117.png)

これを選択して`UnMergeCell`を何度か実行していくとこうなる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/9338ef96-7d08-98ad-4585-bc9927efc9bf.png)

`MergeCell`を繰り返すともとに戻せる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/8bd22277-3075-1c3c-d704-c521765eff2a.png)



### コード（標準モジュール）
``` vb
Sub MergeCell()
  Call Table上のセルのマージ(1, 1, 2, 3)
End Sub
Sub UnMergeCell()
  Call Table上のセルの分割(1, 1, 2, 3)
End Sub
Sub Table上のセルのマージ(R1 As Long, C1 As Long, RLast As Long, CLast As Long)
  On Error GoTo ErrLabel
  Dim tbl操作対象 As Table
  With ActiveWindow.Selection
    
    If .Type = ppSelectionNone Or _
    .Type = ppSelectionSlides Then Exit Sub
    
    Set tbl操作対象 = .ShapeRange.Table
    
  End With
  
  With tbl操作対象
    
    .Cell(R1, C1).Merge _
      MergeTo:=.Cell(RLast, CLast)
    
  End With
  Exit Sub
ErrLabel:
  With Err
    MsgBox "エラーNo:" & .Number & vbLf & .Description
  End With
End Sub

Sub Table上のセルの分割(R1 As Long, C1 As Long, 分割数 As Long, 分割数C As Long)
  On Error GoTo ErrLabel
  Dim tbl操作対象 As Table
  With ActiveWindow.Selection
    
    If .Type = ppSelectionNone Or _
    .Type = ppSelectionSlides Then Exit Sub
    
    Set tbl操作対象 = .ShapeRange.Table
    
  End With
  
  With tbl操作対象
    
    .Cell(R1, C1).Split 分割数, 分割数C
    
  End With
  Exit Sub
ErrLabel:
  With Err
    MsgBox "エラーNo:" & .Number & vbLf & .Description
  End With
End Sub
```
PythonからREDMINEのWIKIにアクセスする方法の検討

# 背景

REDMINE-WIKIについて、プログラミングで操作する方法を調べている。
（話の経緯は下記参照）

https://qiita.com/EasyCording/items/c2c3a5850941f45d1317

今回はpythonからREDMINEのWIKIにアクセスする方法を検討した。


## 前提
　ライブラリはpython-redmineを使う。　　　　https://python-redmine.com/resources/wiki_page.html
　すでにREDMINEには接続済みの状態とする。　（詳細のコードは省略する）

## Wikiへのアクセスコード
　以下はpython-redmineを使ったクラスメソドである。

```python
from redminelib import Redmine

class RedmineWork:

    def read_project(self):
        projects = self.api.project.all( limit=100)
        wikipages =[]
        for pjt in projects:
            wikis = self.read_wikis(pjt.id) 
            for wiki in wikis:
                wikipage = self.get_wiki_byname(wiki.title,pjt.id)
                wikipages.append(wikipage)
        
        return wikipages

    def read_wikis(self,id):
        pages = self.api.wiki_page.filter(project_id=id)
        return pages

    def get_wiki_byname(self,name,id):
        page = self.api.wiki_page.get(name,project_id=id)
        return page

    def wikieditor(self):
        wikipages = self.read_project()
        pdb.set_trace()

```

## Wikiコンテンツへのアクセス方法
1. プロジェクトを全部引っこ抜く  read_project
1. wikiを全部引っこ抜く　 read_wikis    --->  この時点では中身は取れていない！！！
1. wikiの記事を取りに行く   get_wiki_byname    --->  ここでやっと取りに行ける

## つまづいていた点
以下のメソドの違いでつまづいていた。。。（こんな名付けでは、誤解するのも当然である）
　.filter　--->　　これはリソースセット(wiki_pages)で取りに行くもの（wiki-idしか入っていない）
　.get     --->　　page-idを指定して、初めて中身(wiki_contents)を取りに行くことができる
  
そもそも、WIKIのER図を理解していなかった。
https://www.flickr.com/photos/kiwamu/3851572819/

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212914/724a2584-c6f8-6887-feb7-fc34c76aab12.png)


これを突破口として、以下のメソドを実装する。

1. コンテンツ丸ごとを取得するAPI
1. グラフィック上に、wikiツリーを表示（ドラッグ&ドロップで、階層構造の付け替えが出来る）
1. Wikiの親子関係を修正後に、Redmineデータベースに反映する
1. wikiインポート、エクスポートを作る
1. 機械学習でクラスタリングして、自動整理を行う　→　最終的にここまで出来れば上等である
【Swift】UITextViewにプレースホルダーをつける


##まえがき
• notionでメモ程度に書いてるのをQiitaでまとめてみた!
• 自分用
• UITextViewにプレースホルダーねーじゃんってなったので作ってみた
# プレースホルダー付きカスタムTextView↓
```swift
import UIKit

class CustomTextView: UITextView {
    
    var placeholderText: String? {
        didSet{ placeholderLabel.text = placeholderText }
    }
    
    let placeholderLabel: UILabel = {
        let label = UILabel()
        label.textColor = .gray
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    //y軸をセンターにするー
    var placeholderShouldCenter = true {
        didSet{
            if placeholderShouldCenter {
                NSLayoutConstraint.activate([
                    placeholderLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 6),
                    placeholderLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 8),
                    placeholderLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 0)
                ])
            } else {
                
                NSLayoutConstraint.activate([
                    placeholderLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 6),
                    placeholderLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 8)
                ])
            }
        }
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        addSubview(placeholderLabel)
        //AutoLayoutの制約
        NSLayoutConstraint.activate([
            placeholderLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 6),
            placeholderLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 8)
        ])
        //オブザーバーを使って監視
        NotificationCenter.default.addObserver(self, selector: #selector(handleTextDidChange), name: UITextView.textDidChangeNotification, object: nil)
    }
    //変更通知を受け取った時にplaceholderLabelをTextViewのtext.isEmptyで隠すか判断する
    @objc func handleTextDidChange() {
        
        placeholderLabel.isHidden = !text.isEmpty
    }
    
    
}


```

##手順
####storyboardのTextViewにちゃんとカスタムクラスを割りあってからコードと繋げよう
![スクリーンショット 2021-10-29 20.56.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1679562/9a8c22c9-d9e5-73d4-1f6d-7029ee589dbf.png)





####ViewControllerはこんな感じ
```swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var textView: CustomTextView!
    
    @IBOutlet weak var centerYTextView: CustomTextView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        textView.placeholderText = "入力しろや"
        centerYTextView.placeholderShouldCenter = true
        centerYTextView.placeholderText = "YCenter"
    }


}


```
##  完成イメージ
![IMB_ksZshe.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1679562/9e3d13ff-141a-b344-6fbd-af6bb7efec67.gif)




##終わりに
xibファイルはなくてもok
誰かの参考になれば幸いです
Qiitaさんいつもお世話になってるので感謝
間違えてるところ等ありましたら教えてくださいー

##参考
https://qiita.com/REON/items/a5b2122785792f83f851
Google Cloud Storage キャッシュを変更

なぜか知らないが、vue.jsでGoogle Cloud Storageの画像を読み出すと、
ところどころ真っ白になったり読み出せなかったりする。

理由は不明。
まぁ、キャッシュかなと考えているので
Google Cloud Storage の デフォルト 3600秒の画像のキャッシュを伸ばす。


アップロード時にオプション設定してもうまくいかないので、
アップロード後に変更する

```hoge.php

$img = public_path($file);

$object = $bucket->upload(
    fopen($img, 'r')
);

$object->update([
    'cacheControl' => 'public, max-age=2592000'
]);

```

こんな感じ。

とりあえず、すでにあるファイルを変更する場合は以下。

```hoge.php

$storage = new StorageClient([
    'projectId' => config('app.gcp_project_id'),
    'keyFile' => json_decode(file_get_contents(config_path('gcp.json')), true)
]);

$bucket = $storage->bucket(config('app.gcp_bucket_name'));

$objectName = "menuphoto-300x300-10.jpg";

$object = $bucket->object($objectName);

$object->update([
    'cacheControl' => 'public, max-age=22220'
]);

$object = $bucket->object(
    $objectName
);

$info = $object->info();
var_dump($info);

```

こんな感じ。

おまけ

オブジェクト一覧を取得

```hoge.php

//        オブジェクト一覧を取得
        foreach ($bucket->objects() as $object) {
            echo $object->name()."<br>";
        }

```




参考
https://blog.leko.jp/post/how-to-customize-cache-settings-of-google-cloud-storage/

https://cloud.google.com/storage/docs/caching

一括変更はこちら
https://yamavlog.com/modify-gcs-cache-time-on-eage-cache/
スクリプトがアタッチされているオブジェクトを探す方法

##0.0 はじめに
Script（スクリプト）がコンポーネントとしてアタッチされているObject（オブジェクト）を探す方法です。
間違ってアタッチしたScriptがどこかで動いてエラーを出しているって時に役に立ちます。



##1.0 初心者
単純に対象のScriptのStart()に Debug.Log($"私は {name} です"); と書いておけばConsole（コンソール）画面にオブジェクトの名前が表示されます。


##2.0 プロフェッショナル
Project内にある対象のScriptを右クリックすると出てくる**Find References In Scene**を使います。
Hierarchyに対象のScriptがアタッチされたオブジェクトが出ています。

👍**ポイント**
この**Find References In Scene**はScript以外でも使用可能です。特定のPrefabを使用しているObjectを探すこともできます。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352037/0a02c192-55be-a743-f4f6-190533933ab9.png)
Databricks AutoMLで時系列データ予測をサポートしました

:::note info
本機能を利用するには、Databricksランタイム 10.0 ML以降が必要です。
:::

Databricksランタイム 10.0以降でAutoMLの時系列データ予測をサポートしました。この記事では、GUIによる操作方法をご説明します。なお、APIからも本機能を利用できます。

# データの準備

事前にトレーニングデータを「forecast_train_df」としてデータベースに登録しておきます。ここでは、COVID-19感染者数の時系列データを使用します。

```py:Python
import pyspark.pandas as ps
df = ps.read_csv("/databricks-datasets/COVID/covid-19-data")
df["date"] = ps.to_datetime(df['date'], errors='coerce')
df["cases"] = df["cases"].astype(int)
display(df)

# AutoML UIから参照できるようにデータフレームをテーブルに保存します
sdf = df.to_spark()
sdf.write.saveAsTable("forecast_train_df")
```

# GUIを用いた時系列データ予測AutoML

1. ペルソナスイッチャーで「Machine Leaning」を選択し、Experimentにアクセス
![Screen Shot 2021-10-29 at 20.57.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/d00bb820-9b66-8baa-f680-407a29a06869.png)

1. Create AutoML Experimentをクリック
![Screen Shot 2021-10-29 at 20.58.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/c6bfc440-660b-c9bb-67b3-0314633e8809.png)

    **Compute**フィールドで、Databricksランタイム 10.0ML以降が稼働しているクラスターを選択します。

1. **Dataset**フィールドではデータベースに保存したテーブルを選択します。
![Screen Shot 2021-10-29 at 20.59.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/1ea3f9b4-abaa-4f9c-f792-bc3a95eb6cb4.png)

1. **Prediction target**では`cases`を選択します。
1. **Time column**では`date`を選択します。
1. **Forecast horizon and frequency**では`10 Days`を指定して、向こう10日間の予測を行うように指示します。![Screen Shot 2021-10-29 at 20.59.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/50ddca66-f66c-7f08-0283-b2b80141fc0d.png)
1. 必要に応じて**Advanced Configuration (optional)** を展開して終了条件を指定した後、**Start AutoML**をクリックし、トレーニングを開始します。
![Screen Shot 2021-10-29 at 21.00.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/4b4977ac-f4e7-9f8f-86cb-1135e0c95d64.png)
1. トレーニング、評価が完了すると、ベストモデルを生成したノートブック(View notebook for best model)とトレーニングデータのトレンドを分析したノートブック(View data exploration notebook)にアクセスできるようになります。
![Screen Shot 2021-10-29 at 21.08.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/64bd8be8-7f70-0323-4384-a134862bf0bc.png)

# APIを用いた時系列データ予測AutoML

APIを用いたサンプルノートブックはこちらにあります。

https://github.com/taka-yayoi/public_repo/tree/main/AutoML_forecast

ノートブック上で予測結果をプロットすることも可能です。
![Screen Shot 2021-10-29 at 21.12.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/5a053263-c37f-88b9-5946-d49a96c0e177.png)

詳細は[Databricks AutoMLのマニュアル](https://qiita.com/taka_yayoi/items/0ed860131a02aeade14f)をご覧ください。

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
Azureを使って仮想マシンを構築する

## 目標
Azureを使用してWindowsサーバーの仮想マシンを構築する

## 手順
https://dev.classmethod.jp/articles/azure-first-vm/

このサイトがめちゃくちゃわかりやすかった。

## 気付き

事前にIP範囲とサブネットマスクを指定していたので、構築後のネットワーク設定が不要だった
DHCPサーバーが自動で入っていたのか、構築した時点でIPアドレスは割り当てられていた。

![スクリーンショット 2021-10-29 21.09.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/cf60c5d6-d936-c198-f1eb-d37f3891e3f6.png)

画像のIPアドレスは既に削除済み

## まとめ
めちゃくちゃ簡単だった。
次はアプリのデプロイまで頑張る。
【超初心者向け】ラズパイで上手くいかないときはファイアウォールを確認しよう！

ラズパイ超初心者の私がRaspberry Piをいろいろといじってたときに意外と手こずってしまった、ファイアウォールの設定についてまとめてみます。
やり方はこの記事で紹介した方法以外にもありますが、超初心者向けということで割愛させていただきます。

環境
本体：Raspberry Pi 4 Model B　(4GB)
OS：Raspberry Pi OS （buster / 32bit）

本体：Raspberry Pi Zero 2 W
OS：Raspberry Pi OS Lite （bullseye / 64bit）

# 1. （急いでいる方向け）今すぐポートを開放する方法
以下の4つのコマンドを入力すると、ポートの開放ができます。
ゆっくりやりたい方は、2.~5.も確認してみてください。

```md:①インストール
$ sudo apt install ufw
```

```md:②有効化
$ sudo ufw enable
```

`22`の部分を開放したいポート番号に置き換えます。
```md:③ポートの開放
$ sudo ufw allow 22
```

```md:④設定の再読込
$ sudo ufw reload
```

# 2. ファイアウォールをインストールする
ファイアウォールは次の手順でインストールすることができます。

### インストール

```md:インストール
$ sudo apt install ufw
```

:::note info
aptとapt-getについて
```md:以前の方法（apt-get）
$ sudo apt-get install ufw
```
以前はインストール時に`apt-get`を使用していましたが、現在は`apt`が主流のようです。
:::

# 3. ファイアウォールの有効化・無効化
ファイアウォールの有効化・無効化の方法です。

### ファイアウォールの有効化

```md:有効化
$ sudo ufw enable
```

### ファイアウォールの無効化
ファイアウォールの設定が保持されたまま無効化されます。

```md:無効化
$ sudo ufw disable
```

### ファイアウォールをリセットして無効化
ファイアウォールの設定が初期状態にリセットされて無効化されます。

```md:無効化
$ sudo ufw reset
```

### ステータスの確認

```md:ステータスの確認
$ sudo ufw status
```

ファイアウォールが有効化されていれば次のように表示されます。

```md:表示例
Status: active
```

# 4. ポート開放
### 開放ポート設定
ここでは例としてHTTP通信を行うための80番ポートを開放します。

```md:80番ポートの開放
$ sudo ufw allow 80
```

`sudo ufw status`でステータスを確認してみると、次のように表示されるはずです。

```md:表示例
Status: active

To                         Action      From
--                         ------      ----
80                         ALLOW       Anywhere
80 (v6)                    ALLOW       Anywhere (v6)
```

### 設定の適用
設定を再読込して適用させます。

```md:設定の再読込
$ sudo ufw reload
```

# 5. ポート削除
ここでは80番ポートのみ開放された状態であるとします。

### ルールを指定して削除

80番ポートを削除します。

```md:80番ポートの削除
$ sudo ufw delete allow 80
```

`sudo ufw status`でステータスを確認してみると、次のように表示されるはずです。
ポートを複数許可している場合は、削除したポートのみリストからなくなっています。

```md:表示例
Status: active
```

### 設定の適用
設定を再読込して適用させます。

```md:設定の再読込
$ sudo ufw reload
```

# 6. よく開放するポート
ここでは個人的によく開放するポートをまとめます。
あれ、動かないぞ？と思ったらポートが開放されているか確認しましょう。

### HTTP（80番ポート）
```md:HTTP（TCP/80）
$ sudo ufw allow 80
```

### HTTPS（443番ポート）
```md:HTTPS（TCP/443）
$ sudo ufw allow 443
```

### SSH（22番ポート）
```md:SSH（TCP/22）
$ sudo ufw allow 22
```

### VNC（5900番ポート）
```md:VNC（TCP/5900）
$ sudo ufw allow 5900
```

# 7. 更新履歴

- **2021/10/29**
・投稿

- **2022/09/07**
・微修正

- **2023/06/24**
・レイアウトの見直し
・内容の簡単化
・テストした環境の追記
・一部のコマンドを変更
cppreference.comで特定の規格だけ見る方法

[cppreference.com](http://en.cppreference.com) はC、C++のリファレンスサイトです。
デフォルトだと全ての規格が表示されて見辛いですが、特定の規格だけ見る方法を知ったので共有します。

## 手順

1. [cppreference.com](http://en.cppreference.com) のページ上部にある「Create account」をクリックし、ユーザ登録します。
   ![Create account](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266322/985fe89b-6cc1-00de-c5dd-c717674af73a.png)
1. Preferencesから「Gadgets」タブを選択し、「\<gadget-StandardRevisions\>」のチェックボックスをONにして、「Save」ボタンをクリックします。
   ![Preference](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266322/b5156147-901b-02a2-be31-ed244bf94922.png)
1. Preferenceページ以外に移動すると、ページ上部で「Standard revision」を選択できるようになります。
   ![Standard revision](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266322/bb5b8623-c5c8-2512-eb5f-b1173a365903.png)  
   例えば、[std::vectorのコンストラクタのページ](https://en.cppreference.com/w/cpp/container/vector/vector) で「C++98/03」を選択すると以下のようにフィルタリングされた表示になります。  
   ![C++98/03](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266322/0b43d6d6-9f02-b3e1-818b-4f099fc09212.png)

## 参考URL

https://www.reddit.com/r/cpp/comments/nofcuj/what_happened_to_cppreferencecom/
GitHub Actionsの活用事例メモ

## はじめに

最近、GitHub Actionsを勉強し始めたのでCI/CDの自動化以外にもどんなことに利用できるのか知りたくてまとめました。
今後も、なにか見つければ載せていこうと思います。

主に記事として紹介されているものを中心にmarketplaceにあるなかで利用できそうなものについても探してみました。

https://github.com/marketplace?type=actions

## 利用例

### リリース作業の効率化（リリースノートとかリリースのSourceとかを自動作成）

https://dev.to/puku0x/github-actions-1mi5

ありきたりな話ですが、リリースノートの作成といったリリース作業の自動化は価値あるかも。
csprojといったプロジェクトファイル上にちゃんと情報を記載しておけば、その内容を元に自動でリリースノートが作成するのはそう難しくもないはず。

### Pull RequestやIssueのコメントからGitHub Actionsを実行する

https://akaimo.hatenablog.jp/entry/2020/05/16/101251

GitHubのIssueで行なうコメントにはイベントがあり、Pull Requestについても同様のイベントが取れるらしいです。
私のチームでは毎日、定期報告としてIssueの進捗状況をコメントするようにしています。
特定のコメントを入力するとその日のコミット一覧を羅列したテンプレートコメントみたいなものが出せたりすると面白そうです。

トリガのタイミングを時刻にもできるはずなので、毎日決まったタイミングでその日のコミットした一覧とともに報告とか自動化できるとはかどりそうですね。

### 一定期間放置されたIssueをCloseする

https://tech.pepabo.com/2021/03/03/ec_efficiency_with_github_actions/#%E4%B8%80%E5%AE%9A%E6%9C%9F%E9%96%93%E6%94%BE%E7%BD%AE%E3%81%95%E3%82%8C%E3%81%9Fissue%E3%82%92close%E3%81%99%E3%82%8B

やりっぱなしにならないように仕組みとしてこういうの導入してあっても面白そうですね。


### GitHub Projectsのカラム移動でラベルを付与・削除する

https://tech.pepabo.com/2021/03/03/ec_efficiency_with_github_actions/#github-projects%E3%81%AE%E3%82%AB%E3%83%A9%E3%83%A0%E7%A7%BB%E5%8B%95%E3%81%A7%E3%83%A9%E3%83%99%E3%83%AB%E3%82%92%E4%BB%98%E4%B8%8E%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B

（Projectsはカンバンみたいなやつです）
手動で移動させてラベルとかを適宜変えてというのは意外と大変なのでProjectsをよく利用するのであれば、便利そうですし、他にも応用が効きそうな手法ですね。

上記のようなタスク管理にGitHub Actionsを利用したいという場合には公式が参考事例を提示してくれているので参考になるかもしれません。

https://docs.github.com/ja/actions/managing-issues-and-pull-requests/using-github-actions-for-project-management

### Slackなどに通知する

https://fireship.io/lessons/five-useful-github-actions-examples/#:~:text=NODE_AUTH_TOKEN%3A%20%24%7B%7Bse[…]hat%20messages,-Yet%20another%20powerful

プルリクエストしたことを確認者にすぐに知らせるために「プルリク作成しました」といつもSlackで一報していたのですが、このあたりも自動化できると楽になりそうです。
また、テストやSonarCloudが失敗していればすぐにSlackで教えてくれると対応もしやすいかもしれません。

marketplaceにも似たようなのはいろいろありました。

https://github.com/marketplace/actions/slack-send

https://github.com/marketplace/actions/slack-github-actions-slack-integration

### 今日の主題と違うけど、ためになったのでメモ

このアクションにより、依存関係をキャッシュし、出力をビルドして、ワークフローの実行時間を改善できます。
GitHub Actionsの活用というよりは、GitHub Actionsそのものの改善ですが、ワークフローの実行時間は利用制限などもあるので少しでも短くする工夫は大事ですよね。

https://github.com/marketplace/actions/cache

また、以下のような知見も知っておくとどこかで役に立ちそうです。

>また、Dockerタイプのものはワークフロー実行の最初にまずイメージをビルドする必要があるため実行時間が結構伸びます。ですので同じ機能のActionが複数ある場合可能ならJavaScriptタイプを選ぶほうが良いです。

https://qiita.com/bigwheel/items/2ab7deb237122db2fb8d#action%E3%81%AE%E7%A8%AE%E9%A1%9E%E3%81%AFjavascript%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AE%E3%81%9D%E3%82%8C%E3%81%A8docker%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AE%E3%81%9D%E3%82%8C%E3%81%8C%E3%81%82%E3%82%8B
MAN とは

## 勉強前イメージ

メトロポリタン・エリア・ネットワーク だけど都市ってなに？
都市はWANじゃないの？？

## 調査

### MAN とは

Metropolitan Area Network の略で、60km程度の範囲をカバーする名前通り都市などで使われます。
MANは複数のLANを共通のブリッジを持つ単一の大きなネットワークに接続するネットワークです。
ブリッジは光ファイバーで構築されます。
WANほどではないが、LANより広いネットワーク。

### ユースケース

LAN同士を接続したネットワークで、
大学のキャンパスや大企業などで、施設ごと・ビルごとのLAN同時を接続し相互に通信を可能にしています。
CAN(Campus Area Network) と呼ぶこともある。

## 勉強後イメージ

どういうときに使うかとか考えたけど、
キャンパス内とかはMANになるのか・・・・
なんとなくイメージ出来た。

## 参考

- [LAN vs MAN vs WAN：違いは何ですか？](https://community.fs.com/jp/blog/lan-vs-man-vs-wan-whats-the-difference.html)
- [MAN （Metropolitan Area Network）](https://atmarkit.itmedia.co.jp/icd/root/29/27832929.html)
Jetpack Compose 枠線つきの角丸

AndroidのJetpack Composeで大枠のComposeを枠線つきの角丸にする方法です。
この記事は以下のバージョンに対応しています。

| | バージョン |
|:-----------|:------------:|
|Jetpack Compose|1.0.4|
|AndroidStudio|ArcticFox 2020.3.1 Patch 3|

# Viewの場合
Viewを枠線つきの角丸にする場合、下記のようなxmlファイルを作成し、Viewのbackgroundに定義しました。

```xml:rounded_corner_bg.xml
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
  android:shape="rectangle">

  <corners android:radius="20dp" />
  <stroke
    android:width="2dp"
    android:color="@color/black" />
</shape>
```

# Jetpack Composeの場合
Row、Column、ConstraintLayoutといった大枠のComposeを枠線つきの角丸にする場合、下記のようなModifierをComposeのmodifierに定義することで実現できます。

```Kotlin
Modifier
    .border(
        width = 2.dp,
        color = Color.DarkGray,
        shape = RoundedCornerShape(20.dp)
    )
    .background(
        color = Color.Gray,
        shape = RoundedCornerShape(20.dp)
    )
```
borderとbackground両方のshapeにRoundedCornerShapeを定義する点に注意が必要です。

## 例
```Kotlin:RoundedHorizontalBar.kt
@Preview(showBackground = true)
@Composable
fun RoundedHorizontalBar() {
    Row(
        modifier = Modifier
            .height(60.dp)
            .fillMaxWidth()
            .padding(8.dp)
            .border(
                width = 2.dp,
                color = Color.DarkGray,
                shape = RoundedCornerShape(20.dp)
            )
            .background(
                color = Color.Gray,
                shape = RoundedCornerShape(20.dp)
            ),
        verticalAlignment = Alignment.CenterVertically
    ) {
        Icon(
            modifier = Modifier.padding(8.dp),
            imageVector = Icons.Rounded.Done,
            contentDescription = "Done"
        )
        Text(text = "テキスト")
    }
}
```
![スクリーンショット 2021-10-29 17.01.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356260/ad497baa-7d19-4091-34d2-a0be9b707f13.png)
SourceTree で invalid format がでて秘密鍵が使えない

使えるときもあれば使えるときもあり、条件は正直分からない。
少なくとも putty でkeyを作ったならopenssh形式に変換すると何とかなる。

ただターミナルから操作するときは注意。
ssh-add がそのままではおそらく使えない。
ssh-agent を叩いておく必要があるが、これもひと工夫必要。

```terminal
$ eval `ssh-agent`
Agent pid 1669

$ ssh-add .ssh/id_rsa_openssh.ppk
Enter passphrase for .ssh/id_rsa_openssh.ppk:
Identity added: .ssh/id_rsa_openssh.ppk
```

eval が必要なのは windows 環境だからだと思う。
Automation360のIQbotをAWSへ同居

### AWS上のWindows Server 2016 Datacenter EditionにAutomation360.21とIQBot.21を同居させて構築した。
IQBotを同居させる手順はいくつか公開されているが、AWS上はAzureに比べて癖が強くて1年掛かって構築出来たのでここにポイントと手順を記録に残そうと思う。

:::note warn
同居のポイント
・URLを間違うとヘルスチェックはすべて正常なのに外部からのアクセスが出来なくなる。
・Windowsマシン名に<b>アンダースコア</b>を入れるとIQBotのヘルスチェックが謎のInternalServerエラーになるなどの弊害が出る。
:::

### 事前準備

:::note info
1、ポート3000を開ける
2、SQLServerをSQL・Windows認証モードでログインできるようにする。
3、SQL認証モードの管理ユーザのsaをログイン可能にし、パスワードも設定する。
4、SQLブラウザーサービスを起動する。
5、SQLServerインスタンスを再起動する。
6、Microsoft ManagementStudio18を使って、SQL・Windows認証モードで設定したsaアカウントでログイン出来る事を確認する。
7、Windowsのマシン名に_（アンダースコア）を入れることは可能であるが、IQBotインストーラーではエラーになるので_（アンダースコア）が使われていない事を確認する。使われている場合は、ｰ（ハイフォン）などに置き換える事。
<B>※これすごく大事。これがあるとインストール出来るがControlRoomに登録出来ない。
:::

インストール手順
①IQBotインストーラーはカスタムインストールを選択する。
　※別筐体の場合はTypicalで問題ないが、同一の場合はSQL認証モードでSQLServerへログインする必要がある

②SQLServerはlocalhostではなくWindowsのマシン名を設定する。
![IQ1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/608295/25b2d66e-f7f8-99a2-9c7d-18c88cf75dad.png)

③IQBotのサーバ名を指定する画面で、指定するサーバ名はAWSの外部DNS名（グローバルDNS名）にしないといけない。これを間違えるとAWS外からIQBOT管理画面へリダイレクトする時に画面が表示出来ない。
<B>ヘルスチェックもすべて正常に通るので原因不明で嵌まるのでこれも大切なポイント。
TextViewで文字数の制限&カウントダウン&色変化などを実装

なんかややこしいタイトルで申し訳ございません。

要は、こんな感じのを作ります。

![qiita動画3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1106647/bb6f1fc5-0ce6-cea3-8692-873ba7072e8b.gif)

ここでやってること(やりたいこと)を大まかに言うと、
①TextView内の文字が打たれる度に、ラベルをカウントダウンさせる
②任意の最小値(ここでは0に設定)を下回ると、文字を打てなくする
③任意の最小値(ここでは0に設定)を下回ると、TextViewの枠線を赤色に変化
③任意の値(ここでは10に設定)を下回ると、文字を赤文字に変化

の4つです。

ではいきましょう！

<h1>はじめに</h1>

まずはコード全体から

```php

import UIKit

class ViewController: UIViewController {

    //テキストビュー
    @IBOutlet weak var myTextView: UITextView!
    //残り文字数を表示するラベル
    @IBOutlet weak var anotherCountLabel: UILabel!
    //入力可能文字数を設定(任意の値)
    private var maxCount : Int = 30
    //「これ以上入力できません」のラベル
    @IBOutlet weak var cannotWriteMore: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
       
        NotificationCenter.default.addObserver(self, selector: ＃selector(textViewDidChange(notification:)), name: UITextView.textDidChangeNotification, object: nil)
        
        //隠しておく
        cannotWriteMore.isHidden = true
    }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }

    @objc private func textViewDidChange(notification:NSNotification){
      
        let textView = notification.object as! UITextView
        
        //残り文字数ラベルをInt型に変換しておく
        let toIntAnotherCountLabel = Int(anotherCountLabel.text!)
        //①カウントダウンさせる
        anotherCountLabel.text = String(maxCount - myTextView.text.count)
        //②残り10文字で赤文字にする
        if toIntAnotherCountLabel! <= 10{
            anotherCountLabel.textColor = UIColor.red
        }else if toIntAnotherCountLabel! >= 10{
            anotherCountLabel.textColor = UIColor.black
        }
        //③文字数制限(文字が30文字を超えたら入力出来なくする)
        if textView.text.count >= maxCount{
            textView.text = textView.text.prefix(maxCount).description
            //TextViewの枠線の色を赤にする
            textView.layer.borderColor = UIColor.red.cgColor
            textView.layer.borderWidth = 2.0
            //隠してた文字を出現させる
            cannotWriteMore.isHidden = false
        }else{
            textView.layer.borderColor = UIColor.clear.cgColor
            //また隠す
            cannotWriteMore.isHidden = true
        }
        //数合わせ
        if anotherCountLabel.text == "-1"{
            anotherCountLabel.text = "0"
        }
    }

}

```

cannotWiteMoreは、値が0以下になった際に表示したいため、初期値ではisHiddenをtrueにしてます。

コードの最後に数合わせとありますが、これは読んで字のごとく、ラベルに−１と表示されてしまうので、それ防ぐために0を代入させています。

ちなみに、自分の場合はオブザーバーを設置していますが、普通にUITextFieldが独自に持つメソッドを用いる方が楽かもしれないので、そこは柔軟にお願いします。


<h1>さいごに</h1>

お疲れ様でした！！！
RetrofitでDELETEメソッドに@Bodyつける

# 問題
retrofit使ってたらこんなエラーが出た

```
android retrofit non-body http method cannot contain @body.
```

DELETEやGETメソッドで`@Body`を使ったjsonリクエストはできないらしい

# 解決
いやいや、できる

```kotlin
@DELETE("https://hogehoge/fugafuga")
↓
@HTTP(method = "DELETE", path = "https://hogehoge/fugafuga", hasBody = true)
```

`@Body`つけれた
【SwiftUI】複数ジェスチャーの実装

#SimultaneousGesture
SwiftUIで複数のジェスチャーを実装する方法がわからなかったので、備忘録として残しておきます。
複数ジェスチャーの実装をするには**SimultaneousGesture**を実装する必要があります。
以下はオブジェクトの拡大・縮小と移動の２つのジェスチャーを設定したコードになります。
SimultaneousGestureの引数に設定したいGestureを設定することで、複数ジェスチャーの実装ができます。

```swift
let magnificationGesture = MagnificationGesture()
   .onChanged { scale = $0 * initialScale }
   .onEnded{ _ in initialScale = scale }
let dragGesture = DragGesture()
   .onChanged { offset = CGSize(width: initialOffset.width + $0.translation.width, height: initialOffset.height + $0.translation.height) }
   .onEnded{ _ in initialOffset = offset }

RoundRectangle()
   .gesture(SimultaneousGesture(magnificationGesture, dragGesture))
```

#参考
https://software.small-desk.com/development/2021/06/28/swiftui-pinch-and-drag/
Sphinxにpull requestするまでの流れ

現在pull requestで結果待ちなのですが、当初は分かっていなかった点を押さえつつ手順のメモ。

# 1．ユーザー登録

- https://github.com
- https://circleci.com/ja/
- https://readthedocs.org

# ２．Githubにて

1. sphinx-dco/sphinx を fork
1. USERNAME/sphinx をローカルに clone

# ３．circleciにて

1. USERNAME/sphinx を選択して登録（「既存の設定」を選択）
1. 登録したパイプラインが動いて、テストが成功で終わることを確認する。

# ４．ここから変更作業

1. ローカルのclone環境でブランチを作る。
1. （ソースファイルを加えたり、既存のコードを改善したり）
1. git pushする都度、circleciでテストが走る。（エラーは[【この記事】](https://qiita.com/kter/items/84f3ece9a41a2bec535f)で解決）
1. 変更内容に満足したら、次のステップへ

# ５．githubにて

1. pull requestを行う。英語なので頑張る。
1. pull requestを登録すると、circleciとreadthedocsが走る。
1. エラーが出たら内容を確認して修正。
  - commit/pushするとpull requestしたissueに反映される
  - circleci/readthedocsもその都度走る

エラーメッセージを見てもよくわかりません。どれも作ったクラス内のエラーだったので、エラーの発生箇所で「repr(self)」を表示するように手を加えて、その情報を元に修正しました。必要な情報が得られるように `__repr__` は定義済み

# 以上
【React】useStateとuseRefの違い

# useStateとuseRef
- どちらも値を保持することができる

## useState
- 値を更新すると、コンポーネントの再描写が行われる

## useRef
- 値を更新しても、コンポーネントの再描写は行われない

## サンプルコード
下記コード内の

- `カウントアップ（useState）` ボタンを押下時、 `カウント（useState）` の表示が更新される
- `カウントアップ（useRef）` ボタンを押下時、 `カウント（useRef）` の表示は更新されない

```.tsx
import * as React from 'react';

const App: React.FC = () => {
  const [count, setCount] = React.useState(0);
  const countRef = React.useRef(0);

  return (
    <div>
      <div>カウント（useState）: {count}</div>
      <button onClick={() => setCount(count + 1)}>カウントアップ（useState）</button>

      <div>カウント（useRef）: {countRef.current}</div>
      <button onClick={() => countRef.current++}>カウントアップ（useRef）</button>
    </div>
  );
};

export default App;
```

# ふまえて
`useState` と `useRef` を適切に使い分け、無駄なレンダリングを防ぐことが重要である
macOS Montereyにアップデートしたら『command not found: php』

つい先日macOS Montereyにアップデートしました。

その後、作業をするためにphpを立ち上げようとしたらところ、

command not found: php

でエラーに、、、。

なにが原因なのかと調べたところ、

https://jp.quora.com/%E3%82%BF%E3%83%BC%E3%83%9F%E3%83%8A%E3%83%AB%E3%81%A7php%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B%E3%81%A8php%E3%81%AF%E6%8E%A8%E5%A5%A8%E3%81%97%E3%81%AA%E3%81%84-%E5%B0%86

どうやら今回のMonteryでｐｈｐが同梱されず追加パッケージ扱いになるようです。

なので、brewでインストールしたところ、問題なく動きました。
Swift CollectionView周りのライフサイクル

4種類存在する
(1) prepareForReuse
非表示となって必要なくなったセルが再利用される場合、prepareForReuseが発火。
(2) cellForItemAtIndexPath
セルの生成を行うサイクル。Datasourceをデリーゲートすると制約として出てくるのでよく使うもの。
(3) willDisplayCell
セルを表示しようとする直前発火する。 セル表示の直前で必要な作業があれば、ここで行うことができます。
(4) didEndDisplayingCell
セルが表示領域外で出てきたら呼ばれるようになる。

実際にプリントしてみた。。再利用の時はしっかり
再利用される時⇨prepareforreuse
セル表示の直前⇨willDisplayCell
セル生成⇨cellforitemat
セル領域外⇨didEndDisplaying
が呼ばれていた。

```swift


import UIKit

class ViewController: UIViewController {
    
    private lazy var cv: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        let frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
        layout.minimumLineSpacing = 50
        layout.itemSize = CGSize(width: view.frame.width - 20, height: 50)
        let cv = UICollectionView(frame: frame, collectionViewLayout: layout)
        cv.delegate = self
        cv.dataSource = self
        cv.prefetchDataSource = self
        cv.register(CollectionCell.self, forCellWithReuseIdentifier: "cell")
        cv.backgroundColor = .blue
        return cv
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        // Do any additional setup after loading the view.
        
        view.addSubview(cv)
    }


}
extension ViewController:UICollectionViewDelegate,UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        print(#function)
    }
    func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        print(#function)
    }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 20
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        print(#function)
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionCell
        return cell
    }
}
extension ViewController: UICollectionViewDataSourcePrefetching {
    func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) {
        print(#function)
    }
    func collectionView(_ collectionView: UICollectionView, cancelPrefetchingForItemsAt indexPaths: [IndexPath]) {
        print(#function)
    }
}



//collectioncell.swift
import Foundation
import UIKit
class CollectionCell:UICollectionViewCell {
    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .orange
    }
    required init?(coder: NSCoder) {
        fatalError()
    }
    override func prepareForReuse() {
        print(#function)
    }
}
```
また、prefetchDatasourceなるものがcollectionViewには存在していて、メインスレッド以外で,cellforitematより早く発火するようになっている。
負荷のおもい画像データfetchする時などはPrefetchDatasourceで表示が遅いなどに対応できる。使ったことがないので試してみたい。
【GAS】図形を実行ボタン化してスクリプトを実行する

#はじめに
GASを使うことで、単純作業を効率化できることが感じられてきましたが、毎回スクリプトエディタを開いて関数を実行することが煩わしく感じてきました。それに、自分以外が使用する際に「スプレッドシートのツールからスクリプトエディタを開いて・・・」と説明するのは大変です。

スプレッドシートは、GASで作成した関数と図形オブジェクトを関連付けることが可能なので、実行したい関数を指定すればワンクリックで実行することができます。

#1.図形オブジェクトを作成
まず、実行ボタンとなる図形オブジェクトを作成します。
左上のメニューバーから「挿入→図形描画」の順でクリックします。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1114592/c41b5272-02d0-19fd-a6a7-20d64d4c9771.png)
 
すると、図形描画の画面が表示されるので、ボタンとなる図形を選択し、自由に大きさ形を設定します。
![スクリーンショット 2021-10-27 23.19.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1114592/9f5719f4-01db-719e-b55c-5fc3442027e4.png)
![スクリーンショット 2021-10-27 23.21.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1114592/985cb98c-5f14-200d-a385-26d24ca2263e.png)

ボタン上にどんな用途のボタンか分かるようにテキストを設定します。「図形を右クリック→テキストの編集」から任意のテキストを入力します。
![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1114592/8bb1316b-f14b-95ee-c501-ce6e993d4d48.png)

完成したら右上の「保存して終了」をクリックして、図形オブジェクトをスプレッドシート上に保存します。
![図3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1114592/f771d0f6-c632-72ec-5af5-5a9b26268b73.png)

#2.図形オブジェクトと関数を関連づける
作成した図形オブジェクトに対してGASの関数を関連づけることで、オブジェクトがクリックされると関数が実行されます。
図形の右上にある３点から「スクリプトを割り当て」をクリックします。
![図4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1114592/606c1323-fa0c-4859-c13e-07ea99825c34.png)
すると、関数名を入力するフォームが現れるので実行したい関数を入力します。
![スクリーンショット 2021-10-27 23.26.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1114592/05d16ba2-e5ed-5b4a-099c-a1c2252725a8.png)

以上で、オブジェクトと関数が紐づけられます。

#3.実行確認
現在、開発中のカレンダーから予定をある程度フォーマットして出力する関数をオブジェクトに紐づけて実行します。
すると、カレンダーの予定がA2のセルに入力されました。
![スクリーンショット 2021-10-27 23.27.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1114592/a28e908e-e9e0-499d-7e99-f7fbb70c8356.png)

#まとめ
今までスクリプトエディタを開いて関数を選択し、実行するしかできませんでしたが、スプレッドシート上のオブジェクトから実行することができることで、自分以外でも使いやすいものになりました。便利な機能と合わせて、誰でも使いやすいものになれば、より需要は高まりそうです。
javascriptでクリップボードにコピー2021年版

# 概要
クリップボードにコピーではまりました。
ブログ記事に紹介された方法が古くなってたりしたので、ひとまず整理しとこうかと書きました。

# 変更履歴
2021-11-12 一部のスマホアプリ内ブラウザで動かなかったので対応しました

# 結論

```javascript
    /**
     * クリップボードにコピー
     * @param string value コピーする文字列
     */
    function copyToClipboard(value) {

        // モダンブラウザ
        if (typeof navigator.clipboard === 'object') {
            navigator.clipboard.writeText(value).then(function() {
                // 成功
                console.log('clipboard.writeText OK');
            }, function() {
                // 失敗（アプリ内蔵ブラウザの一部はここを通る）
                let result = copyToClipboard2(value);
                console.log('writeText NG, copy ' + ((result !== false) ? 'OK' : 'NG'));
            });
            return;
        }

        // IE
        if (typeof window.clipboardData === 'object') {
            window.clipboardData.setData('Text', value);
            // 結果の確認方法は不明
            console.log('clipboardData.setData DONE');
            return;
        }

        // 旧来の汎用的なやり方（？）
        let result = copyToClipboard2(value);
        console.log('copy ' + ((result !== false) ? 'OK' : 'NG'));
    }

    /**
     * クリップボードにコピーを、body末尾にdomを追加する方法で行う
     * @param string value コピーする文字列
     * @return 失敗した場合はfalse
     */
    function copyToClipboard2(value) {
        // 旧来の汎用的なやり方（？）
        const CLASS_NAME = 'temp_class_name_for_clipboard_copy';
        const SELECTOR = 'input.' + CLASS_NAME;
        $('body').append($('<input type="text" class="' + CLASS_NAME + '" value="' + value + '" />'));
        dom = $(SELECTOR)[0]
        dom.select()
        let result = document.execCommand("copy");
        $(SELECTOR).remove();

        return result;
    }
```

# 説明
1. 主要ブラウザの最新版を使っていれば、 `navigator.clipboard.writeText()` でいけます。
    1. 2019年頃はまだブラウザに採用されてなかったみたいですが、今回はほぼこれ1個で行ける結果になりました。
2. 対応することでモチベーションが削られるIEに関しては、専用の機能を使います。
    2. 一次資料見つかりませんでした。さすがIE。
2. それらが使えなかったとき用の保険で、旧来からある「ダミーつくってコピー」をつけました。
    2. ただし execCommand は 今はDeprecatedになってます。
    2. 今回これが動くケースはなかったので
        2. 見えない位置にとかスマホのときに諸々といった細かいことは省きました。
        2. 保険でちょっとマシになればいいなー程度です。
        2. サンプルとしてはjquery非依存のほうがいいんですけどそれも省きました。
4. [2021-11-02追記] 一部のスマホアプリ内ブラウザのためのコードを追記しました。AndroidのLINEほかいくつかです。
    4.  `typeof navigator.clipboard === 'object'` かつ `typeof navigator.clipboard.writeText === 'function'` のくせに、実行すると必ず失敗します。なんなんよ :sob:
    4.  仕方ないので、失敗時に「旧来からある汎用的なやり方」を付け足しました。




# 参考
1. [Navigator.clipboard - MDN Web Docs](https://developer.mozilla.org/ja/docs/Web/API/Navigator/clipboard)
1. [Clipboard.writeText() - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText)
1. [Document.execCommand() - MDN Web Docs](https://developer.mozilla.org/ja/docs/Web/API/Document/execCommand)
1. [クリップボードとのやりとり - MDN Web Docs](https://developer.mozilla.org/ja/docs/Mozilla/Add-ons/WebExtensions/Interact_with_the_clipboard)
1. [[JavaScript]クリップボードを使ったコピーとペースト - qiita](https://qiita.com/butakoma/items/642c0ec4b77f6bb5ebcf)
TerraformでAWSのIAMユーザー作成

# はじめ

AWSコンソールから簡単にIAMユーザー作成できますが、IaC精神でコード管理したい気持ちがありますね。そのとき、どうすれば良いのか紹介したいと思います。

# gpgのペア鍵を生成する方法

```
gpg --full-generate-key
```
選択順番

```
1回目
(1) RSA and RSA (default)

2回目
4096

3回目
0 = key does not expire

その後
Real name
では本名を入れます。

Email address
では自分のメールアドレスを入れました。

Comment
ではなにも入力せずEnterを押しました。

Passphrase: 
では好き文字列入力
```

ファイルにgpg鍵を出力します

```
gpg -o {任意のファイル名}.public.gpg  --export 入力した本名
gpg -o {任意のファイル名}.private.gpg --export-secret-key　入力した本名
↑このときにパスフレーズを求められます
```

最後にgpg鍵をbase64でエンコードしないといけない

```
cat {作成した鍵のファイル名}.public.gpg | base64 | tr -d '\n' > {任意のファイル名}.public.gpg.base64
```
この鍵をpgp_keyとして次のステップで利用してください。

# TerraformでIAMユーザー作成

簡単にこんな感じ

```
resource "aws_iam_user" "iam_user" {
  name          = "iam_user_name"
  force_destroy = true
}

resource "aws_iam_access_key" "iam_user_access_key" {
  user    = aws_iam_user.iam_user.name
  pgp_key = "pgp key data" # 事前にファイル読み込みがベスト
}

resource "aws_iam_user_login_profile" "iam_user_profile" {
  user    = aws_iam_user.iam_user.name
  pgp_key = "pgp key data"
}

resource "aws_iam_user_policy_attachment" "iam_user_policy_attach" {
  user       = aws_iam_user.iam_user.name
  policy_arn = "policy arn" # 事前にポリシー作成が必要
}
```

# クレデンシャル確認
AWSコンソールから秘密キーを見れないので、またTerraformを使います。

## 事前準備

```
brew install gpg pinentry-mac
```

.zshrcなどに下記を記述

```
GPG_TTY=$(tty)
export GPG_TTY
```

```
source ~/.zshrc
```
などして再読み込み

## 復号化された秘密キー取得

```
terraform show
```
で確認できます。暗号化された秘密キーを一旦Macに保存します。

```
cat encrypted_secret.txt | base64 -D | gpg --decrypt | cat > secret.txt
```

Inappropriate ioctl for deviceというエラーが出た場合は事前準備に書いてある.zshrcを記載してsourceで再読み込みしてみてください。

これでシークレットアクセスキーの確認ができました。アクセスキーはAWSコンソールから確認できます。
最近、エキサイトでは脱レガシー運動が盛り上がっています。