Pulseaudioが起動しなくなった時の対処法

Windows 11で動かしていたPulseaudioが以下の通りエラーとなって起動しなかった。

W: [(null)] pulsecore/core-util.c: Secure directory creation not supported on this platform.
W: [(null)] pulsecore/core-util.c: Secure directory creation not supported on this platform.
W: [(null)] pulsecore/core-util.c: Secure directory creation not supported on this platform.
E: [(null)] pulsecore/pid.c: Daemon already running.
E: [(null)] daemon/main.c: pa_pid_file_create() failed.

pidファイルが削除されず残っていることが、エラーの原因らしい。ctrl+cを使わずに×ボタンでウィンドウを閉じるとファイルが残ってしまうとのこと。

自分の環境では、他のサイトで指定されていたフォルダにpidファイルは無く、下記のフォルダにpidファイルが作成されていた。下記のファイルを削除したらPulseaudioが正常に起動するようになった。

%USERPROFILE%\.config\pulse\%USERDOMAIN%-runtime\pid

WSL2 UbuntuでUSB デバイスを使用する

  1. usbipd-win プロジェクトの最新リリースのページにあるmsiファイルをダウンロードする
  2. ダウンロードした usbipd-win_x.msiファイルを実行する

WSL2のコンソール上で以下のコマンドを実行する。インストールするバージョンは自身の環境とあわせる。

sudo apt install linux-tools-5.15.0-33-generic hwdata
sudo update-alternatives --install /usr/local/bin/usbip usbip /usr/lib/linux-tools/5.15.0-33-generic/usbip 20

PowerShellを管理者として実行する。下記のコマンドを実行し接続されているUSBデバイスのリストを取得する。

usbipd wsl list

BUSID  VID:PID    DEVICE 
3-4    328f:2013  HD Webcam eMeet C960, USB 入力デバイス 

使用したいUSBデバイスのBUSIDを、下記コマンドで割り当てする。

usbipd wsl attach --busid 3-4

WSL2のコンソール上で下記コマンドを実行し、先ほど割り当てたUSBデバイスが表示されることを確認する。

lsusb

Bus 001 Device 002: ID 328f:2013 SHENZHEN EMEET TECHNOLOGY CO.,LTD. HD Webcam eMeet C960

使用し終わったら、下記コマンドで割り当てを解除する。

usbipd wsl detach --busid 3-4

wsl2の仮想ハード ディスク (VHD) ファイルの物理サイズを減らす

色々実験していたら、VHDファイルサイズがかなり大きくなってしまったため、以下のコマンドで物理ファイルを減らす対応を行った。

wsl --shutdown
diskpart

# open window Diskpart
select vdisk file="C:\Users\ユーザーID\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_~~~\LocalState\ext4.vhdx"
attach vdisk readonly
compact vdisk
detach vdisk
exit

Vuexで検索条件を保持する

やりたいこと

検索条件を保持し、当該画面に戻ってきたときに、前回の検索条件を表示する。

コード例

Vuexで呼び出される処理を定義していく。
※細かいところは省略済み。

//ファイルパス:modules/novel/search.js
const state = {
  searchParameter: {
    title: '',
    writername: '',
    description: ''
  }
}

const getters = {
  getSearchParameter: state => state.searchParameter
}

const actions = {
  // 検索処理
  [NOVEL_SEARCH]: ({ commit }, param) => {
    return new Promise((resolve, reject) => {
      // 検索条件をstateに保存する処理を呼び出す(下記のcommitでmutationsのNOVEL_SEARCHが実行される)
      commit(NOVEL_SEARCH, param)
      novelRepository.get(searchParameterBuilder(param))
      .then(resp => {
        commit(NOVEL_SEARCH_SUCCESS, resp)
        resolve(resp)
      })
      .catch(err => {
        commit(NOVEL_SEARCH_ERROR)
        reject(err)
      })
    })
  }
}

const mutations = {
  [NOVEL_SEARCH]: (state, param) => {
    state.searchParameter = param
  }
}

export default {
  state,
  getters,
  actions,
  mutations
}
import { createStore } from 'vuex'
import novelSearch from './modules/novel/search'

export default createStore({
  modules: {
    novelSearch
  }
})

vueファイルから以下の通り呼び出して、使用する。(記事の都合上、分けて記載しているけど、本来1つのファイル)

<script setup>
import { reactive, computed } from 'vue'
import { useStore } from 'vuex'
import { useI18n } from 'vue-i18n'
import { ElMessage, ElMessageBox } from 'element-plus'

const store = useStore()
const { t } = useI18n()

// Vuexに保持されている検索条件を読み込む
const searchParameter = computed(() => store.getters.getSearchParameter)

const state = reactive({
  title: searchParameter.value.title,
  writername: searchParameter.value.writername,
  description: searchParameter.value.description
})

function search() {
  const { title, writername, description } = state
  // 検索処理を実行する(search.jsのactionsのNOVEL_SEARCHが実行される)
  store.dispatch(NOVEL_SEARCH, { title, writername, description }).catch(error => {
    ElMessage({
      message: error,
      grouping: true,
      type: 'error'
    })
  })
}
</script>
<template>
  <div class="novel-search">
    <el-card class="box-card box-card-wrapper">
      <el-row class="row-wrapper">
        <el-col
          class="col-wrapper"
          :span="6"
        >
          <el-input
            :placeholder="$t('title')"
            v-model="state.title"
            clearable
          />
        </el-col>

JenkinsでwarファイルをTomcatにデプロイする

前提

ビルドが成功して、warファイルが作成されること。

プラグインのインストール

JenkinsのPlugin ManagerでDeploy to container Pluginをインストールする。

ビルド後の処理の追加

Deploy war/ear to a containerを追加する。

Warファイルのパス、コンテキスト名を設定する。

Built-in Tomcat manager rolesで、manager-scriptに設定した、ユーザー名、パスワードをCredentialsに設定する。

JenkinsでMavenの実行結果のレポートを作成する

Mavenのインストール

sudo apt install maven
mvn --version

レポート作成でよく使うプラグインをインストールする

JaCoCo plugin: JaCoCoコードカバレッジレポートをJenkinsに統合する。

Warnings Next Generation Plugin: 静的分析ツールによって報告されたコンパイラの警告または問題を収集し、結果を視覚化する。(自分はspotbugs、checkstyleで使用)

Jenkinsの設定

ビルドにMavenの呼び出しを追加する。

package site

ビルド後の処理に以下の項目を追加する。

1.JUnitテスト結果の集計
target/surefire-reports/*.xml


2.JaCoCoカバレッジレポートを記録


3.Javadocの保存


4.CheckStyleとSpotBugsの解析結果を保存

GithubにコミットしたらJenkinsで自動的にビルドされるようにする

Jenkins側の設定

グローバルセキュリティの設定

ログインしていない場合でも、jenkinsにリードオンリーでアクセスできるように設定する。

ジョブを作成する

GitHub projectにチェックし、GitHub上のプロジェクトのURLを設定する。同時にソースコード管理にもURLを設定する。公開レポジトリであれば認証情報は入力不要。

GitHub hook trigger for GITScm pollingにチェックを入れる。

上記でジョブを作成する。これでジョブを自動的に起動する準備が出来たので、後はプロジェクトの要件に合わせてビルドやテストが起動するように、カスタマイズすれば良い。

GitHub側の設定

連携するプロジェクトのSettingsを開きWebhookを作成する。Payload URLにはJenkinsのURL+「/github-webhook/」を指定する。Content typeにはJSONを指定する。

動作確認

GitHubに変更がpushされると、Jenkinsのジョブが起動することが確認できる。

Mavenでのビルド、そのビルド後の処理について

Mavenのビルド、Mavenのビルド処理で作成したJavadoc等をJenkinsプロジェクトのメニューに表示されるようにする方法はこちら

Vue Composition APIを試す

Composition APIを使用すれば、同じ論理的な関心事に関連するコードを並べることが出来る?可読性が良くなる?良くわからないけど、前にVue 2で書いたコードを書き換えてみる。

このドキュメントでは実際にどのように変更したかをメインに記載する。

ログイン画面(Login.vue)の例

・Vue 2
一見シンプルに見えるけれども、thisで参照するものが多すぎて、何が使えて、何が使えないのか、後から見るとわかりづらい。

<script>
import {AUTH_REQUEST} from '@/store/actions/auth'

export default {
  data () {
    return {
      username: '',
      password: '',
    }
  },
  methods: {
    login: function () {
      const { username, password } = this
      this.$store.dispatch(AUTH_REQUEST, { username, password }).then(() => {
        this.$router.push(this.$route.query.redirect || '/')
      }).catch(error => {
        this.$message({
          showClose: true,
          message: error,
          type: 'error'
        })
      })
    }
  }
}
</script>

・Vue 3.2
Vue 2で必要だった独特な書き方がなくなって、一般的なJavaScriptの書き方になっている。インポート、宣言部、関数とわかれていて、わかりやすくなっているように感じる。

<script setup>
import { reactive } from 'vue'
import { useStore } from 'vuex'
import { useRouter, useRoute } from 'vue-router'
import { ElMessage } from 'element-plus'
import { AUTH_REQUEST } from '@/store/actions/auth'

const store = useStore()
const router = useRouter()
const route = useRoute()

const state = reactive({
  username: '',
  password: ''
})

function login() {
  const { username, password } = state
  store.dispatch(AUTH_REQUEST, { username, password }).then(() => {
    router.push(route.query.redirect || '/')
  }).catch(error => {
    ElMessage({
      message: error,
      grouping: true,
      type: 'error'
    })
  })
}
</script>

Raspberry Pi 4 Model Bを設定する

やりたいこと

Raspberry Pi OS動かして、デスクトップ画面を表示する。

Raspberry Pi 4を購入する

今は品薄で、なかなか手が入らない。仕方がないので必要なものが揃っている下記を購入した。

Raspberry Pi OSをインストールする

下記からRaspberry Pi Imagerをダウンロードしてインストールする。
https://www.raspberrypi.com/software/

SDカードを挿入し、Raspberry Pi Imagerを起動して、OS選択し下記の通り実行する。

OSをインストールしたSDカードをRaspberry Piに挿入し電源を入れる。

※4/21追記
コンパクトなキーボードとマウスが欲しかったので下記を購入した。USBレシーバーも付属しているので、互換性を気にしなくて良く、すぐ使用できる点が気に入った。

element-ui 2からelement-plus 2にアップグレードする

今まではelement-ui 2を使用していたが、今後はVue 3に対応しているelement-plus 2を使用する。変更点のメモを残しておく。

element-ui 2の依存関係

"element-ui": "^2.15.6",

element-plus 2の依存関係

"@element-plus/icons-vue": "^1.1.4",
"element-plus": "^2.1.8",

element-ui 2の初期設定

import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui'
import locale from 'element-ui/lib/locale/lang/ja'
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(ElementUI, {locale})

new Vue({
  render: h => h(App)
}).$mount('#app')

element-plus 2の初期設定

import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import locale from 'element-plus/lib/locale/lang/ja'
import 'element-plus/dist/index.css'

const app = createApp(App)

app.use(ElementPlus, {locale})

app.mount('#app')