■
Go言語で順列を実装
permute.go
package main func Permute(nums []int) [][]int { ans := calc(nums) return ans } func calc(nums []int) [][]int { if len(nums) == 0 { return [][]int{} } var ans [][]int for i := range nums { arr := []int{} for j := range nums { if i != j { arr = append(arr, nums[j]) } } childs := calc(arr) if len(childs) == 0 { ans = append(ans, []int{nums[i]}) return ans } for _, child := range childs { pattern := append([]int{nums[i]}, child...) ans = append(ans, pattern) } } return ans }
main.go
package main import ( "fmt" ) func main() { nums := []int{1, 2, 3} for _, v := range Permute(nums) { fmt.Println(v) } }
実行結果
[1 2 3] [1 3 2] [2 1 3] [2 3 1] [3 1 2] [3 2 1]
inline-blockで上寄せさせたい時
はじめに
inline-block
で横並びさせる時、要素の高さがバラバラだと一番高い要素の下面に合わせて配置される。
上寄せさせたいため、その方法を記載する。
方法
inline-block
なのでvertical-align
が使用できる。
以下のように記載することで上寄せすることができる。
クラス名 { display: inline-block; vertical-align: 'top'; }
参考文献
laravel passportでユーザー情報を取得(laravel6)
はじめに
laravelを学習し始めたのでlaravel passportを利用してユーザー情報の取得を行った
ログイン機能の作成部分まではlaravelのドキュメントを流用しているのでそちらをみるとより正確な情報を得ることができるので、ぜひそちらを見てください
環境
- laravel 6.5.1
- mysql 5.7
手順
laravel passportのパッケージをインストール
$ composer require laravel/passport
クライアントとアクセストークンを保存しておくためのテーブルを作成
$ php artisan migrate
App\User
モデルにLaravel\Passport\HasApiTokens
トレイトを追加する
<?php namespace App; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Laravel\Passport\HasApiTokens; // 追加 class User extends Authenticatable { use HasApiTokens, Notifiable; // HasApiTokensを追加 }
AuthServiceProvider.php
内でアクセストークンの発行、失効のためにPassport::routes
メソッドを呼び出す
<?php namespace App\Providers; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; use Illuminate\Support\Facades\Gate; use Laravel\Passport\Passport; // 追加 class AuthServiceProvider extends ServiceProvider { /** * アプリケーションのポリシーのマップ * * @var array */ protected $policies = [ 'App\Model' => 'App\Policies\ModelPolicy', // 最初はコメントされているのでコメントを削除する ]; /** * 全認証/認可サービスの登録 * * @return void */ public function boot() { $this->registerPolicies(); Passport::routes(); // 追加 } }
config/auth.php
内のガードのapi
認証のdriver
オプションをtoken
からpassport
に変更する
'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'passport', // token => passport 'provider' => 'users', ], ],
アクセストークンを生成するために必要な暗号キーの作成
$ php artisan passport:install
コントローラーの作成
$ php artisan make:controller Api/AuthController
Api/AuthControllerにloginメソッドを作成
<?php namespace App\Http\Controllers\Api; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Http\JsonResponse; class AuthController extends Controller { public function login(Request $request): JsonResponse { $credentials = $request->only('email', 'password'); if (Auth::attempt($credentials)) { $user = Auth::user(); $token = $user->createToken('Laravel Password Grant Client')->accessToken; return new JsonResponse(['token' => $token], 200); } return new JsonResponse([ 'message' => 'Unauthenticated.' ], 401); } }
Route::post('/login', 'Api\AuthController@login');
ユーザーの作成
$ php artisan tinker $ $user = new App\User; $ $user->name = 'testuser'; $ $user->email = 'test@email.com'; $ $user->password = Hash::make('testtest'); $ $user->save();
Tokenをリクエストする
$ curl -X POST http://localhost:8000/api/login -d email=test@email.com -d password=testtest
レスポンス
{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiI2IiwianRpIjoiZmU1YWE4OGY1MTRkYzdmZDUyOTlkYzMyZDE3NmIwNGM0YWE0MDRhNWZkMzBkYmFmYjJhYzExMDhiYWNkNDJiOTc0ZDY4OTQ1MWU5MTcwYWMiLCJpYXQiOjE1NzQwOTI4MjMsIm5iZiI6MTU3NDA5MjgyMywiZXhwIjoxNjA1NzE1MjIzLCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.B6FoP_dLWwCN9S17WxMUplPKVZyLwaW7zIRzVJJm-sFlCQ65JOxtGYgsVWeAHmadnmwOJ3yL3Yz1mHHpBFk9ZFD3mGy23UQIqGM71JUyrvjrAlDLmiyqNGz1PUM-7_ta3FM4-KDn7OWCiUnYHZMWJtylP9wvQ8b3ArglC4DeaQxgGvCQS7_vavB1_o0I7kEkqRjHuXl0-7I_w9E2FQXJHrw7tFPdznAy6rkeOYMLKdDEvAOdSlNXCwwhiARPFWiTk7NaBAlfa0Wjf8MeJSFIlUf9AiJo7lLu8r28A4Miik7J_Y9dRxipUcdCjiz7gPjPqFXeeqhH1NQk_qC-6Fy2u2xzx6pAU-Lu1vp32TANn9ZQ5Vn0xFxJJBTJ0FoOzqcQ44fb5T93K9sCIc_1L_X75K3g5KsY96N4h_bZr84e_VUvB_WHQ0iq8VJO2F-Lj1tsSJiUOUwepB1d2eIWbFzWTc1Ur56crUoBr27GoilhFT-8qp5Md2qoOeottu5qO1v5ybOj9DGZIKeZVN_z4L4awb-IuseMGQQCbfquMNmBaLAmgFTlhA3usoiArp9sX4WC1uphf9u9bhAr5tCiqdeVI5K-lLo_qESfP_Zney2IZtmLNCrNpjwxk7BJA7Sl4oI0clUYg-NJnrhRIRW7DHg1Z7eHZsaItDORCkr78HMlHr4"}
Tokenからユーザー情報を取得
$ curl -X GET http://localhost:8000/api/user -H 'Content-Type: application/json' -H 'Authorization: Bearer 取得したToken'
レスポンス
{"id":1,"name":"test","email":"test@email.com","email_verified_at":null,"created_at":"2019-11-18 10:56:18","updated_at":"2019-11-18 10:56:18"}
以上でユーザー情報の取得をできるようになりました。
参考文献
Vue.js 学習記録2
はじめに
watchでdataを更新する方法
概要
$dataを使用してdataの更新を行う。
watch: { userForm: { handler: function (fromUserForm, toUserForm) { this.$data.validEmail = validateEmail(fromUserForm.email) }, deep: true } },
Vue.js 学習記録1
はじめに
Vue.jsでpropsを使っていてネストしたオブジェクトのkeyが存在するかを判定する方法について記録
実装方法
export default 外にpropsで必須のkeyを指定する
const propsDefault = () => ({ id: 1, name: '', body: '' })
props内でvalidatorを設定する
props: { item: { type: Object, validator: v => { return Object.key(v).sort().join() === Object.keys(propsDefault).sort().join() } } }
これでpropsで受け取ったネストしたオブジェクトのkeyが存在するかを判定できる
UbuntuでもMacみたいにトラックパッドでワークスペースを変える
はじめに
ノートパソコンにUbuntuを入れたけどMacみたいにトラックパッドでワークスペースが切り替えれない。 なのでトラックパッドでワークスペースを切り替えれるようにしました。
環境
パッケージのインストール
# ユーザーをinput groupに入れる $ sudo gpasswd -a $USER input # ライブラリをインストール $ sudo apt install xdotool wmctrl libinput-tools # クローンとインストール $ git clone http://github.com/bulletmark/libinput-gestures $ cd libinput-gestures $ sudo ./libinput-gestures-setup install
PCを再起動する
$ touch ~/.config/libinput-gestures.conf
中身は以下のようにした
gesture swipe left 4 xdotool key alt+control+Down gesture swipe right 4 xdotool key alt+control+Up
libinput-gestures-setup restart
を実行して再読込する。
これで4つ指でワークスペースを切り替えることができるようになりました。
Javascriptでメモ帳作成 クソコードを書いてしまった
はじめに
Javascriptの勉強をしててそういえばメモ帳作ってないなと思い作ってみました。
しかし、クソコード。
クソコードでも一応記録として残しとく。
作成したもの
作った機能
- 保存機能
- 編集機能
- 削除機能
作れなかった機能
- 選択範囲太字機能
- 選択範囲斜体機能
- 選択範囲下線機能
ソースコード
const MEMO_APP = () => { let currentIndex = 0; // 作業中のインデックス番号 class Item { constructor(id, title, text) { this.id = id; this.title = title; this.text = text; } } const initState = () => { if (!localStorage.id) { localStorage.setItem('id', 0); } else { Model._stateAll = JSON.parse(localStorage.memos); } } const Model = { _stateAll : [], /** * * @param {String} type * @param {*} arg */ setItem(type, arg) { switch(type) { case 'add': this._stateAll.push(arg); localStorage.setItem('memos', JSON.stringify(this._stateAll)); localStorage.id ++; break; case 'edit': this._stateAll[arg.id - 1].title = arg.title; this._stateAll[arg.id - 1].text = arg.text; localStorage.setItem('memos', JSON.stringify(this._stateAll)); break; default: throw Error('The value of the argument is invalid'); } }, /** * * @param {String} type * @param {*} arg */ removeItem(type, arg) { switch (type) { case 'remove': let count = 0; for (let value of this._stateAll) { if (value.id === arg) { this._stateAll.splice(count, 1); } } console.log(this._stateAll) localStorage.setItem('memos', JSON.stringify(this._stateAll)); break; default: throw Error('The value of the argument is invalid'); } } } /** * イベント */ const setFormEvent = (memoId) => { const form = document.querySelector('form'); /** * 初期化 */ const initForm = () => { form.reset(); currentIndex = 0; } /** * セーブ */ const saveForm = () => { const editTitle = document.querySelector('#editTitle'); const editText = document.querySelector('#editText'); if (!currentIndex) { let memo = new Item(JSON.parse(localStorage.id)+1, editTitle.value, editText.value); Model.setItem('add', memo); } else { let memo = new Item(currentIndex, editTitle.value, editText.value); Model.setItem('edit', memo); } render(); } /** * 削除 */ const trashMemo = () => { console.log(currentIndex) Model.removeItem('remove', currentIndex); initForm(); render(); } /** * セーブイベント */ const saveEvnet = () => { const saveBtn = document.querySelector('.fa-save'); //saveBtn.removeEventListener('click', editForm, { passive: false }); saveBtn.addEventListener('click', saveForm, { passive: false }); } /** * 追加イベント */ const addEvent = () => { const plusBtn = document.querySelector('.fa-plus'); plusBtn.addEventListener('click', initForm, { passive: false }) } /** * 削除イベント */ const trashEvent = () => { const trashBtn = document.querySelector('.fa-trash'); trashBtn.addEventListener('click', trashMemo, { passive: false }); } addEvent(); saveEvnet(); trashEvent(); } const renderMemoList = (value) => { const div = document.createElement('div'); div.classList.add('memo'); div.textContent = `${value.title}`; memoList.appendChild(div); div.addEventListener('click', function () { const editTitle = document.querySelector('#editTitle'); const editText = document.querySelector('#editText'); editTitle.value = value.title; editText.value = value.text; currentIndex = value.id; //setFormEvent(value.id); }) } /** * 描画関数 */ const render = () => { const memoList = document.querySelector('#memoList'); const memos = JSON.parse(localStorage.memos); memoList.textContent = ""; //初期化 for (let value of memos) { renderMemoList(value); } } const start = () => { setFormEvent(); initState(); } start(); if (localStorage.memos) { render(); } } MEMO_APP();
中身について
currentIndexは作業中のメモのidを保持するための変数
idとmemosというkeyで分けている idは最新のid番号の保持の役割をしていて、新規メモ作成時のmemos.idはlocalStorage.idを使う。 localStorageのステートの変更はすべてsetItemメソッドで行っておりModel._stateAllのステートを更新してから行う。
まとめ
どこをどうみてもクソコードすぎる。 初心者の方がまだましなコードが書けそう。 プログラム設計についてしっかり考えないといけないと思いました。