2019年12月16日月曜日
Angular で作られたプロジェクトをPWAにしてみよう。(前編)Angular 7 から 8 へのアップデート
12月 16, 2019
オフィス狛 技術部のKoma(Twitterアカウントの中の人&CEO)です。
すっかりBlogをサボってしまいました。
社内勉強会用の資料作成で、Android&Kotlinにどっぷり浸かっていました。(言い訳)
気を取り直して、今回は久しぶりのAngularです。
弊社、iOSもAndoridもネイティブでゴリゴリ開発しているのですが、実は、プロジェクト的には減少気味です。
やっぱりアプリの申請とか、色々と気にする事が多いのでしょうね。
代わりにSPAのサイトをレスポンシブで作るプロジェクトがかなり増えています。
そんな中、新たな選択肢として、PWAのプロジェクトも増えています。
と言う事で、今回は、「既存のAngularプロジェクトをPWA化する」を備忘録的に記事にします。
【注意】当記事では、事前準備までを説明していて、実際にPWA化までは行っていません。PWA化のみ見たい方は、「Angular で作られたプロジェクトをPWAにしてみよう。(中編)PWA化の実施」をご覧ください
Angular で作られたプロジェクトをPWAにしてみよう。(中編)PWA化の実施
(1)対象のシステム要件
今回やろうとしていることは以下の通りです。・既存のAngularで作られたSPAサイトをPWA用として新たに作成する。(既存のサイトは残す。つまりコピーしてサイト名変更)
・既存のサイトのAngularバージョンは「7」
・最終的には、Chrome デベロッパーツールのAuditsで、正しくPWA化されている事を確認する。
・その他の機能についてのアップデートは行わない(もっとも少ない対応内容でPWAを実現させる)
では、早速、やって行きましょう!
(2)サイト名(プロジェクト名)変更
まずは、既存のサイト(koma-system-web)をコピーして、名称を「koma-system-pwa」に変更します。サイトのrootディレクトリ名称変更の他に、以下のファイルにもサイト名が記載されているので、合わせて修正します。
angular.json
app.e2e-spec.ts
package.json
(3)Angular 7 から 8 へのアップデート
Angular 8から、CLIによるPWA作成が簡単に出来るようになっているので、まずはAngularのバージョンアップを行います。基本的な作業としては、こちらの手順通りになります。
バージョンは(Angular Version)は、7.0から8.0でいきます。
アプリの複雑度(App Complexity)は・・・・Mediumぐらいですかね、とりあえず。
その他の依存関係(Other Dependencies)ですが、今回のプロジェクトは、AngularJSも混在していませんし、 Angular Material、Express、Hapiも使用していないので、チェックは付けません。
(Express、Hapiは、サーバーサイドレンダリングで使用するものですかね、多分)
パッケージ管理(Package Manager)はnpmを使っているので、npmを選択します。
【更新する前に(Before Updating)】
サイトに記載している手順と注意書き通りに作業を進めて行きます。If you use the legacy HttpModule and the Http service, switch to HttpClientModule and the HttpClient service. HttpClient simplifies the default ergonomics (you don't need to map to JSON anymore) and now supports typed return values and interceptors. Read more on angular.io.HttpModuleは使えないからHttpClientModuleに変更してね、と言う事ですね。
HttpClientModuleは、確かAngular 4.3 ぐらいから使えるようになった機能です。
Once you and all of your dependencies have updated to RxJS 6, remove rxjs-compat.rxjs-compatを使っているなら、削除してね、と言う事ですね。
If you use the Angular Service worker, migrate any versionedFiles to the files array. The behavior is the same.Angular Service workerを使っている場合もマイグレーションを行う必要があるようですが、
今回のプロジェクトでは使用していないので、特に何もしません。
【更新作業(During the Update)】
Update to version 8 of the core framework and CLI by running ng update @angular/cli @angular/core in your terminal早速実行していきます
無事に実行できたら(*1)、プロジェクト内を確認してみましょう。
*1)ちなみに、私が試したプロジェクトでは、いくつかのプラグインがAngular8に対応していませんでしたので、代替のプラグインを取り込んだりして、何度もやり直しました。
Angular now uses TypeScript 3.4, read more about errors that might arise from improved type checking.あれ、アップデート後のpackage.jsonを見ると、typescriptが3.5.3にupdateされているけど、良いのかな・・・?
Make sure you are using Node 10 or later.こちらも念の為確認
$node --version v10.14.1うん、大丈夫そう。
【更新後作業(After the Update)】
では、最後に、「ng update」を実行しますが、その前にちょっと試しに「ng update --all」をやってみました。
すると・・・・
Package "@angular-devkit/build-angular" has an incompatible peer dependency to "typescript" (requires ">=3.1 < 3.6", would install "3.6.3") Package "@angular/compiler-cli" has an incompatible peer dependency to "typescript" (requires ">=3.4 <3.6", would install "3.6.3"). Package "@angular/core" has an incompatible peer dependency to "zone.js" (requires "~0.9.1", would install "0.10.2"). Incompatible peer dependencies found. Peer dependency warnings when installing dependencies means that those dependencies might not work correctly together. You can use the '--force' option to ignore incompatible peer dependencies and instead address these warnings later.色々出てますが、TypeScriptのバージョンで怒られているものはないですね。
3.5.3は大丈夫なんだ・・・。
と言う事で、地道に「ng update」で更新が必要なものを探ります。
$ ng update
Using package manager: 'npm'
Collecting installed dependencies...
Found 54 dependencies.
We analyzed your package.json, there are some packages to update:
Name Version Command to update
--------------------------------------------------------------------------------
@ngrx/store 7.4.0 -> 8.3.0 ng update @ngrx/store
と言う事なので、ひとまず、「ng update @ngrx/store」でngrxだけ上げます。
これで、「ng build」してみると・・・・
An unhandled exception occurred: Could not find the implementation for builder @angular-devkit/build-angular:dev-serverエラーになってしまいました。
と言う事で、「ng update @angular-devkit/build-angular」も実行します。
そして、最後の最後に「npm audit fix」で、脆弱性が発生しているパッケージなどのチェックと修正を同時に行ってしまいます。
これで、「Angular 7 から 8 へのアップデート」は完了です。
と言う事で、すいません、長くなってしまったので、続きは中編に記載します。
(同時に記事公開しますので、許してください)
次回:Angular で作られたプロジェクトをPWAにしてみよう。(中編)PWA化の実施
2019年12月9日月曜日
PHP Conference 2019に行ってきました。
12月 09, 2019
オフィス狛 技術部のmmm(むー)です。
先週のことですが、PHP Conference Japan 2019に行ってきました。
(現在の業務ではPHPは使用しておりませんが…)
・ 公式URL
https://phpcon.php.gr.jp/2019/
・ セッションのタイムテーブル
https://fortee.jp/phpcon-2019/timetable
今年のテーマは 「beyond .*」で、これから先のPHPの未来がさらに飛躍するようにとつけたようです。
今回第20回目を記念して、PHPの像のぬいぐるみが販売されていました。
自由すぎると定評のPHPですが、先月末7.4がリリースされました。
オープイングセッションでは、PHP7.4の新機能の紹介がありまして、型付けプロパティやアロー関数を使用できるようになりました。
次にリリースされるバージョンは8になるようです。
また、5.6も7.1もEOL(End of Life)になったねって話が出てました。あっという間ですね…
カンファレンスに参加する醍醐味は、自分が知らない技術・考え・作者の方の思いを知ることができることだと思います。以下、各セッションの感想になります。
MVCにおける「モデル」とはなにか
天重誠二さんhttps://speakerdeck.com/tenjuu99/what-mvc-is
フレームワークの話をするのかと思っていましたが、概念的な話でした。
ドメインモデルについての話を現実世界で使用している伝票システムにたとえて説明をしていたのが面白かったです。
また、誰にとってのデザインかを考えた上で設計するのは大切ですね。
今回の発表でたくさんの参考文献が紹介されていたのですが、その中の一つ「誰のためのデザイン」は私も以前プログラマーでも読んだ方が良いとデザイナーの方に勧められて読みました。
タイトルの通り誰のためにデザイン(設計)するのかということが、実生活を例に紹介されていてとても面白い本でした。他の参考文献も読んでみたいと思います。
思想と理想の果てに -- クリーンアーキテクチャのWEBフレームワークを作ろう
成瀬允宣さんhttps://nrslib.com/phpcon-2019-proposal/
クリーンアーキテクチャとはフレームワークに依存しないという前提のもと、環境に依存しないフレームワークを作る説明のセッション。クリーンアーキテクチャを採用すれば、どの処理をそこに書いたか悩むことから解放されます。
この発表を他の会場で行った時、似たようなライブラリがあると参加者の方に聞けたので、アウトプットする人のところに情報が集まってくる(アウトプットしよう)とのことでした。
また、フレームワークは変わらないと思っていても、10年15年やってるとフレームワーク変えることはあり、10年後保守してる人達が辛い思いをするからフレームワーク非依存をおすすめしますといった内容でした。
PHPは何を捨て、どんな力を手に入れてきたのか
うさみけんたさんhttps://www.pixiv.net/fanbox/creator/105589/post/691574
PHPを使用していると、PHP5.3を最後にPHP6がスキップされて、次は7になっていることは一目瞭然だと思います。
PHP5.3は、6が開発されるまでの繋ぎで、6でUnicode化等を行うつもりでしたが 開発が止まってしまったのでした…。
現在、他のモダンと言われている言語に追いつくためにPHPは歴史的経緯で残っているレガシーコードを消していこうという動きがあります。
は使用できないよう、PHPから派生したP++を作る…等、今年の夏頃議論が白熱してPHP界隈で炎上していました。
銀河の平和はまだわかりませんが、詳細は調べてみてくださいとのことでした。
PHPUnit: Past, Present and Future
Sebastian Bergmannさんhttps://thephp.cc/dates/2019/12/php-conference-japan/phpunit-past-present-future
PHP Unitの開発者の方のセッションです。別のセッションの関係で、途中から聞きました。
Sebastianさんの誕生やプログラミングを始めたこと、PHPが誕生したこと、PHP Unitの開発を始めたこと順を追って各歴史を順番に振り返えるセッションでした。 PHP4では例外処理がなかったため大変だった等の話を聞いて、私にとってはあって当たり前の機能だったので、その時代の話が聞けて面白かったです。
セッション終了後には、エモかったという感想がTwitterにあふれていました。
ちなみに、PHP Unitのロゴは好きなゲーム、宇野デザイナーさんにお願いしたそうです。
英語でしたが、ゆっくり話してくださっていたので聞きやすかったです。
How to Supercharge your PHP Web API
Aurimas Niekisさん※スライドがアップされていませんでした
私のプログラマーとしてのスキル能力と英語力が足りなくて、内容がわかりませんでした…
セッションが終了した後に、少し対面で話をさせていただいたのですが、Aurimasさんは来年の2月から日本で働き始めるようです。
また、私がNode.jsを今業務で使用していることを伝えると、Node.jsも使っているので質問があればいつでも連絡してねと言ってくださいました。(優しい…)
カンファレンスに参加していると知り合いが少しずつ増えていくので、時々集まる同窓会のようで楽しいです。
来年のPHP Conferenceは2020/10/11に開催されるようですので、都合が合えば参加したいです。
2019年11月30日土曜日
knex.jsで実行したSQL文を確認する。
11月 30, 2019
オフィス狛 技術部のHammarです。以前の投稿で、knex.jsのtipsをいくつか書いたり(Node.jsでknex.jsを使ったSQL書き方Tips)、弊社技術部のmmm(むー)が書いたりしていますが(knex.jsでfromに2つ以上のサブクエリを書く方法)、今回はもう1つ「実行したSQL文を確認する」やり方を書きたいと思います。
これ意外とよく使うのに、やり方がぱっとわからなくて、社内でもどうやるのか質問があったりしたので新たにtipsとして追加したいと思います。
もちろん公式サイトにも載ってはいるのですが、日本語対応されていないのでちょっとわかりずらいんですよね。
で、やり方は単純で、SQL実行文に.toSQL()という記述を追加することで確認可能です。
具体的には
■記述例1
knex
.select('*').from('users')
.where('id = ?', [1]))
.toSQL()
上記の結果を出力すると、
bindings: [1],
method: 'select',
sql: 'select * from "users" where id = ?',
options: undefined,
のように出力されて、バインド値と実際のSQL文を確認することができます。method: 'select',
sql: 'select * from "users" where id = ?',
options: undefined,
ちなみにpostgresqlはSQL実行文に.toSQL().toNative()と記述することで同様の結果が得られるようです。
■記述例2
knex
.select('*').from('users')
.where(knex.raw('id = ?', [1]))
.toSQL().toNative()
出力結果
bindings: [1],
sql: 'select * from "users" where id = $1',
sql: 'select * from "users" where id = $1',
自分も最初はこのやり方を知らずに、デバッグでステップ実行してどこでSQL作っているのかずーっと奥の方まで追って行って、確認するのに結構苦労してました(苦笑)
以上のように知ってしまえば簡単なんですが、知らないとかなりやりずらいので、ご参考にしてみてください。
SpringBoot「1.5」を「2.1」へバージョンアップ。
11月 30, 2019
オフィス狛 技術部のJoeです。
SpringBoot 1系が2019/8/1にEOLになり、担当しているプロジェクトもバージョンアップ要件(1.5 → 2.1)がありました。
バージョンアップで対応した内容の一部をご紹介します。
① application.ymlファイルのエラー
非推奨となったプロパティが大量に出てきました。こちらは全てメッセージに従いキー名を変更することで解決しました。【参考)メッセージ】
Property 'spring.thymeleaf.content-type' is Deprecated: Use 'spring.thymeleaf.servlet.content-type' instead. Property 'server.session.timeout' is Deprecated: Use 'server.servlet.session.timeout' instead. Property 'spring.messages.cache-seconds' is Deprecated: Use 'spring.messages.cache-duration' instead. Property 'spring.http.multipart.max-file-size' is Deprecated: Use 'spring.servlet.multipart.max-file-size' instead. Property 'spring.http.multipart.max-request-size' is Deprecated: Use 'spring.servlet.multipart.max-request-size' instead. Property 'spring.datasource.initialize' is Deprecated: Use 'spring.datasource.initialization-mode' instead.
② Beanオーバーライドが無効
次に下記エラーが発生しました。The bean 'XXX', defined in class path resource [XXX.class], could not be registered. A bean with that name has already been defined in class path resource [XXX.class] and overriding is disabled.
SpringBoot 2系では、Beanオーバーライドがデフォルトで無効になったようです。
メッセージのActionに従い、application.ymlファイルに下記を追記しました。
spring.main.allow-bean-definition-overriding: true
③ 非推奨、廃止、構成変更のパッケージ
非推奨、廃止、構成変更になったパッケージがいくつかありましたので、下記のように修正しました。■非推奨
【変更前】
import org.hibernate.validator.constraints.NotBlank; import org.hibernate.validator.constraints.NotEmpty;【変更後】
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotEmpty;
■廃止
【変更前】
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
public class MessageConfig extends WebMvcConfigurerAdapter { ・・・
【変更後】
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
public class MessageConfig implements WebMvcConfigurer { ・・・
■構成変更
【変更前】
import org.springframework.boot.web.support.SpringBootServletInitializer;【変更後】
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
④ application.ymlファイルから@ConfigurationPropertiesで値が設定されない
こちらは動作確認をして気が付いたのですが、@ConfigurationPropertiesアノテーションを付けたクラスでsetterメソッドがstaticだと、application.ymlファイルから値を設定できなくなってしまいました。下記のように非staticなメソッドに変更することで無事設定されました。
@Component
@ConfigurationProperties(prefix = "outerconf")
public class OuterConf {
private static String rootdir;
public static String getRootdir() {
return rootdir;
}
// 非staticに変更
public void setRootdir(String rootdir) {
OuterConf.rootdir = rootdir;
}
}
SpringBootのバージョンアップはたくさんの方が記事にされていますが、環境によって対応が異なるとは思いますので、何かお役に立てれば幸いです。
2019年11月29日金曜日
「コンテンツに応じた塗りつぶし」で写真の不要なものを消す。
11月 29, 2019
こんにちは、オフィス狛 デザイン部のSatoです。
今回はPhotoshopCC2019から機能が強化された「コンテンツに応じた塗りつぶし」という機能を使って写真から不要なものを消す方法をご紹介しようと思います。
この機能を使うとあのAdobe Senseiが数分で遠目で見る分には問題ないくらいに自然に選択した部分の中身を近くの部分そっくりにしてくれます。
https://unsplash.com/photos/Osd4ngHD4kM
↑今回はこの写真から中央に立っている人物を消してみます。
とっても綺麗な写真ですが今は無人の廃墟の写真が欲しいので女の子にはどいてもらいましょう……。
まず、消したいものを選択していきます。
精密に消したい方は自動選択ツールなどがいいかと思いますが、今回はなげなわツールでざっくり選択しました。
選択後、Photoshopメニューバーの「編集」の「コンテンツに応じた塗りつぶし」をクリックします。
コンテンツに応じた塗りつぶしツールのワークスペースが表示されます。
左が編集画面、右がプレビュー画面です。
緑になっている部分はサンプリングされる(人工知能が参考にする)部分です。
右上のサンプリングブラシツールを使って緑の部分を微調整していきます。
サンプリング箇所の拡張と削除のブラシの切り替えは上部のサンプリングブラシツールのオプションの+と-のアイコンでも切り替えできます。またOptionかAltキーを押しっぱなしにしても切り替えができます。
消したい選択範囲を広げたい場合なげわツールで追加しましょう。
プレビュー画面で確認しつつ、いい感じになったら右下にあるOKボタンを押すと通常のワークスペース画面に戻り、(右にある出力先設定の値が初期設定の「新規レイヤー」になっている場合)修正した部分の新しいレイヤーができています。
違和感があまりなく人物が消えましたね!
しかし拡大しよく見ると、木と石が合体したような瓦礫などができあがってしまっていたり少し違和感があります。
拡大すると意外と気になりますね…。
このような気になる部分はコピースタンプツールで微調整をします。
全体的に見ると少し違いが分かりづらいので比較画像にまとめてみました。
この方法で修正した後の画像がこちらです。
遠目だと分かりずらいですが、比較画像の通り変になっている部分と人物の影をコピースタンプツールで消しました。
拡大しても大丈夫なくらいに違和感が減りました!
「コンテンツに応じた塗りつぶし」のみで完璧なものができる訳ではなさそうですが、コピースタンプツールやパッチツールで修正するよりもかなり手早く「遠目で見ると違和感ないレベルまで」修正できて感激です。
他の空の写真と組み合わせて夕暮れの写真を作ってみました。
この写真の空の部分のみトリミングし使いました。
色々と細かい調整が大変で人物を消す+微調整の10倍以上の時間がかかってしまいました。
つまり「コンテンツに応じた塗りつぶし機能」は本当に素早く人物を消すことができます!
コピースタンプツールで人や邪魔なものをチマチマ……消さなくていいのは本当にありがたいですね……。
Adobeのマニュアルに「コンテンツに応じた塗りつぶし」機能の詳しい使い方が書いてあるのでそちらもチェックしてみてください。
今回のブログ記事に使用した写真は全てUnsplashというフォトストックサイトのものを使わせていただきました。
Unsplashに掲載されている写真は無料かつクレジット不要で写真加工や商業利用可なのでデザイナー的に非常にありがたいサイトです。
More precisely, Unsplash grants you an irrevocable, nonexclusive, worldwide copyright license to上記の通り利用規約が非常に緩い+Unsplash APIというなにやら便利なものもあるらしいのでTrelloなどのwebサービスも写真をよく使っているようです。
download, copy, modify, distribute, perform, and use photos from Unsplash for free, including for
commercial purposes, without permission from or attributing the photographer or Unsplash.
This license does not include the right to compile photos from Unsplash to replicate a similar or competing service.
Licenseページより引用
今回使用した写真含め、とても綺麗な写真が多いので見ているだけでも楽しいサイトですので、ぜひ活用してみてください。
2019年11月28日木曜日
knex.jsでfromに2つ以上のサブクエリを書く方法。
11月 28, 2019
オフィス狛 技術部のmmm(むー)です。
今回初投稿になります。
業務ではNode.jsを使用してAPI作成をしています。
今回は、Node.jsでDB操作を行う為のknex.jsと言うクエリビルダにて、from句に2つ以上のサブクエリを記載する方法を記載します。
SQL自体はなんてことないものですが、knex.jsでの書き方がわからず検索するのに時間がかかったため備忘録も込めて。
■実行環境
// node
node -v
// v10.16.3
// Knex.js
npm list --depth=0 | grep knex
// knex@0.15.2
// SQL Server
SELECT @@VERSION
// Microsoft SQL Server 2017 (RTM-CU13) (KB4466404) - 14.0.3048.4 (X64) Nov 30 2018 12:57:58 Copyright (C) 2017 Microsoft Corporation Developer Edition (64-bit) on Linux (Ubuntu 16.04.5 LTS)
■書き方
結論から記載すると、半直書きするしかありません。ちなみにこの方法に従わなくても全て直書きする方法もあります。
const subQuery1 = knex.select('id').from('table1');
const subQuery2 = knex.select('name').from('table2');
knex
.select('*')
.from(
knex.raw([
knex.raw(subQuery1).wrap('(', ') as sub_1'),
knex.raw(subQuery2).wrap('(', ') as sub_2'),
]),
);
説明
・ knex.raw そのままのSQLを書くことが可能
・ wrap knex.rawの中で使用でき、クエリをラッピング(クエリの前後に何か挿入)できる
以上となります。
またknex.jsについて調べたことがあれば、都度更新していこうと思います。
2019年10月31日木曜日
Windows ServerでApacheを2.4.41へアップデートする。
10月 31, 2019
オフィス狛 技術部のJoeです。
数か月前になりますが、Apache HTTP Web Server 2.4系における複数の脆弱性に対応した Apache HTTP Web Server 2.4.41 が公開されました。
https://www.apachelounge.com/
担当したプロジェクトのWindows Serverがアップデート要のバージョンであったため、Apacheのアップデートを行ったのですが、「インストーラーをダウンロードして実行」のように簡単にはいかなかったので、備忘も兼ねて記事にしてみました。
アップデートを実施した環境は以下になります。
※OSやバージョンにより手順が異なる場合があるのでご注意ください。
OS:Windows Server 2012 R2
Apache:2.4.29 → 2.4.41
Apacheのアップデート
①Apacheのダウンロード
下記サイトよりダウンロードします。https://www.apachelounge.com/
[手順]
左のメニューから「Downloads」を選択
→ ビルドバージョン(VCxx、VSxx など)を選択
→ 対象のApacheバージョンを選択してダウンロード
※ビルドバージョンの「VCxx、VSxx」は、ビルドされたVisual Studioのバージョンになるので、ご利用の環境により選択してください。
・VC14:Visual Studio C++ 2015
・VC15:Visual Studio C++ 2017
・VS16:Visual Studio C++ 2019
②アップデート前Apacheバックアップ
アップデート前の「Apache24」フォルダを別の場所へバックアップしておきます。※アップデート後に、ソースや設定ファイル等を移行します
③コマンドプロンプト起動(管理者)
コマンドプロンプトを管理者として実行します。④Apacheアンインストール
コマンドプロンプトで下記のコマンドを入力し、Apacheを停止してアンインストールします。cd [Apacheのインストール先フォルダ]\bin httpd -k shutdown httpd -k uninstall
⑤Apacheフォルダ配置
上記①でダウンロードしたファイルを解凍した新しいバージョンの「Apache24」フォルダを、Apacheのインストール先フォルダに配置します。(旧バージョンのフォルダはバックアップしているので、私はこのタイミングで削除しました)⑥インストール
コマンドプロンプトで下記のコマンドを入力し、Apacheをインストールします。cd [Apacheのインストール先フォルダ]\bin httpd -k install
⑦設定ファイル反映
ソースや設定ファイルを、アップデート後の「Apache24」フォルダに移行します。⑧Apacheスタート
コマンドプロンプトで下記のコマンドを入力し、Apacheをスタートします。cd [Apacheのインストール先フォルダ]\bin httpd -k start
⑨バージョン確認
コマンドプロンプトで下記のコマンドを入力し、Apacheをスタートします。cd [Apacheのインストール先フォルダ]\bin httpd -v以下のように出力され、正しくアップデートされました。
C:\Program Files\Apache Software Foundation\Apache24\bin>httpd -v Server version: Apache/2.4.41 (Win64) Apache Lounge VC14 Server built: Aug 12 2019 10:48:01
⑩サービスの設定を確認
Apacheの自動起動などを設定している場合は、念のためサービスで設定を確認しておきます。以上でアップデートが完了になります。
登録:
投稿 (Atom)









