OmniAICreator/Qiita-1.07M huggingface dataset:
Ubuntu に Ruby をインストールする（個人メモ）

自作ツール動作環境作成の解説のために、Rubyの動作環境の作成手順が必要なので、個別で作成しました。

# 事前の環境作成

LXD環境で行うことを想定しています。


## コンテナの作成
~~~
LXCNAME=rb01
lxc launch ubuntu:22.04 $LXCNAME
lxc exec $LXCNAME -- sh -c "apt update && apt full-upgrade -y && apt autoremove -y"
lxc exec $LXCNAME -- sh -c "reboot"
~~~



## 前準備

rootユーザーでログイン。
~~~
lxc exec rb01 -- /bin/bash
~~~

Ruby のビルドに必要なパッケージを apt 経由でインストールします。
~~~
apt install build-essential
apt install libssl-dev libreadline-dev zlib1g-dev
apt install libpq-dev
~~~


# Rubyをインストール

rbenv を使用します。

https://github.com/rbenv/rbenv

ubuntu ユーザーでログイン。
~~~
lxc exec rb01 -- /bin/su - ubuntu
~~~

## rbenvのインストール

rbenvのインストールと初期設定を行います。
~~~
# rbenvをインストール
git clone https://github.com/rbenv/rbenv.git ~/.rbenv

# 環境変数の設定
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc

# シェルを再起動（もしくは再ログイン）
exec $SHELL -l

# ruby-buildをインストール
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
~~~

## 必要なRubyをインストール

インストール可能なバージョン一覧を表示
~~~
rbenv install -l
~~~

Rubyをインストール（その時の最新を選択で問題ないと思います）
~~~
rbenv install 3.1.2
rbenv global 3.1.2
~~~

以上でRubyが使用できるようになっているはずです。
~~~
$ ruby -v
ruby 3.1.2
~~~




# 参考URL

https://www.ruby-lang.org/ja/

https://qiita.com/kaishuu0123/items/2a91495e7daa8c7783ed
メール２重送信回避

備忘録です。
OctoberCMS 3.2.7
メール設定をイベントログにしても２重にログされるので、どうしようもない。

```php
function onStart(){

Mail::rawTo('address@domain', 'Hello friend');
return Redirect::to("/");
}
```
どうやら、どこかにリダイレクトしないと、メールが２度送信される模様です。
if文でmodifierを呼び分けてはいけない

# 概要
https://developer.apple.com/videos/play/wwdc2021/10022/

を視聴していたら，36:31ぐらいからちょうどタイトルと同じような内容が紹介されていた。パッと理解することができなかったので，まとめてみます。

# 実例

以下の例を見てみる。

```swift
import SwiftUI

struct ContentView: View {
    @State private var isOpacity: Bool = false

    var body: some View {
        VStack {
            if isOpacity {
                ChildView()
                    .opacity(0.3)
            } else {
                ChildView()
            }
            Button("Change Opacity") {
                isOpacity.toggle()
            }
        }
    }
}

struct ChildView: View {
    @State private var isGood: Bool = false

    var body: some View {
        VStack {
            Text(isGood ? "Good" : "Bad")
            Button("Change Goodness") {
                isGood.toggle()
            }
        }
    }
}
```

`ContentView`ではopacityを変化させる`isOpacity`を管理しており，`ChildView`では文言`"Good"/"Bad"`を変化させる`isGood`を管理している。`ContentView`では，opacityを変化させるためにif文を使用している。一見問題なさそうに見えるが，挙動を確かめてみる。

![Untitled.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628850/b375528d-9f14-8aab-5409-f931c9c82a7e.gif)


挙動が以下のようになっている。

1. "Change Goodness"ボタンを押して，テキストを"Bad"から"Good"に変更した
1. "Change Opacity"ボタンを押して，opacityを0.3に変更した
1. 2でopacityのみ変更したが，テキストも"Good"から"Bad"に変更されている

# 原因

https://swiftwithmajid.com/2021/12/09/structural-identity-in-swiftui/

が非常に参考になった。

> SwiftUI destroys and creates the views whenever the condition changes. This process deallocates the destroyed view’s state and uses animation to remove the destroyed view.

より，`ContentView`の`isOpacity`が変わった時，`ChildView`が再生成され`isGood`がデフォルトのfalseとなり，opacityだけではなく，文言も"Good"から"Bad"に変わってしまった。

# 解決方法

```swift
struct ContentView: View {
    @State private var isOpacity: Bool = false
    var body: some View {
        VStack {
            ChildView()
                .opacity(isOpacity ? 0.3 : 1)
            Button("Change Opacity") {
                isOpacity.toggle()
            }
        }
    }
}
```

上記のように，`opacity`で指定する値自体を`isOpacity`で出し分ければ良い。

> There is no changes in the view tree when you set the padding to 0 or opacity to 1. SwiftUI understands that and doesn’t apply these view modifiers. That’s why we call them inert view modifiers. Try to use them as much as possible to improve the performance of your view and remove unwanted transitions.

とあるように，`opacity`で1を指定してもmodifierが適用されないそう。ちなみに inert = 不活性 だそう。
MVCゼミ ワーク

# ワークの下準備
**ターミナルでアプリ作成** 
```ruby:ターミナル(コマンドプロンプト)
cd Desktop

rails _6.1.5_ new mvc

cd mvc

code .

rails db:create

# コントローラーを作成してみよう！！

rails g model Post body:string

rails db:migrate

```

**seedを編集しよう！**
```ruby:db/seeds.rb
Post.create([
  { body: 'Web' },
  { body: 'コース' },
  { body: 'LOVE' }
])
```

https://qiita.com/takehanKosuke/items/79a66751fe95010ea5ee

**ターミナルで適応**
```ruby:ターミナル(コマンドプロンプト)
rails db:seed
```

# MVCを構築していこう！
**Controllerにindexアクションを定義してみよう！**
```ruby:app/controllers/posts_controller.rb
class PostsController < ApplicationController
  #追加する箇所
 

  #ここまで
end
```

**Viewに@postsを表示してみよう！**
```ruby:app/views/posts/○○○.html.erb
<h1>MVCゼミ</h1>
<h3>MVC一覧</h3>
<div class="MVC-container">
  <% @posts.each do |t| %>

  #追加する箇所
 

  #ここまで

  <% end %>
</div>
```

**Routesにposts/index のURLが送られたら routes.rb で posts_controller.rb の index が実行**
```ruby:config/routes.rb
Rails.application.routes.draw do
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html

  #追加する箇所
 

  #ここまで

end
```

# つまずいた人は以下をクリック！


<details><summary>つまずいた人向け</summary>



**Controllerにindexアクションを定義してみよう！**
```ruby:app/controllers/posts_controller.rb
class PostsController < ApplicationController
  #追加する箇所

  #ヒント
 　def index
    @posts = ○○○.○○○
   end

  #ここまで
end
```

**Viewに@postsを表示してみよう！**
```ruby:app/views/posts/○○○.html.erb
<h1>MVCゼミ</h1>
<h3>MVC一覧</h3>
<div class="MVC-container">
  <% @posts.each do |t| %>

  #追加する箇所
 
  #ヒント：<%= t.○○○ %>

  #ここまで

  <% end %>
</div>
```

**Routesにposts/index のURLが送られたら routes.rb で posts_controller.rb の index が実行**
```ruby:config/routes.rb
Rails.application.routes.draw do
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html

  #追加する箇所

  #ヒント：get '○○○/○○○' => '○○○#○○○'

  #ここまで

end
```

</details>
[Java]依存性の注入(Dependency Injection)の理解が曖昧な方への説明

### はじめに
この記事は依存性の注入の概念に集中するため、
なぜ依存性の注入を使うのかメリットは何かは詳しく説明しないです。

### 依存性の注入(Dependency Injection)とは？
#### 定義
依存性の注入(Dependency Injection)、もしくは依存性注入、依存注入、DIと呼ばれています。
[Wikipedia](https://ja.wikipedia.org/wiki/%E4%BE%9D%E5%AD%98%E6%80%A7%E3%81%AE%E6%B3%A8%E5%85%A5)により、依存性の注入とはあるオブジェクトや関数が、
依存する他のオブジェクトや関数を受け取るデザインパターンであると書いてありますが、
なかなか理解しづらいですね、、、
#### 具体的な例
それでは現実の物を使って理解しましょう。
例えば、車はエンジンがないと動けないので、この時に車はエンジンに依存すると言えるでしょう。
(エンジンは車の依存)
こういう関係は依存性と言います。これだけです。

### 依存性の注入を使わない場合
車(Car)とエンジン(Engine)をJavaのコードで見てみましょう。
```java
class Car {
    private Engine engine;

    public Car(){
        engine = new Engine();
    }

    public void run(){
        engine.start();
    }
}
```
Carクラスの中では直接Engineクラスをインスタンス化するため、
もしエンジンの種類を変更したい場合は、Carクラスの作成時にすでにエンジンの種類を指定しているため、変更することが面倒くさいです。

例えば、車作った時に内部は既にディーゼルエンジンを装置したのに、
それ以降ガソリンエンジンに変更したかったら、どう考えてもやりたくないですねw

### 依存性の注入を使う場合
同じ車(Car)とエンジン(Engine)の例をJavaのコードで見てみましょう。
```java
class Car {
    private Engine engine;

    public Car(Engine engine){
        this.engine = engine;
    }

    public void run(){
        engine.start();
    }
}
```
この書き方でEngineオブジェクトは外部から注入することが可能となり、
クラス間の依存関係が単純化されるだけでなく、Carクラスのテストもしやすくなります。

例えば、車作ってからエンジンの種類を決めると、その時にどんなエンジンでも自由に選べるでしょう。
つまり、車自体はエンジンに依存しなくなりました！！

### じゃあ依存性の注入の注入とは？
依存性の注入の注入は以下のコードで見ましょう！
```java
Engine engine = new Engine(); // ここでインスタンス化したengineを
Car car = new Car(engine); // Car()の中にCar(engine)←こう注入する！
car.run();
```
この方法はコンストラクター(constructor)注入と呼ばれ、依存性注入の一般的な実装です。
これにより、インスタンス(Car)が作成されるときに依存性(Engine)が正しく注入されることを保証できます。

他にはセッター(setter)注入とフィールド(field)注入という方法もあります。
```java
// セッター(setter)注入
Engine engine = new Engine();
Car car = new Car();
car.setEngine(engine);
car.run();
```
```java
// フィールド(field)注入
Engine engine = new Engine();
Car car = new Car();
car.engine = engine;
car.run();
```
セッター注入とフィールド注入はインスタンス化してから依存性を注入するため、
実行時に依存関係が注入されない可能性があります。
したがって、実務では依存性が正しく注入されるため、コンストラクタ注入を多く使ってます。

### 終わりに
Spring Bootの ```@Autowired```を使えば、
```java 
Engine engine = new Engine();
```
すら書かなくていいです！(自動的に生成してくれるので)

最後、
この記事はとにかく現実の例で依存性の注入をわかりやすく伝えたいだけです！
structの配列をuserdefaultで保存・読み込みしてTableViewに表示する（デモ有り）

### 1. Structを定義するためのファイルを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/e86f7ef9-c09d-2051-dffe-2b3bbe59a91a.png)
どこでも良いので右クリック→`New File...`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/c7009e56-7f84-5cac-59c5-0120293fe09c.png)
`Swift File`→`Next`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540178/1098c4bf-18e9-b644-a0f9-4505797e3d86.png)
好きな名前を設定→`Create`

```swift
import Foundation

struct Movie: Codable {
    var title: String
    var description: String
    var thumbnail: Data
}
```
構造体を定義します

```swift
func saveMovies(movies: [Movie], forKey: String) {
    let jsonEncoder = JSONEncoder()
    guard let data = try? jsonEncoder.encode(movies) else {
        return
    }
    UserDefaults.standard.set(data, forKey: forKey)
}
```
```swift
func loadMoies(forKey: String) -> [Movie]? {
    let jsonDecoder = JSONDecoder()
    guard let data = UserDefaults.standard.data(forKey: forKey),
          let movies = try? jsonDecoder.decode([Movie].self, from: data) else {
        return nil
    }
        
    return movies
}
```
構造体を保存、読み込みするメソッド

## デモアプリはこちら

https://github.com/sugijotaro/struct-save-userdefaults-demo

## 参考

https://www.hfoasi8fje3.work/entry/2021/04/06/%E3%80%90Swift%E3%80%91%E6%A7%8B%E9%80%A0%E4%BD%93%E3%81%AE%E9%85%8D%E5%88%97%E3%82%92UserDefaults%E3%81%A7%E4%BF%9D%E5%AD%98/%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B
麻雀で学ぶTypeScript 5 チー

前回：[麻雀で学ぶTypeScript 4 ポン](https://qiita.com/bonetaro/items/9edcb82c2e1827bec666)
ソースコード：https://github.com/bonetaro/mahjong-ts

今回はチーを実装しました。
![スクリーンショット 2023-01-21 213018.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4989/55866a84-8ea0-01d0-4ff1-491aef58e714.png)

チーは、上家からしかできない、チーする塔子（ターツ）候補が複数の可能性がある（ポン、カンの場合は一種類）など、ポンやカンよりいろいろとやっかいです。その分、いままでの実装では足りない箇所が多くありました。

ポンやカンができるかどうかは、ツモ番のプレイヤーが捨てた牌と同じ牌がポンは2枚、カンは3枚手牌にあるかで判定できますが、チーの場合は、プレイヤーが捨てた牌と同じ色の数牌でかつ、順子が構成可能な塔子（ターツ）があるかを判定する必要があります。現状はこれをそのまま実装していますが、文章でいうよりも実装は面倒（塔子候補の列挙など）な上に、これではTypeScriptらしい？実装ではないのではないかというか、そもそもTypeScriptの型を活かした実装とは何か？に悩んでおります。

```typescript
export type 萬子 = "m"; // 英語はCharacters
export type 筒子 = "p"; // 英語はWheels
export type 索子 = "s"; // 英語はBamboos
export type 風 = "w"; // Wind
export type 元 = "d"; // Dragon

export type 数牌の数 = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
export type 数牌の色 = 萬子 | 筒子 | 索子;

export type 萬子牌 = `${数牌の数}${萬子}`;
export type 筒子牌 = `${数牌の数}${筒子}`;
export type 索子牌 = `${数牌の数}${索子}`;

export type 数牌 = 萬子牌 | 筒子牌 | 索子牌; // Suits

export type 東 = `e${風}`; // EastWind
export type 南 = `s${風}`; // SouthWind
export type 西 = `w${風}`; // WestWind
export type 北 = `n${風}`; // NorthWind

export type 白 = `w${元}`; // WhiteDragon
export type 發 = `g${元}`; // GreenDragon
export type 中 = `r${元}`; // RedDragon

export type 四風牌 = 東 | 南 | 西 | 北; // Winds
export type 三元牌 = 白 | 發 | 中; // Dragons
export type 字牌 = 四風牌 | 三元牌; // Honours

export type 牌 = 数牌 | 字牌;

export type 対子like = [牌, 牌];
export type 刻子like = [牌, 牌, 牌];
export type 槓子like = [牌, 牌, 牌, 牌];

export type 塔子like = [数牌, 数牌];
export type 順子like = [数牌, 数牌, 数牌];

export type 雀頭like = 対子like;
export type 面子like = 順子like | 刻子like | 槓子like;
```

上記は、麻雀に出てくる用語をTypeScriptのTypeとして独自定義しています。前半は麻雀をそのまま定義している（はず）ので違和感ない（字牌のstringのチョイスは微妙かもですし、そもそも型の宣言に漢字をつかっているのが気持ち悪いというのはご勘弁ください）と思いますが、課題なのは「対子like」以降です。

「対子」は、本来同じ牌（実体）の2つの組み合わせであり、「対子like」のような「牌」という型（= 数牌 | 字牌）としての34種類あるうちの2つの組み合わせとは違います。

```typescript
export type 対子 = ["1m", "1m"] | ["2m", "2m"] | ["3m", "3m"] | ... | ["gd", "gd"] | ["rd", "rd"];
export type 順子<C extends 数牌の色> =
  | [`1${C}`, `2${C}`, `3${C}`]
  | [`2${C}`, `3${C}`, `4${C}`]
  | [`3${C}`, `4${C}`, `5${C}`]
  | [`4${C}`, `5${C}`, `6${C}`]
  | [`5${C}`, `6${C}`, `7${C}`]
  | [`6${C}`, `7${C}`, `8${C}`]
  | [`7${C}`, `8${C}`, `9${C}`];
```

上記のように、全部列挙すればいいといえばいいのですが、仕事ではそれでいいとしても:-P、趣味としてはそうはいきませんw。TypeScriptで何ができるか、どう使うべきか、を試行錯誤することが学びであり、壁をのりこえようとすることが成長であるはずですよね。

今はまだ分からないことが多いですので、もう少しTypeScriptのお勉強をつづけて次回に一旦の落としどころを出したいと思います。
[Blender]ジオメトリノードをちょっと試してみたい！という方用の記事

# 概要
ジオメトリノードを初めて触る方向けの記事です。
この記事の手順を応用すればたくさんの木を並べたり草を生やしたりするのに使えそうですね。
# 本文
（画面左下のボタンから）Geometry Node Editorを選択してエディタ画面を表示して
![スクリーンショット 2023-01-22 0.12.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/8932df8e-793a-1040-5e81-9ec0e59d2fc2.png)
Newを押してジオメトリノードを新規作成します。
![スクリーンショット 2023-01-22 0.16.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/11a9060c-767f-d408-6927-64f98487f009.png)
初期状態でノードが二つ表示されます。繋いでいる線は切っておきます。
左側のGroup Inputは今回使いません。
![スクリーンショット 2023-01-22 0.16.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/42df1980-b006-e571-3fc5-b448d4da36e6.png)
ノードを2つ追加します。一つ目は「Instance on Points」
![スクリーンショット 2023-01-22 0.18.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/5a5bbe17-0956-37d4-ebd0-eea100c6082d.png)
二つ目は「Mesh Circle」
![スクリーンショット 2023-01-22 0.19.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/4c475565-186a-3413-a6d4-365b8bc820af.png)
ノードを以下スクショのように繋いだ後、おもむろにオブジェクト（今回はスザンヌ）をドラッグ&ドロップすると「Object Info」というノードが作成されます。
「Instance on Points」の「Instance」に繋ぐとオブジェクトが円形に配置されます。（MeshCircleノードのVerticesとRadiusを変更する事で並び方を調整できます。）
![スクリーンショット 2023-01-22 0.27.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/ce28be47-5721-18e9-c528-1e34f07419ca.png)
生のPHPでフリマサービスを作る_part1

## フリマサービス作成の流れ

1\.機能を洗い出す
2\.画面設計（今回はPHPの深掘りがメインなので割愛します）
3\.テーブル設計
4\.クラス設計
5\.実装


### 機能を洗い出す
**今回の作るフリマサービスの機能は以下の通り**
- ユーザー登録
- ログイン
- ログアウト
- 退会
- プロフィール登録
- プロフィール編集
- パスワード変更
- パスワードリマインダー
- 決済（余裕があれば）
- コンテンツ登録
- コンテンツ編集
- コンテンツ削除
- コンテンツ一覧表示
- コンテンツ詳細表示
- コンテンツ検索
- コンテンツ毎の掲示板表示
- コンテンツ毎の掲示板へのメッセージ登録
- お気に入り登録


### テーブル設計
以下のように設計する
![スクリーンショット 2023-01-22 0.31.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461162/6f8d7e0d-29f0-93a3-5b42-bef4fa9ac15c.png)


### クラス設計
次回へ
changetypeディレクティブについて

●changetypeディレクティブ
LDIFファイルを利用してエントリの追加、削除および変更を行う。

書式

dn: 対象エントリの識別名
changetype: 変更種別
変更内容
･･･

変更種別
・add エントリの追加
・delete エントリの削除
・modify エントリ情報の変更(属性の追加、削除、変更など)
・modrdn RDN(相対識別名)の変更
フォームで入力した画像をスプレッドシートのセル内に埋め込みたい

# やりたいこと

フォームで入力した画像を・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3100878/7a66e059-8800-0fae-9f29-56fd1fff9e4d.png)

スプレッドシートのセル内に埋め込みたい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3100878/6a0a10b1-efc2-73ef-edc6-0b5c1f269e04.png)

# 前提として

## フォームに画像を入力するとどうなる？
フォームで画像を入力した場合、画像はフォーム作成者のGoogleドライブに保存される。
フォームの回答はスプレッドシートに保存されるが、画像の場合はこのドライブに保存した画像のURLが入る。
![スクリーンショット 2023-01-21 233124.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3100878/426ce191-e6ef-e33c-6ce0-96fc79e129ec.png)

# GASを使ったやり方

以下の手順で実現する。
①回答のあるスプレッドシートから画像URLを取得する
②画像URLから画像IDを取得する
③画像IDから画像のBLOBデータを取得する
④BLOBデータから[CellImageオブジェクト](https://developers.google.com/apps-script/reference/spreadsheet/cell-image)を生成する。
⑤画像を表示したセルに、CellImageオブジェクトを値として設定（setValue）する。

②~④を関数にしたものが以下です。
```javascript:手順②~④まで
/**
 * ドライブ内の画像をセルに挿入できる形式に変換する
 * imageUrl: Googleドライブ内の画像URL
 */
function getCellImagefromUrl(imageUrl) {

  // ②URLからIDを取得
  const imageId = imageUrl.substring(imageUrl.indexOf("id=")+3);

  // ③画像IDから画像のBLOBデータを取得する
  var blob = DriveApp.getFileById(imageId).getBlob();
 
  // BLOBデータをbase64でエンコード
  var c_type = blob.getContentType();
  var base64 = Utilities.base64Encode(blob.getBytes());
  var data = "data:" + c_type + ";base64, " + base64;

  // ④BLOBデータからCellImageオブジェクトを生成する
  var image = SpreadsheetApp.newCellImage()
                            .setSourceUrl(data)
                            .build();

  return image
}
```

# スプレッドシート上でのやり方

①対象セルを選択した状態で
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3100878/78de0e60-59c7-8d8d-bcd0-913eb2cd25a5.png)

②ヘッダーの「挿入」＞「画像」＞「セル内に画像を挿入」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3100878/a925e5ae-95b5-a82e-4c26-dab60be7c766.png)

③あとは画像を選択するだけ！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3100878/f511d7ac-2873-f144-77e5-364da10db548.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3100878/bf1e33fc-4570-ed8b-ebc5-5ff47c98d695.png)
【Linux】検索したファイルに対してコマンドを実行する方法

## `exec`オプション
`find`コマンドの`exec`オプションを使用することで取得したパスに対してコマンドを実行できます。

以下のように記述すると取得したパス一つ一つに対してコマンドが実行されます。

```zsh
find . -name "*.txt" -exec rm {} \;
```
実際に実行されるコマンドは以下のようになります。

```zsh
$ rm "./sample1.txt"
$ rm "./sample2.txt"
$ rm "./sample3.txt" 
$ rm "./sample4.txt"
$ rm "./sample5.txt"
```

以下のようにすると取得したパスを並べた状態で引数として実行します。

```zsh
find . -name "*.txt" -exec rm {} +
```
実際に実行されるコマンドは以下のようになります。
```zsh
$ rm "./sample1.txt" "./sample2.txt" "./sample3.txt" "./sample4.txt" "./sample5.txt"
```

## `xargs`コマンド
また`xargs`コマンドを使用することで取得したパスに対してコマンドを実行できます。

```
find . -name "*.txt" | xargs rm
```

上記のように記述すると以下のように`rm`が実行されます。

```zsh
$ rm "./sample1.txt" "./sample2.txt" "./sample3.txt" "./sample4.txt" "./sample5.txt"
```

取得したファイルパス一つ一つに対して実行したい場合には以下のようにします。

```
find . -name "*.txt" | xargs -L 1 rm
```
```zsh
$ rm "./sample1.txt"
$ rm "./sample2.txt"
$ rm "./sample3.txt" 
$ rm "./sample4.txt"
$ rm "./sample5.txt"
```
SESに転職してからの心境の変化【エンジニア2年目】

こんにちは。Webエンジニアの吉田です。

今回社会人2年目のエンジニアがSlerからSESに転職するまでに感じたこと、現場で働いてからの心境の変化を書かせていただきました。
SES業界自体ネガティブなイメージを持つ人が多いため、読んでくださった方が少しでも明るい印象を持っていただけたら嬉しいです！
## 1.転職の背景

私は大学卒業後に中小SIer企業に就職し、主に業務システム開発に携わり、詳細設計から結合試験まで多くの経験をさせていただきました。
しかし2年目からは顧客との調整、運用・保守の仕事が増えていき、徐々にプログラミングをする機会が減っていきました。
まずはコーディング技術をしっかり身につけ、その上で設計やプロジェクト管理を行いたいと思いSESへの転職を決意しました。

## 2.入社までの不安だった日々

社会人2年目の夏に転職したこともあり、「現場で活躍できるかな」「SESと検索するとネガティブな記事ばかりで不安だな」と感じていました。

SESで検索すると **「現場での人間関係が上手くいかない」「スキルが身につかない」** 等のネガティブな記事が多く見られます。
もちろん現場にもよりますが、私が参画した現場では**自社の社員のように親切丁寧**に教えてくださり、チーム内のコミュニケーションが良好な環境でした。

そして今までのスキルを活かし現在では以下の業務を行なっています。

- 新規画面の製造（言語：Java）
- 試験仕様書作成
- 単体、結合試験

プロジェクトを進めていく中で自身の技術力を向上させ、現場の方々と信頼関係を築き、**難易度の高い製造**を任せられる時にとてもやりがいを感じます。

また入社直後は現場での立ち回り方や、コーディング等でわからないことも多くありましたが、上司からアドバイスいただいたり、自社の勉強会で先輩方から技術力を学ぶことができ、自信をもって業務に取り組むことができました。

## 3.私が感じたSESのメリット

### ・幅広いスキルを習得できる

Sler、自社開発では携わるプロジェクトのジャンルが限られることもあります。
ですがSESは現場によって言語や、業界が異なるため様々な技術に触れられ、幅広くスキルを身に付けることができます。
**「自身が経験したい技術」「得意分野」** を現場で自身のスキルを最大限に活かしながら、働くことができるのがメリットだと思います。

### ・大きな案件に携われることができる

本人のスキルによっては**元請けの有名企業のシステム開発**に携われる機会もあります。
また設計工程等の上流工程を任せられる場合もあり、さらなるスキルアップも期待できます。また多くの優秀なエンジニアと交流ができる機会が増えエンジニアとして大きく成長できる可能性が増えます。

### ・ワークライフバランスを重視できる

SESは労働時間について事前に定めた雇用契約を結んでいるため、**長時間労働が少ない環境**です。
メリハリがつくことで仕事にも身が入り、高いパフォーマンスを発揮することができています。

## **3.SESとして働く上で大切なこと**

これは全てのエンジニア全員に通ずることですが、**当事者意識を持って働く**ことです。
チーム内のコミュニケーションを積極的にとり、開発を進めていく上で問題や不足していることが見つけたら自ら率先してフォローすることが大切です。

顧客からの信頼を上げることで、難易度の高い仕事を任せてくださったり、自身の給与アップ、スキルアップにも繋がります。

## 最後に

SESは様々な現場に携われることができ、困っていることがあれば会社が助けてくれるため、**フリーランスと正社員の良いところを掛け合わせた業界**だと思っています。
「SESはブラック」というイメージが根付いていますが、SESの会社でも、**エンジニアを第一**に考えた良い企業は多くあります！

業界にとらわれず自身の働き方にあったを会社を見つけ、楽しいエンジニアライフを過ごしましょう！
自分が大切にしたいマネジメントの価値観

## はじめに
渋谷のIT企業でテックリードしてます（強くなりたい）。
野澤です。

まず前提、自分はマネジメント経験は特にありません。
一人二人三人くらい、手取り足取りエンジニアリングを教えたり、ときには後輩くんと一緒に同じプロジェクトに入ったり、ときには他のチームの新人メンバーの話を聞いたり、レビューしたりなどなど、
主にプレイヤーとして動いていました。

ただ色々なリーダーの元で開発をしてきたり、他のプロジェクトのメンバーの話を聞いたりして、なんとなく大切にしたい価値観が自分の中にあることに気づき、それをアウトプットしたいと思いこの記事を書いています。
（テックリードという役割を任され、4月から後輩くんも入ってくるのでそろそろマネジメントを体系的に学ぶときなのかもしれない。。。）

## 本題
自分が大切にしたい、忘れないようにしていきたいのは
**相手の力を120%引き出せているかという視点**
であり
**相手の力を120%出せている状態こそ正解**
という価値観です。

特に具体的に意識していきたいのは、
- 正論で詰めない
- 相手の改善点を**真正面**から指摘して、改善してもらうように相手に動いてもらうということを良しとしない（それを本音でぶつかっているから良いことだ。。。とはしない。）

です。
例えば、ある開発タスクを新人くんに任せて、そのタスクを新人くんが期限までに終わらなかったとします。

そのときに、
「なんで終わらなかったんだろう？」
「次は期限内に終わらせられるように反省点と改善点と今後どうしていくかをテキストにまとめて共有して」
「もっと自分とかに聞いてくれたら良かったんじゃない？」
というコミュニケーションをとってしまいがちだと思うのですが、

それを積み重ねてしまうと、人によっては
- 自信を失ってしまう（無力感を認識するのと自信が失なわれてしまうのは別のイメージ）
- 以前失敗したから今回は失敗してはいけないというプレッシャー（次こそは期限に間に合わせないといけない！）になってしまう
- 期限に間に合わせることが最優先になってしまう
- 辛い。。。

などなど弊害が出てきてしまいます。
自信がなくなってきてて、失敗できないというプレッシャーが頭の中にあり、開発するのが楽しくない（or 辛い）という状態はその人の本来の力の60%とかしか出せてないと思うんです。

相手の間違えていることや足りない部分を指摘するのは【**正しい**】反面、それでその人の本来の力を60%まで下げてしまっていてはその指摘は【**間違え**】なのです。
（自分基準でいうと）

本来の力の60%でタスクをこなすので、また期限に間に合わなかったり失敗をしてしまいます。
そうすると、本来の力100%でこなしていれば本来指摘されなくてよかった部分も指摘されたりしてまた自信を失って。。。

何がいいたいのかというと、
**相手の120%の力を引き出した上での足りない点、改善点を一緒に改善していくような動き**
をしていかないといけないなと思っています。


## 最後に
マネジメントに正解はないと思っていますが、
やはり記事を書いている中で、体系的なマネジメントの知識が全く足りてないなと思ったので、
少しずつ勉強していきたいなと思います。
【色変記事】AtCoder水色までにやったこと

# 自己紹介


はじめまして、yamamotoyukiと申します。
東大エンジニアリング研究会というサークルで、競プロの勉強会を行っており、私が水色になるまでに学習したことをまとめることにしました。同様の記事はたくさんあるので、AtCoderを行う方は一つの意見として参考にしていただければと思います。



![スクリーンショット 2023-01-21 18.30.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3117520/91bee69e-c90b-97a8-3608-8f3128d23b50.png)

# 始めた時期
私はプログラミングの学習を本格的に始めたのが2022年の3月からなので、はじめは基礎文法を学んでいました。
6月に入り、ある程度は基礎文法を理解したので、AtCoderのコンテストに参加してみたところ、基礎文法とある程度の数学的考察でABCはC問題くらいまで解けるようになっていました。
コンテストに参加するときに理解していたことは下記の2つぐらいだったと思います。


1.pythonの基礎文法
2.実行時間に間に合うためのループ回数の上限

基礎文法は[AtCoderで始めるPython入門](https://qiita.com/KoyanagiHitoshi/items/3286fbc65d56dd67737c) のサイトに載っている内容がなんとなく分かる程度です。
ちなみに私は頻繁に使わないものの書き方を覚えてはないです。
基礎文法は最初に学ぶのではなく問題を解きながら学んでいくのもありな気がします。


ただし、**ループ回数の上限は10<sup>8</sup>程度である**ということは最初に知っておくべきだと思います！

# 灰色から茶色のとき
私は最初にコンテストに参加したときからある程度解けるようになっていたので、このときはABCのC問題までを30分で解くのが目標でした。（あわよくばD問題も解きたいとは思っていましたが）


この段階で最初に学んだのは**二分探索**と**ソートアルゴリズム**です。
これらのアルゴリズムの学習と同時に**データ構造**についても簡単に学習しました。
時期で言うと6月から7月頃です。


データ構造は最初の方に学んでおくと、アルゴリズムを勉強したときに実装のイメージが付きやすいと思います。

# 緑色のとき
水色になるためにはD問題を解くことは必須であるので、まずD問題頻出の**動的計画法**について学びました。
また、動的計画法と同じくらいの時期に、**幅優先探索**と**深さ優先探索**を学びました。
これは8月から9月頃です。

動的計画法の問題をある程度解けるようになったら、**グラフアルゴリズム**を学び始めました。
このときにUnionFind木について知りましたが、もっと早く知っていればよかったと思います。

グラフアルゴリズムではダイクストラ法やワーシャルフロイド法といった最短経路をもとめるアルゴリズムと最小全域木を求めるクラスカル法などを学びました。

グラフアルゴリズムは10月に学びましたが、概念を理解しただけで今でも実際に使えるレベルではない気がします。（ちなみに10月は毎日競プロの勉強をしていました。）

11月12月はあまり勉強する時間がなく、コンテストにも参加できないことがありましたが、12月中旬からは再びコンテストに参加し、時々練習として問題を解くようにしています。

# まとめ
競プロの勉強は自分のペースで少しずつ新しいアルゴリズムを学んでいけばいいと思います。
ただ、概念だけ分かっていても実際に問題を解けるわけではないので、アルゴリズムを学んだら問題で使えるように練習するといいと思います。（私も今まで学んだアルゴリズムの問題を練習しなければと思っています）

私自身は青色を目指して精進していきたいと思います。

拙い文章ですが、読んでいただきありがとうございます。
PC環境で表示されない絵文字を表示する方法


# はじめに

某アイドルグループが好きなのですが、ブログに表示される絵文字がほとんど表示されない日々が続いていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71795/a89703cc-1c53-09a6-a9f9-c607cdb37c3c.png)

あああ！？！？なんで！？！？ちくしょうめ！！！！！！！！！

なんだその豆腐は！？？？！？！！！？！？！？

許せるものではありません。

世は大スマホ時代、iOSとAndroidが対応してるんだからスマホで見れば良いのかもしれない。

けど、完全に負けた気がするので調べました。


# 結論

Chromeアドオンを入れたら解決しました。

https://chrome.google.com/webstore/detail/twemoji-for-chrome/fopgafjdjlongoeblobbafbnapafcicg

Twemoji for Chrome

導入後
↓
![after_unicode.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71795/5d3379b3-2dd7-eb61-7f5b-13794c502934.png)

やった～ :relaxed: 



# 懸念点

一応既にUnicode 15が既に2022年9月に公開済みなんですが、もしかしたら対応されないかもしれないです……。

https://twitter.com/catnose99/status/1607545008042967040

その時はその時に考えましょう（諦め）


# 試したけど関係なかったこと

- Windows側のフォント変更
- Chromeのフォント変更
- Chromeで絵文字を使いやすくするアドオンの導入
- Windowsアップデートのオプションを探す


# 調べた備忘録

（2023-01-21時点）

なぜかFireFoxでは何もせずともUnicode 14までの対応が済んでました。偉いというか、感心というか、見直しました。

Chrome, Edge, BraveではUnicode 12までの対応でしたね。

そして、Chromeだろうがブラウザを問わず、Web版TwitterではUnicode14までがしっかり表示されていました。

https://twitter.com/funyofunyo/status/1615953614362796033?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1615953614362796033%7Ctwgr%5E59277cfa8cd4bce3b69257fc7fad9d1fb0210e87%7Ctwcon%5Es1_&ref_url=http%3A%2F%2Ftas.habit-calendar.com%2F%3Fkeyword%3DUnicode

コピペしようにもQiitaで絵文字使うの超大変なので、リンク先で見てください。

https://superuser.com/questions/1094188/how-do-i-display-the-latest-unicode-characters-esp-emoji-in-windows-browsers

↑
こちらの質疑にある『Test characters:』の所が確認するのに最適でした。


# まとめ

Unicode 12って、2019年3月のものですからね……。

正直、絵文字の対応が遅すぎて何かのバグかとも思いました。日々のWindosアップデート、Chromeアップデートは？対応しないの？なんで……？と。

まぁ、世の中ほとんどスマホで完結する時代に入ってるから、無視してもいい作業なのかもしれませんけど……。

ちょっと悲しい調査結果でした。


終わり
【TOGAF9認証試験のための勉強メモ(1)】TOGAF概要

こんばんは。torippy1024です。
先日、会社の研修にて、TOGAF9 トレーニング・コース(資格試験付き)を受講しました。
試験に向けて現在勉強中のためメモを書いています。何回書けるかわかりませんが、よろしくお願いします。

## TOGAFとは
TOGAFとは、The Open Groupのアーキテクチャフォーラムが開発しているITアーキテクチャ作成フレームワークです。
「グローバルでオープンであること」が売りのフレームワークで、外資系IT企業のアーキテクトやプリセールスフェーズを担当するテクニカルセールスやコンサルタントは学んでおくと実務に役立つことがあると思われます。

ただ一方で、このTOGAF、ITシステムのためのフレームワークではありません。もっと一般的なエンタープライズアーキテクチャ(Enterprise Architecture;EA)を作成するためのフレームワークです。このため、ITの知識は必要なく、どちらかというと必要な知識はEAに関するものだったりします。
(日本はEAの普及が遅れているので、ピンと来ない人が多い・・・と講師の方が嘆いていました)

最新のバージョンは10なのですが、私が受講した時は9.2でした。
英語版でかつ非商用利用であれば90日間、無料で参照可能です。(ただし企業が商用利用する場合はライセンス購入が必要)
https://publications.opengroup.org/c182 (本編)
https://publications.opengroup.org/c180 (ガイド類)
https://publications.opengroup.org/i182 (本編 90日トライアル版)

日本語翻訳版は公開されていないようです。
欲しい方はOpengroup公式サイトから購入するか、研修を受講しましょう。税抜き30万円で、3日間の研修+1日間の試験のコースです。
https://opengroup.or.jp/togaf.html

## TOGAF Certifiedとは
TOGAFの資格試験に合格すると、資格が取得できます。
試験には以下の二つがあるそうです。
TOGAF Foundation (Level 1)
TOGAF Certified (Level 2)

Level1とLevel2で、それぞれ異なる試験があり、Level1に合格しないとLevel2は受験できません。
(正確には、研修に参加すると試験日に両方受験することになるが、Level1に落ちるとLevel2は採点されない様子)

合格率は決して低くなさそうです。(というか、研修を受講すると講師の方がかなり試験に向けたヒントを教えてくれると思いました)
日本ではまだあまりメジャーな資格ではないですし、資格保有者はもっと増えてほしいと思っているのでは？と勝手な推測をしています。

また、3日間の研修は日本語で行われ、試験も日本語になっているようですが、英語での受験もできるそうです。
資料は公開されているわけですし、独学で勉強して英語で試験を受ければ格安で資格取得ができるなとちょっと思いました。
(研修自体がためになったので、個人で数十万のお金は出せないけどTOGAFの資格を取りたいという奇特な人でないとこのパスは取らないと思いますが)

## TOGAF9の概要
3日間の研修(ご時世上、オンラインにて受講)を受けて、ざっくりとしたTOGAFの個人的な概要理解を書くと、以下です。

**TOGAFとは、ADM(Architecture Development Method;アーキテクチャ開発手法)の技法とガイドラインを使うフレームワークのことである。**

では、ADMとは何かというと、ざっくりとは以下です。

**ADMとは、大企業向けのエンタープライズアーキテクチャを策定するためのフレームワークで、初期フェーズ、フェーズA～Hの9つのフェーズと、アーキテクチャ要件管理というプロセスからなり、9つのフェーズを反復的に行うことでアーキテクチャ策定を行うものである。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684500/a2b8503d-0895-e98e-2a24-296a7504bf22.png)
画像引用元：https://opengroup.or.jp/togaf.html
※無断の画像引用なので、NGだったら消します。すいません。。

ということは、ADMさえわかればTOGAF試験には合格できるのか？と思われるかもしれませんが、そうではありません。
TOGAFでは、非常に(日本人には)難解な専門用語が含まれており、TOGAFの専門用語を理解した上で、ADMとそのガイドラインを学ぶ必要があります。

ですので、やることは以下の２点です。
- TOGAF用語を理解する
- ADMとそのガイドラインの内容を理解する

この2点を理解すれば、Level1、Level2両方の試験に受かるはずです！たぶん！(まだ受かっていないので根拠なし)

とりあえず初回の概要は以上です。
【Embulk】embulk-output-postgresqlで出力先のテーブルに主キーを設定する。


## 実施したいこと

- embulk-output-postgresqlで出力先のテーブルに主キーを設定する。

## 必要なプラグイン

- embulk-output-postgresql 

## 設定方法

- config.ymlにcreate_table_constraintを追加する。以下の記述によりhoge1,hoge2,hoge3を複合主キーとしたhoge_tableにデータが登録される。

```config.yml
out:
  type: postgresql
  mode: truncate_insert
  default_timezone: "Asia/Tokyo"
  host: "192.168.1.XXX"
  port: 5432
  user: XXXX
  password: XXX
  database: XXX
  schema: XXX
  table: hoge_table
  create_table_constraint: 'PRIMARY KEY (hoge1,hoge2,hoge3)'
```
UbuntuでUnable to locate packageの解決法

シェルスクリプトの勉強中に少々躓いた箇所があったので、以下に解決法を記載する。

◆作業環境
Windows 11

◆実行内容
最初にfingerコマンドを試し打ちしてみた。
```
$ finger
Command 'finger' not found, but can be installed with:
sudo apt install finger
```

最初はインストールされていないだけかと思いきや、違った。
```
$ sudo apt install finger
[sudo] password for user:
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Package finger is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

E: Package 'finger' has no installation candidate
```

ちなみにtreeコマンドを実行してみても同じような結果だった。

```
$ tree
Command 'tree' not found, but can be installed with:
sudo apt install tree
```
インストールを試みてみたが結果は同じ。
```
$ sudo apt install tree
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
E: Unable to locate package tree
```

最終的にはapt自体をアップデートすることが必要だったことが発覚。
```
$ sudo apt update
(中略)
22 packages can be upgraded. Run 'apt list --upgradable' to see them.
```

aptのupdateを実行した結果、fingerコマンドもtreeコマンドも使えるようになった。


◆後書き

せっかくなのでaptコマンドについても調べてみた。
結果を以下にて要約。

・aptコマンドはパッケージ管理コマンドである。
・そもそもaptコマンドはAPTの操作をするコマンドである。
・更に掘り下げると、APTはLinuxのソフトウェアの導入や管理、削除に用いられるパッケージ管理システムの一つ。
【Embulk】embulk-output-postgresqlで任意のカラムを追加する。


## 実施したいこと

- embulk-output-postgresqlで出力先のテーブルに、システム日付が自動で設定されたcreated_atと固定文字列が設定されたカラムを追加したい。

## 必要なプラグイン

- embulk-filter-column
- embulk-filter-eval


## 設定方法：created_atを追加する

- config.ymlに以下の記述を追加する。（一度、defaultの値を設定して書き換えるような記述をするらしい。）

```config.yml
filters:
  - type: column
    add_columns:
      - {name: created_at, type: timestamp, default: '19000101', format: "%Y%m%d" , timezone: "+09:00"}
  - type: eval
    eval_columns:
     - created_at: Time.now
```

## 設定方法：固定文字列のカラムを追加する。

- config.ymlに以下の記述を追加する。

```config.yml
filters:
  - type: column
    add_columns:
      - {name: hoge_column, type: string, default: 'hogehoge' }
```
KerasライブラリのMobilenetV2を使った鉄鋼材料の金属組織画像の判定

# はじめに
前回の[機械学習を使った鉄鋼材料の金属組織画像の判定](https://qiita.com/_Moony/items/5d0a1b15204c84d63990)では、機械学習アプリTeachableMachineを使って金属組織の判定を行いましたが、ここではKerasライブラリのMobilenetV2というモデルを使って金属組織の判定を試みます。

# モデルの作成
- 金属組織の画像データは[前回](https://qiita.com/_Moony/items/5d0a1b15204c84d63990)と同じものを使用しました。
- 学習モデルはImageNetで事前学習済みの[KerasライブラリのMobilenetV2](https://keras.io/ja/applications/#mobilenetv2)を使用して、転移学習で行いました。
- TeachableMachineで作成されるモデルのファイルサイズは2.4kBと同程度のファイルサイズになるように学習モデルを作成しています。

以下の①～③のプログラムや学習モデルについてはサンプル画像と一緒にgithubに格納しております。
① MobilenetV2モデルによる学習・検証プログラム（TrainValidation_MobileNetV2_model）
② 上記①で作成したモデル（model.h5およびlabels.txt）
③ 上記②を使って推論するプログラム（Metallography_MobileNetV3.py）
上記②、③の使い方については、githubのREADMEをお読みください。

https://github.com/repositoryfiles/Metallography-MobileNetV2

上記①については一般的な画像分類（犬・猫の画像分類など）のMobileNetV2モデルを作成するプログラムです。使い方は次のとおりです。

- あらかじめ、分類する種類の分だけフォルダを作成して画像を格納しておきます。プログラムも適当な場所に置きます。
- プログラムの24と25行目のフォルダ名をご使用の環境に合わせて編集してから実行します。
- 学習終了後、二枚のグラフ（accracyとloss）が表示されます。これらを閉じるとプログラムは終了します。
- 学習で作成されるmodel.h5とlabels.txtを使って、Metallography_MobileNetV3.pyで実際の画像を推論することができます。
- 学習の正解率が低い場合、画像の水増し条件や学習率などの変更で改善することがあります。

なお、学習に用いた金属組織画像によるaccuracyとlossは次のとおりです。

<img width="400" alt="Figure_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1729073/111c3c10-28a1-cf22-b964-8efe779a9d8e.png">

図1　学習に用いた金属組織の画像データに対する学習曲線

<img width="400" alt="Figure_2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1729073/49f1795c-3fe3-4a8d-81a5-aaab23bc11c8.png">

図2　学習に用いた金属組織の画像データに対する損失曲線

何かのお役に立てれば幸いです。
Googleプロジェクト管理：プロジェクトデータのシグナルによる優先順位付け

# はじめに

わたしが [Google プロジェクト管理:プロフェッショナル認定証で得られた素晴らしい体験][google]を、要点をまとめ小さく分割して、わかりやすく簡潔に紹介していきます。

興味があれば、ぜひ ***"Google プロジェクト管理:プロフェッショナル認定証"*** を受講してみてください。

[google]: https://qiita.com/mapami/items/317ae776a2268fd54c8f

https://jp.coursera.org/professional-certificates/google-project-management

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/dc97f9d2-8c30-5310-a190-3fb484c9c091.png" width="800">

# プロジェクトにとって最も重要なデータを特定する

プロジェクトマネージャーとして収集できる情報や事実はいろいろありますが、プロジェクト全体の成功を脅かすシグナルを意識することが重要です。シグナルとは、観察可能な変化のことで、プロジェクト全体の健全性を判断し、何かがおかしいという兆候を早期に発見するのに役立ちます。

どのデータが最も重要かを判断するためには、 アクセスできるデータの種類を認識し、どのシグナルに反応すべきかを知ることが重要です。

では、どのデータが重要なのか、どのように判断すればよいのでしょうか？

# 収集するデータに優先順位をつける

プロジェクトマネジャーとして、シグナルを探し、データに優先順位をつけて、良い結果を出すかどうかは、あなた次第です。そのためには、いくつかの方法があります。

#### <font color="MediumBlue">1.チームの生産性とアウトプットを観察する</font>

どのタスクが全体の目標に最も貢献しているかを確認するのです。そうすれば、どのデータポイント（この場合はタスクとアクティビティ）に焦点を当てるべきかの重要性を判断する助けになります。

#### <font color="MediumBlue">2.ステークホルダーにとって最も価値のあるデータに優先順位を付ける</font>

例えば、ある製造会社で、第3四半期までに携帯用家電製品を発売するというプロジェクトが進行中だとします。ステークホルダーは、この期限に間に合うかどうか心配しています。

さて、このプロジェクトについてどんなデータがあるのか、まず考えてみましょう。

今が第1四半期で、すでに2,000ドル予算がオーバーしていることは知っています。しかし、バーンダウンチャートによれば、予定より30日進んでいることも分かっています。<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/fd510fb9-777a-3325-5efe-7c6253f95c06.png" width="600">

プロジェクトは予定通り進んでいると思うかもしれませんが、関係者が家電製品にもっと多くの機能を追加したいと言ってきたため、この3週間でタスクの数が10%増加しました（<font color="Red">Behind schedule</font>)。そして、その新機能を追加するために必要な深夜と長時間の労働で、チームの生産性が落ち始めている。

さて、第3四半期の締め切りに間に合うかどうか、どうでしょうか？どうしますか？

予算が2,000ドル超過しているというシグナルに注目したくなるかもしれませんが、ステークホルダーが予算超過よりも納期を守ることを重視していると伝えたのなら、 ***<font color="MediumVioletRed">予算よりも時間やスコープに関する主要なシグナルに注目</font>*** し、そのシグナルに注目して、改善すべき領域を特定し優先順位付けすることをお勧めします。

関係者が、チームのタスクを増やすような新機能の要求を止めれば、納期を守れることが、関連データからわかります（<font color="Blue">Ahead of schedule</font>)。生産性メトリックスを使用して、チームの現在の生産性割合でスコープの増加をどのように管理するかを予測し、これをステークホルダーに伝えることができます。

ステークホルダーと期待を何度もリセットする必要がないように、プロジェクトの優先順位を常に最新の状態に保ち、この情報に誰もがアクセスできるようにします。ステークホルダーは、重要な質問に対する答え、成功基準、成果物、プロジェクト全体の健全性など、ハイレベルな概要をプロジェクト計画で確認することができます。

:::note info
他にも多くのデータポイントがあることを忘れないでください。シグナルを利用し、プロジェクトの目標に最も大きな影響を与えるタスクに焦点を当て、ステークホルダーの優先順位に合わせることは、正しいタスクの優先順位を決めるのに有効な方法です。
:::
AndroidでSharedPreferenceのxmlファイルはインストール直後にはできていない

# SharedPreferenceのxmlファイルができるタイミング

[Androidで設定画面を作ってみる](https://qiita.com/cozyk100/items/540ba3c9575d4955e014)でAndroidX Preference Libraryを使って設定画面のサンプルを作りました。業務でHTTPで通信するようなアプリを開発していて、HTTPの送信先のURLをAndroidX Preference Libraryを使って作りました。

ここで、気がついたのですが、

**SharedPreferenceのxmlファイルはインストールした直後はできていない**。設定画面（PreferenceFragmentCompatのFragment）が呼ばれたタイミングで作られます。(もしくは、SharedPreferenceに初めて、putXxxxしたタイミング。ま、言われてみれば当たり前と言えば当たり前)

標準では、ここにできているはずです。
```
/data/data/{パッケージ名}/shared_prefs/{パッケージ名}_preferences.xml
```

ここで問題になったのが、インストール直後、1回でも設定画面を開いてくれれば問題ないのですが、1度も開かずに送信しようとすると、送信先のURLがSharedPreferenceにないので、送信先が取得できず、送れないということです。
送信先のURLはAndroidX Preference Libraryの画面定義のxmlにデフォルト値として定義されているので、設定画面を1度開けば、何も変更しなくても、xmlファイルに書き込まれます。

似たような作りのアプリであれあ同じ問題が起こるかもしれません。

この事象の対応として

1. アプリの起動時、もしくは送信前にSharedPreferenceに送信先のURLが無ければ、設定画面に誘導する。
1. 何らかの方法で、インストール時にSharedPreferenceのxmlを作る。

上記の1.は実現可能ですが、設定値はほぼデフォルトのままで変更する必要がなく(テスト時とか、よほどのことが無い限り変更がない)、なのにユーザを設定画面に誘導するのは無駄のような気がする。
2.は送信先URLがAndroidX Preference Libraryの画面定義のxmlにデフォルト値と別々に二重定義になってしまう可能性があり、イマイチ。

# 解決策
PreferenceManagerの[setDefaultValues](https://developer.android.com/reference/androidx/preference/PreferenceManager#setDefaultValues(android.content.Context,int,boolean))を使うことにより、AndroidX Preference Libraryの画面定義のxmlからDefault値を撮ってきて、xmlファイルに書き出します。

これは、MainActivityのonCreateに入れておきます。
```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    ・・・
    PreferenceManager.setDefaultValues(applicationContext, R.xml.root_preferences, false)
    ・・・
}
```
第3引数はfalseにしておくと、このメソッドがまだ一度も呼ばれていない場合だけ、default値が作られます。(毎回、上書きされることはない)

これで、無駄に設定画面に誘導することもなく、送信先URLを二重定義することもなく済みました。
社会人1年3ヶ月社畜エンジニアが現場等で感じること（つぶやき）


# はじめ
本記事について、自身の体験談を記載しています。
記者は新卒21でIT業界未経験で入り、今までで感じたことや必要だと感じたスキル等などを記載してます。
個人的な意見などもあるので、暇つぶしにいていただければと思います。（笑）

### あんただれ？:boy_tone1:（笑）
関西出身の大学21卒の文系です。大学卒業前はIT全般的に未知の世界くらいわかりませんでした。
タイピングはデスノートのLなみに遅い。※1分間ではかったとき20文字だったかな？
なぜあんまり意味がないWord2013　Excel2013取得した。。。
なぜかクラウドだけ触ったことあるがNWやserverってなに？レベル。（プログラミング不可）
コミュニケーション能力も全体的にない（ビジネス用語も話せず友達も少ないほう....）

## これまでの業務経験:keyboard:
これまで地方自治体や企業の派遣で案件先に常駐してました。
内容はシステムのテスト業務、ヘルプデスク運用、監視作業etc...行っていました。(業務の中でも雑魚い方)
それも良い経験になり、それぞれで学ぶことが多くありました（一部めっちゃしごかれた:head_bandage:）
その分、社会人基礎力及び技術面に関して知識や能力が付き始めたと実感できるようになっていきました。



## 今までの業務で感じたこと
### 良いこと:thumbsup_tone3:
- タイピング早くなる
- いやでも最新のIT業界の話題が入る
- 資格取得で給料に反映される
- PCなどの操作方法やバグが解決できるような力身につく
- コミュ力がつく（提案力やビジネスコミュ力）

### 悪いこと:thumbsdown_tone3:
- 夜勤があり（案件による）
- 体調管理が難しい
- 給料アップが少ない（会社による）
- 常に勉強しなければいけない

### 良し悪し（時と場合による編）:eyes:
- 給料の差がある（案件や会社による）
- 夜勤やシフトなど含めいつ何時でも対応することがある（案件や業務内容にもよる）
- 休日やプライベートが確保できる（案件による）
- 転勤や出張がある（案件による）
- 勉強や学習時間が勤務時間にできる（案件による）
- 待遇いいことがある（会社による）
- PCの知識がイヤでもつく（笑）
- シフトなので平日が休みなる（夜勤制は基本的にシフト多い気がする）
- ショートスリーパーは有利（睡眠時間が少ない人）   　etc....

良し悪しの部分の方が圧倒的に多く、こればかりはその時と場合によります。
記者の場合は上記が思い浮かびました。:thinking:
他にも、インフラ業界で働く人はいろいろと感じていることがあるかと思います。
記者が一番良いと感じたのは、勉強や学習時間が勤務時間でもできる（ダメな場合もある）ことです。実際にserverやcloud関連の資格を在籍期間で取得できました。
それ以外にも、勉強時間はプライベートも含めますが、仕事時間は勉強して、帰宅後はのんびり過ごすこともしばしば....（笑）
それ以外にも、別の調べごとや読書もしてました。
言うまでもありませんが、あくまで業務優先であり、その場のルールに則っての話になります。
このように勉強する人にとってはとても神時間があるので、とても嬉しいものでした。

また正反対に悪いと感じたことは、夜勤やシフト含めいつ何時でも対応することがあるということです。これはこの業界で多いことで、インフラはものにもよりますが、基本的に基盤を支えているものになります。例えば、NWは通信ができて当たり前な時代ですが、通信不可になると途端にユーザー側に影響がでて、炎上します。そうすると復旧作業に向けて、いつ何時も対応しなければいけません。これは近年の多く見られる災害も同様になります。もちろん企業によってBCPやDRなど他諸々の対策は行ってると思いますが、発生するとても大変です。
もちろん、単純に夜勤やシフトもありますが、このように夜勤やシフト含めいつ何時でも対応することがあるのがつらいところです。

## 必要だと思うスキルについて（個人的な意見）
これまでの業務を踏まえ、社会人的スキルと技術的なスキルに分けて話しますがが、その前にここではITインフラ業界が前提となります

### 社会人的なスキル:tongue:
・計画力
・コミュニケーション力
・主体性
・行動力
・収集力　etc.....

### 技術的なスキル:muscle_tone3:
・インフラ部分の技術
・ITLL
・ExcelやWordなの資料作成
・タイピング力
・好奇心　　etc.....

社会人的スキルについて、基本的なスキルばかりです。他スキルとはなりませんが、人柄の良さや姿勢or見せ方も少しばかりあるかと思います。記者の周りには、技術あるものの社会人スキルや人柄がよくない人もいます。また、仕事に熱心であるものの、姿勢or見せ方が悪い人もいます。そんことを盛り込むとより技術的スキルも必要となりますが、それよりも社会人的スキルの方が必要なのかもしれません。

技術的なスキルについて、セキュリティーやITLLは必要な部分だと言えます。特にセキュリティーはほぼ全般に該当し、ITLLは運用保守に該当し、未経験の人は運用保守に行く可能性があることから、必要だと思われます。


またタイピング力は速さ正確と同様に必要であり、遅ければいろいろ指摘されることもあるかもしれません（記者はめちゃくちゃ遅かった）


# まとめ
### 向いている人と向いていない人
:::note
- 常に勉強や物事に取り組む意思や行動ができるひと（向き）
- 計画力や人間性がしっかりしている人（向き）
- 注意力がない人や容易な人（不向き）
- コミュ力がない人や意欲がない人（不向き）
:::

最後に、上記のすべての考え方や必要なことは、自身の経験上や考えなどをもとに記載しています。
IT業界に新卒で入社してから2023年までいろいろな業務を行いました。
そこでは上記の様な能力などは必要だと思います。
今後、IT業界は人材不足になるといわれいますが、その通りだと思います。
もしIT業界で新卒生で就活を悩んでいる人がいれば、ぜひ参考にしてみたくだい。
MySQL起動エラーの対処の仕方【Can't connect to local MySQL server through socket '/tmp/mysql.sock' (38)】

## エラー内容
```
mysql -u root -p     
Enter password: 

ERROR 2002 (HY000):
Can't connect to local MySQL server through socket '/tmp/mysql.sock' (38)
```

MySQLに繋がらない！！

## 解決策

一番多いのがMySQLが起動していないパターン。。
なので一旦起動しましょう。

```
mysql.server start

Starting MySQL
 SUCCESS! 
```
再度チャレンジ！！！

```
mysql -u root -p   
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 8.0.32 Homebrew
mysql> 
```

入れました〜〜！！
はい、解決！終了！！
【SwiftUI】特定の条件でのみオーバーレイする

# はじめに
条件によって`Text("Hello, world!")`にオーバーレイの有無を決定したいとします。

# サンプルアプリ
![Simulator Screen Recording - iPhone 14 Pro - 2023-01-21 at 21.35.26.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/8039a8ff-ea86-d602-c248-ec9f0ac3dc15.gif)


# やりかた
```swift:ContentView
import SwiftUI

struct ContentView: View {
    @State var isShowBorder: Bool = false
    var body: some View {
        VStack(spacing: 50) {
            Toggle("", isOn: $isShowBorder)
                .labelsHidden()

            Text("Hello, world!")
                .padding(.init(top: 10, leading: 20, bottom: 10, trailing: 20))
                .overlay(isOverlay: isShowBorder) {
                    RoundedRectangle(cornerRadius: 10).stroke(style: .init(lineWidth: 3))
                }
        }
    }
}
```
```swift:View+
import SwiftUI

extension View {
    @ViewBuilder
    func overlay<T: View>(isOverlay: Bool, content: () -> T) -> some View {
        if isOverlay {
            self.overlay {
                content()
            }
        } else {
            self
        }
    }
}
```

ここで重要なのは`@ViewBuilder`です。

# おわり
久しぶりにSwiftUIの記事を書きました
草莽Erlang ── 33. lists:enumerate

口で言うより行うことがErlang習得への近道と信じています。

https://qiita.com/mnishiguchi/items/9237780e849d80a85e11

## lists:enumerate/1

各要素をインデックスと一緒にタプルで括って、新しいリストを返します。

https://www.erlang.org/doc/man/lists.html#enumerate-1 

要素の数え方は「１、２、３ぁっダー！」です。例えば最初の要素のインデックスは`1`となります。

https://youtu.be/AWxwmqzbOaw

https://youtu.be/FSz7N5hCltw

https://note.com/awesomey/n/n4d8c355bc8f7

```erlang
> lists:enumerate([a, b, c]).
[{1,a},{2,b},{3,c}]
```

## lists:enumerate/2

`lists:enumerate/2` を使うと、インデックスの最初の値を指定できます。

```erlang
> lists:enumerate(0, [a, b, c]).
[{0,a},{1,b},{2,c}]

> lists:enumerate(100, [a, b, c]).
[{100,a},{101,b},{102,c}]
```

[listsモジュール](https://www.erlang.org/doc/man/lists.html)には他にもリスト処理のための関数がたくさんあります。

## Elixirにも挑戦したい

闘魂ElixirシリーズとElixir Schoolがオススメです。

https://qiita.com/torifukukaiou/items/3b65e5c04fa8c55f526e

https://elixirschool.com/ja

https://qiita.com/piacerex/items/09876caa1e17169ec5e1
UbuntuにSSHで接続する

## 環境確認
### クライアント側
Ubuntuのバージョン確認
```shell
lsb_release -a
```
```
Distributor ID:	Ubuntu
Description:	Ubuntu 20.04.2 LTS
Release:	20.04
Codename:	focal
```
### 接続側
```macOS```
## クライアント側の設定
### ユーザーの追加
```sh
adduser katsuji
```
パスワードを設定してとか聞かれるのでパスワードだけ設定してあとはEnter

```sh
usermod -G sudo katsuji
```

### sshd_condigの編集
```/etc/ssh/sshd_config```を編集することでrootでの接続を拒否したり、接続ユーザーを追加できる。
色々と書いてあるが以下の項目を追加する
```shell:/etc/ssh/sshd_config
PermitRootLogin no #root以外の接続を拒否
AllowUsers katsuji　 #ユーザーの追加
Port XXXX #デフォルトは22なので変更しておく方が安全
```

## 接続側の設定
### sshのconfigを作成
```sh
vi ~/.ssh/config
```
```:~/.ssh/config
Host ssh_katsuji #適当な名前
  HostName X.X.X.X #クライアント側のIPアドレス
  User katsuji
  IdentityFile ~/.ssh/cnh.pem　#sshの公開鍵
  ServerAliveInterval 60　
  Port 443
```

## 接続
```ssh ssh_katsuji```で接続できる！
表拡張機能を使ってRで作成したデータをTableauに取り込む

## 表拡張機能
表拡張機能はTableau 2022.3から追加された、
RやPython等で加工・分析したデータを、Tableauのデータ表として取り込むことのできる機能です。

この機能を使えば、
Tableauでは面倒な集計をRで行ったり、
Rで実行した分析結果をTableauでいい感じに可視化したりが簡単にできるはず！
というわけで、Rで表拡張機能を使う方法をまとめました。

※普段からRを使っている人向けの内容のため、Rのダウンロード方法やRコードの解説は割愛します。

## TableauをRサーバーに接続する
まず、TableauでRを使えるようにセッティングをします。
手順は以下の通りです。
#### 1. Rserveパッケージをインストール
R（Rstudioでも可）を起動し、以下のコードを実行。
``` .R
install.packages("Rserve"); library(Rserve); Rserve()
```

#### 2. Tableauを起動し、「分析の拡張機能接続の管理」を選択
ヘルプ > 設定とパフォーマンス > 分析の拡張機能接続の管理　で選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984873/da5161b0-f5ec-1b25-8aab-b25dff35cfe0.png)

#### 3. 接続タイプでRserveを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984873/9e015de9-938b-b359-77ab-612cfb6acf5b.png)

#### 4. ホスト名、ポートを入力し接続
ホスト名：localhost、ポート：6311と入力。
テスト接続を押してみて、「分析の拡張機能に正常に接続されました」と表示されればOK。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984873/a9bfa2ec-086c-2780-d237-2a91c979b3ff.png)


これで準備は完了です。


## 表拡張機能を使用する
今回は、表拡張機能を使ってサンプルスーパーストアのデータを加工してみようと思います。
サンプルスーパーストアのデータですが、日本語だと文字コード関係のエラーが出てしまったので、
英語版（[こちら](https://community.tableau.com/s/question/0D54T00000CWeX8SAL/sample-superstore-sales-excelxls)からダウンロードしました）を使用しています。
（文字コード問題、解決策をご存じの方がいらっしゃれば是非教えていただきたいです…）

#### 1. データをTableauに接続
まずはいつも通りデータに接続します。

#### 2. 「新しいテーブル拡張機能」をドラッグ&ドロップ
![テーブル拡張機能のドラッグ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984873/a0b659e4-d3d4-54b8-1c24-fb9ff4ec1749.gif)

#### 3. シートをドラッグ&ドロップ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984873/d515fcec-72a8-4550-7d7a-44fbf2a8b55f.png)

#### 4. スクリプトを入力
右側のスクリプトボックスの中にRのスクリプトを入力し、適用をクリックします。
今回はCategory・CityごとにSalesの和を求める集計をしてみました。
使用したスクリプトは以下の通りです。

``` .R
library(dplyr)

# 元データ(.arg1)をデータフレーム型に変換
df <- data.frame(as.list(.arg1))

# Category、CityごとにSalesの和を計算
df_city_sales <- df %>%  
  group_by(Category, City) %>% 
  summarise(city_sales_sum = sum(Sales))

# 元データと結合
df_join <- df %>%
  select(Order.ID, Order.Date, City, Category, Sales) %>%
  left_join(df_city_sales, by = c("Category","City"))

# Tableauに取り込みたいデータを表示
df_join
```

Tableauからの入力データは **.arg1** という名前で格納されています。
この.arg1ですが、どうやらpairlistというデータ型になっているらしく、
**一度list型に直してから、データフレーム型に変換**する必要があります。

#### 5. データ確認
「出力テーブル」を確認すると、作成したテーブルを確認できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984873/b47b2711-820b-669f-6461-ce619c4b6979.png)

作成したテーブルは通常のデータソースと同様にVizに使用可能。
（ちゃんとTableau側で集計した数値とRで集計した数値が一致している）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984873/09cb050f-db62-9ea5-621c-5f78878d989c.png)

## おわりに
今回は簡単のためにTableauでもできるような集計しかさせていませんが、
複雑な前処理をR側にやらせてみたり、
Rで分析した結果をそのままTableauで可視化したりと、
使いこなせればかなり強力な機能な気がしています。

普段Rを使って分析などをされている方は、是非いろんな形でご活用いただけたらと思います。


## 参考URL
https://www.tableau.com/ja-jp/learn/whitepapers/using-r-and-tableau
https://www.youtube.com/watch?v=zErOzr-qUPk&t=1897s
C# ゲーム作成時 備忘録

## for
```cs
for(int i = 1; i <= 10; i++){
    //処理
}
```

## 抽象クラス,メソッド
「abstract」をつける
```cs
public abstract class className
public abstract vaid methodName();
```
### 実装方法
継承先のクラスで「override」する
```cs
public override void methodName(){
    //処理
}
```
## 時間の引き算とフォーマット
コンストラクタでstartTimeを取っておいて、endTimeから引く例
```cs
DateTime startTime;
//<省略>
string getClearTime(){
    DateTime endTime= DateTime.Now;
    TimeSpan resoutTime = endTime-startTime;
    return resoutTime.ToString(@"hh\時\間mm\分ss\秒");
}
```

## 三項演算子

変数 = 条件 ? true : false
```cs
void OnCollisionStay(Collision collision)
{
	//衝突しているタグが"testTag"ならtrue,それ以外ならfalse
	bool flag = (collision.gameObject.CompareTag("testTag")) ? true : false;
}
```
Preattentive Attributesの効果を知る

:::note info
本ページのTableauを用いた出力結果を引用する場合は，引用元として本ページを明記ください
:::

前回の記事ではPreattentive Attributesの外観についてご紹介しました．
今回の記事では，実際にPreattentive Attributesの効果を見ていきたいと思います．

Preattentive Attributesとは私たちの脳，より正確には空間記憶が，ビジュアルを見るときに無意識に処理する属性のことでした．

私たちの脳は見たり覚えたりするものについて非常に選択的です．
まずは，色を変えるとビジュアルを見るときの私たちの脳，より正確には空間記憶が変わるのかを見てみましょう．
図の引用には以下の文献を使用しています．
>Healey CG, Enns JT. 2012. Attention and visual memory in visualization and computer graphics. IEEE Trans. Vis. Comput. Graph. 18:1170–88

![スクリーンショット 2023-01-21 19.46.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394349/a4083eb9-8082-0cbc-035d-bc6cece78e4e.png)
これはPreattentive Attributesの中の色を変更した例です．
左側の図と右側の図を見て注視する箇所は変わりましたか？
例外を除き，全ての人間がYesと答えるでしょう．
ビジュアルを見るときの私たちの空間記憶が変わったことが分かります．

![スクリーンショット 2023-01-21 19.52.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394349/a54974f9-b9b9-ccae-922b-9d9d2814eb01.png)
これはPreattentive Attributesの中の形状を変更した例です．
こちらも同様に左側の図と右側の図を見て注視する箇所は変わったでしょう．


挙げた例はPreattentive Attributesの色と形状です．
ただ，Preattentive Attributesには順位があり，実は色や形状は最も高い効果というわけではありません．
Preattentive Attributesは，位置＞色＞サイズ＞形状の順で効果が大きいと言われています．

ここからはTableauのサンプルデータ「サンプル - スーパーストア」を使用して，Preattentive Attributesを変えた結果を出力し，都道府県別売上で効果の比較を行います．
以下が全出力結果です．
https://public.tableau.com/views/qiita_viz/sheet0?:language=ja-JP&publish=yes&:display_count=n&:origin=viz_share_link

リンク切れの場合は以下の画像をご確認ください．

![スクリーンショット 2023-01-21 20.30.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394349/8c7c0367-5e75-e1b2-700d-ca2ccfca7ad0.png)
これだけではさらっと見て売上の比較が出来ません．

![スクリーンショット 2023-01-21 20.20.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394349/1fffd620-e6a6-52e0-9d9f-097e560b2497.png)
形状よりはだいぶ分かりやすくなりました．
ただ，同じぐらいの規模の都道府県の比較がしづらいです．

![スクリーンショット 2023-01-21 20.28.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394349/f83dc2bc-4095-94df-54b8-c99de997d64f.png)
サイズよりさらに分かりやすくなりました．
ただ，「売上規模はなんとなくこれぐらいなんだろうな」ぐらいしかまだ分かりません．

![スクリーンショット 2023-01-21 20.19.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394349/e7aa8342-4ae5-4d7e-e588-dfcb099aafe4.png)
色よりも分かりやすくなりました．
都道府県間の差もある程度わかります．

以上，本記事で述べたように脳は見たり覚えたりするものについて非常に選択的です．
Preattentive Attributesの効果を有効に活用して，自らの意図を適切に伝えるビジュアル分析を行なっていきましょう．
pythonでメモ帳を作ってみた。

<iframe width="560" height="315" src="https://www.youtube.com/embed/wwWTSJd8y4Q" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

## 完成系
![](https://storage.googleapis.com/zenn-user-upload/1d5f25fbf67e-20230121.gif)


## 仮想環境を作成(Windows)
```
python -m venv memo
.\memo\Scripts\activate
```

## ライブラリインストール
今回利用するtkinterは標準ライブラリのため、今回特にインストールする必要はありません。

## アプリ作成
### 1.枠組み作成
まずは以下のような中身のないアプリを作成します。
![](https://storage.googleapis.com/zenn-user-upload/4d832e6eff56-20230121.png)
```python
import tkinter as tk

root = tk.Tk()
root.mainloop()
```
### 2.文字入力設定
文字を入力できるようにします。
![](https://storage.googleapis.com/zenn-user-upload/06a439e1410e-20230121.png)
お試し入力
![](https://storage.googleapis.com/zenn-user-upload/7dd750466a53-20230121.png)
```python
import tkinter as tk

root = tk.Tk()
root.title("メモ帳")

text_widget = tk.Text(root)
text_widget.pack()
root.mainloop()
```
### 3.中身のないボタンを設置
![](https://storage.googleapis.com/zenn-user-upload/2860bf00aa44-20230121.png)
```
import tkinter as tk

root = tk.Tk()
root.title("メモ帳")

text_widget = tk.Text(root)
text_widget.pack()

save_button = tk.Button(root, text="名前を付けて保存", command='')
save_button.pack(side=tk.LEFT)
open_button = tk.Button(root, text="開く", command='')
open_button.pack(side=tk.LEFT)

root.mainloop()
```

### 4.完成
![](https://storage.googleapis.com/zenn-user-upload/35ee9458686f-20230116.png)
```python
import tkinter as tk
from tkinter import filedialog

def save_file():
    file = filedialog.asksaveasfile(mode='w', defaultextension=".txt")
    if file:
        text_content = text_widget.get("1.0", tk.END)
        file.write(text_content)
        file.close()

def open_file():
    file = filedialog.askopenfile(mode='r', defaultextension=".txt")
    if file:
        text_widget.delete("1.0", tk.END)
        text_widget.insert("1.0", file.read())
        file.close()

root = tk.Tk()
root.title("メモ帳")

text_widget = tk.Text(root)
text_widget.pack()

save_button = tk.Button(root, text="名前を付けて保存", command=save_file)
save_button.pack(side=tk.LEFT)
open_button = tk.Button(root, text="開く", command=open_file)
open_button.pack(side=tk.LEFT)

root.mainloop()
```

## exe化
```
pyinstaller memo.py --hidden-import=tk-inter --onefile --noconsole
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2465378/2f7168e9-3866-3f60-19bb-5126ee5e7843.png)