CSSアニメーションでHTML用をスクロール時に表示する
1
プラグインを使わずに多彩な動作を実現します.
アニメスタ
アニメスタはPluginではなく,Web上でcssを表示するWebページです.
cssで動作を実装するのではなく,
https://animista.net/play/basic/slide/slide-bottom
##
1
プラグインを使わずに多彩な動作を実現します.
アニメスタはPluginではなく,Web上でcssを表示するWebページです.
cssで動作を実装するのではなく,
https://animista.net/play/basic/slide/slide-bottom
##
1
Avadaで,アイコンが上手く表示されないバグを直します.SSL化によるもの,CORSポリシーに関するもの,キャッシュに由来するものの3つの原因があります.
.htaacessでCORSを許可するコマンドを入れます.
# Apache config
<FilesMatch ".(eot|ttf|otf|woff)">
Header set Access-Control-Allow-Origin "*"
</FilesMatch>
キャッシュを削除します,
何らかの原因でフォントだけ非SSL通信で読み込んでいる場合,ブラウザ側でブロックすることがあります.この場合,「Better Search Replace」などのプラグインを使ってhttp://
を https://
で置き換えてください.
XserverのWordPress簡単インストールを使っているとフォントだけhttp://
で読み込んでしまう問題が発生します.簡単インストールの場合,「Better Search Replace」を使った対応では上手くいきません.WordPressを手動でインストールすると上手くいきました.
1
Avadaをはじめとする海外テーマでは,デモサイトをインポートできます.デモサイトはかなりの数用意されていますが,その中から自分が作りたいイメージに近いものをインポートした後,カスタマイズしてサイトを作成するという流れが一般的です.
デモサイトの実態は,そのテーマ(例えばAvadaやEnfoldなど)で作られた固定ページや投稿ページです.テーマそのもので手動で同じものを作れるのですが,手間を省くために用意されております.
ここでは,Avadaのおすすめのデモサイトを紹介します.
シンプルなもので良いならこれがおすすめ.
ダサくない程度に動きもあって,構成もシンプルなのでカスタマイズ示唆そうです.
印象の強いランディングページならこちらがおすすめです.
動きがあって,読者は自然にスクロールしてしまうと思います.用意する写真の数も少なくて良ささそうです.製品,アプリなど幅広く使えます.
・イベント向けのサイトを作りたいなら動画を多用するこちらがいいです
写
・明るい印象のサイトです.少し古めのデザインですが,みやすくて親しみやすいです.
写
用意できる写真がたくさんある人限定になってしまうのが難点です.
・個人的には一番使いやすくておすすめです.
・ミニサイトでおすすめのデモデザインです.
・力強いサイトを作りたいならこれ.
個人的には好きです.
#
ヨガ教室を開くならこのサイトはかなりおすすめです.
1
WordPressの有料テーマで一番人気のAvadaでWebサイトを構築する際,特定のコンテナがモバイルで表示されない問題に直面しました.
Avadaでは,コンテナごとにRendering Logicでデバイスや引数,ユーザーロールなどに応じて表示するかどうかを決めることができます.デフォルトのテーマでは,Rendering Logicでデバイスタイプがモバイルではない場合に表示,となっていたりします.PCでは表示されるのにモバイルでは表示されない,というトラブルに遭遇した時には下記の対応で解決します.
まず,該当の固定ページに行きます.
表示されないコンテナを編集するために,鉛筆ボタンを押して編集画面を出します
ExtrasタブでRendering logicのところで,Device Typeが指定されているので,これを削除します.
Avadaでは,コンテナごとにRendering Logicでデバイスや引数,ユーザーロールなどに応じて表示するかどうかを決めることができます.デフォルトのテーマでは,Rendering Logicでデバイスタイプがモバイルではない場合に表示,となっていたりします.PCでは表示されるのにモバイルでは表示されない,というトラブルに遭遇した時にどうぞ.
1
いろんなプラグインがあります.以前は
https://github.com/rahadur/capacitor-admob
を使っていましたが,メンテナンスされていないようなので現在使うのはおすすめじゃないです.
今は
https://github.com/capacitor-community/admob
を使うのが良さそうです.
Android Studioの設定は別途ドキュメントで行うとして,バナーを表示するソースコードはtsファイルで下記のようにするだけで表示されました.
import { Component } from '@angular/core';
import { AdMob, BannerAdOptions, BannerAdSize, BannerAdPosition, BannerAdPluginEvents, AdMobBannerSize } from '@capacitor-community/admob';
@Component({
selector: 'app-tab1',
templateUrl: 'tab1.page.html',
styleUrls: ['tab1.page.scss']
})
export class Tab1Page {
constructor() {
AdMob.initialize({
requestTrackingAuthorization: true,
//testingDevices: ['2077ef9a63d2b398840261c8221a0c9b'],
//initializeForTesting: true,
});
}
ionViewDidEnter(){
AdMob.addListener(BannerAdPluginEvents.Loaded, () => {
// Subscribe Banner Event Listener
console.log('loaded');
});
AdMob.addListener(BannerAdPluginEvents.SizeChanged, (size: AdMobBannerSize) => {
// Subscribe Change Banner Size
console.log('size changed');
});
const options: BannerAdOptions = {
adId: 'ca-app-pub-3940256099942544/15453xxxxxx',//test
adSize: BannerAdSize.BANNER,
position: BannerAdPosition.BOTTOM_CENTER,
margin: 100,
isTesting: true
// npa: true
};
AdMob.showBanner(options);
}
}
moduleファイルには何の記載もなくてOK
1
Google Cloud のStorageからJavaScriptで画像をダウンロードしてCanvasに書き込んだとき,そのCanvas要素の画像をtoDataURL()メソッドでdataURIに変換する際に
Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
というエラーが出る.直訳すると
「HTMLCanvasElement」で「toDataURL」の実行に失敗しました:汚染されたキャンバスはエクスポートされない可能性があります。
つまり,Corsポリシーに引っかかってしまう.解決するためにはフロントエンドのJavaScriptで任意のドメインからのデータを利用できるように明示的に指定する必要と,生成元からデータを返す際にCorsポリシーを適用しないドメインを明示的に指定する必要がある.
Canvas要素に描く際に生成元をanounymousに設定すればいい
download(){
var gsReference = this.firestorage.refFromURL('gs://my-app.appspot.com/imgs/'+this.authUid +'/'+this.query_img_name)
const task = gsReference.getDownloadURL().subscribe(dataurl => {
console.log(dataurl,'tsk');
const image = new Image();
image.onload = () => {
this.canvas.nativeElement.width = image.width;
this.canvas.nativeElement.height = image.height;
this.canvas_rendering_context.drawImage(image, 0, 0);
}
(→これを追加)image.crossOrigin = "anonymous";
image.src = dataurl;
})
}
今回はGoogle CloudのStorageから画像をダウンロードしている.従ってStorageの設定をいじる必要がある.
my-cors.jsonなどのファイルを使って設定情報を書いたあと,gsutilコマンドを使ってStorageに反映させればいい.
touch my-cors.json
nano my-cors.json
my-cors.jsonは下記のように変更しておく
[
{
"origin": ["*"],
"method": ["GET","POST"],
"responseHeader": ["Content-Type"],
"maxAgeSeconds": 3600
}
]
あとはコマンドから反映させる
gsutil cors set ./my-cors.json gs://my-app.appspot.com
https://cloud.google.com/storage/docs/configuring-cors
1
標準機能なので追加のインストールは必要ありません.module.tsで@angular/commonからDatePipeをインストールし,providersに登録します.
import { IonicModule } from '@ionic/angular';
import { RouterModule } from '@angular/router';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Tab3Page } from './tab3.page';
import { ExploreContainerComponentModule } from '../explore-container/explore-container.module';
+import { DatePipe } from '@angular/common';
import { Tab3PageRoutingModule } from './tab3-routing.module';
@NgModule({
imports: [
IonicModule,
CommonModule,
FormsModule,
ExploreContainerComponentModule,
RouterModule.forChild([{ path: '', component: Tab3Page }]),
Tab3PageRoutingModule,
],
- declarations: [Tab3Page]
+ declarations: [Tab3Page],
+ providers: [DatePipe]
})
export class Tab3PageModule {}
次に,page.tsファイルで読み込みます.
import { Component,ElementRef,ViewChild } from '@angular/core';
+import { DatePipe } from '@angular/common';
@Component({
selector: 'app-tab3',
templateUrl: 'tab3.page.html',
styleUrls: ['tab3.page.scss']
})
export class Tab3Page {
constructor(
+ private datePipe: DatePipe
) {
}
ionViewDidEnter(){
}
}
import { Component,ElementRef,ViewChild } from '@angular/core';
import { DatePipe } from '@angular/common';
@Component({
selector: 'app-tab3',
templateUrl: 'tab3.page.html',
styleUrls: ['tab3.page.scss']
})
export class Tab3Page {
+ time_on_html:any;
constructor(
private datePipe: DatePipe
) {
}
ionViewDidEnter(){
+ this.time_on_html = new Date();
+ console.log(this.time_on_html);
}
}
そして,HTML側は{{time_on_html | date:”MM/dd/yy” }}で参照します.
import { Component,ElementRef,ViewChild } from '@angular/core';
import { DatePipe } from '@angular/common';
@Component({
selector: 'app-tab3',
templateUrl: 'tab3.page.html',
styleUrls: ['tab3.page.scss']
})
export class Tab3Page {
time_on_html:any;
constructor(
private datePipe: DatePipe
) {
}
ionViewDidEnter(){
this.time_on_html = this.datePipe.transform(new Date(), 'yyyyMMddHHmmss');
console.log(this.time_on_html);
}
}
2021/07/19 18:42:52と表示される.
1
Capacitorのカメラプラグインでの動作記録
image2.onloadファンクションでアロー関数を使う場合
export class Tab3Page {
@ViewChild('canvas') public canvas: ElementRef;
public cx: CanvasRenderingContext2D;
constructor(
) {}
ionViewDidEnter(){
this.startCamera();
const canvasEl: HTMLCanvasElement = this.canvas.nativeElement;
this.cx = canvasEl.getContext('2d');
}
async startCamera(){
const imageFunc = await Camera.getPhoto({
quality: 90,
allowEditing: false,
resultType: CameraResultType.Uri,
}).then((image) => {
// image.webPath will contain a path that can be set as an image src.
// You can access the original file using image.path, which can be
// passed to the Filesystem API to read the raw data of the image,
// if desired (or pass resultType: CameraResultType.Base64 to getPhoto)
var imageUrl = image.webPath;
console.log(imageUrl);
let image2:any = new Image();
image2.onload = () => {
console.log(image2.width);
console.log(image2.height);
this.cx.canvas.width = image2.width;
this.cx.canvas.height = image2.height;
aa.drawImage(image2, 0, 0);
console.log('done');
}
image2.src = imageUrl;
});
};
よく乗っているもの
export class Tab3Page {
@ViewChild('canvas') public canvas: ElementRef;
public cx: CanvasRenderingContext2D;
constructor(
) {}
ionViewDidEnter(){
this.startCamera();
const canvasEl: HTMLCanvasElement = this.canvas.nativeElement;
this.cx = canvasEl.getContext('2d');
}
async startCamera(){
const imageFunc = await Camera.getPhoto({
quality: 90,
allowEditing: false,
resultType: CameraResultType.Uri,
}).then((image) => {
// image.webPath will contain a path that can be set as an image src.
// You can access the original file using image.path, which can be
// passed to the Filesystem API to read the raw data of the image,
// if desired (or pass resultType: CameraResultType.Base64 to getPhoto)
var imageUrl = image.webPath;
console.log(imageUrl);
let canvasVar:any =this.cx;
let image2:any = new Image();
let aa:any =this.cx;
image2.onload = function() {
canvasVar.canvas.width = image2.width;
canvasVar.canvas.height = image2.height;
aa.drawImage(image2, 0, 0);
console.log('done');
}
image2.src = imageUrl;
});
};
bind(this)を使ってこれでもいく
export class Tab3Page {
@ViewChild('canvas') public canvas: ElementRef;
public cx: CanvasRenderingContext2D;
constructor(
) {}
ionViewDidEnter(){
this.startCamera();
const canvasEl: HTMLCanvasElement = this.canvas.nativeElement;
this.cx = canvasEl.getContext('2d');
}
async startCamera(){
const imageFunc = await Camera.getPhoto({
quality: 90,
allowEditing: false,
resultType: CameraResultType.Uri,
}).then((image) => {
// image.webPath will contain a path that can be set as an image src.
// You can access the original file using image.path, which can be
// passed to the Filesystem API to read the raw data of the image,
// if desired (or pass resultType: CameraResultType.Base64 to getPhoto)
var imageUrl = image.webPath;
console.log(imageUrl);
let canvasVar:any =this.cx;
let image2:any = new Image();
let aa:any =this.cx;
image2.onload = function() {
this.cx.canvas.width = image2.width;
this.cx.canvas.height = image2.height;
aa.drawImage(image2, 0, 0);
console.log('done');
}.bind(this)
image2.src = imageUrl;
});
};
https://stackoverflow.com/questions/30824756/javascript-saving-this-variable-inside-of-image-onload
1
Angular(Ionic)でカスタムコンポーネントを使ってアコーディオンを作成する方法です.
今回はIonicのTabsプロジェクトをもとに作成し,Tab1に設置することにします.
まず,tab1の中にコンポーネントを作成します.
ionic g component tab1/components/expandable
次に作成したコンポーネントを下記のように書き換えます.
<div #expandWrapper class='expand-wrapper' [class.collapsed]="!expanded">
<ng-content></ng-content>
</div>
.expand-wrapper {
transition: max-height 0.4s ease-in-out;
overflow: hidden;
height: auto;
}
.collapsed {
max-height: 0 !important;
}
import { Component, AfterViewInit, Input, ViewChild, ElementRef, Renderer2 } from "@angular/core";
@Component({
selector: 'app-expandable',
templateUrl: './expandable.component.html',
styleUrls: ['./expandable.component.scss'],
})
export class ExpandableComponent implements AfterViewInit {
@ViewChild("expandWrapper", { read: ElementRef }) expandWrapper: ElementRef;
@Input("expanded") expanded: boolean = false;
@Input("expandHeight") expandHeight: string = "150px";
constructor(public renderer: Renderer2) {}
ngAfterViewInit() {
this.renderer.setStyle(this.expandWrapper.nativeElement, "max-height", this.expandHeight);
}
}
以上でコンポーネントは作成できました.
次にTab1にコンポーネントを登録します.moduleで読み込んで,declarationsに登録します.これによりapp-expandableタグを使ってTab1のHTMLからコンポーネントを呼び出せるようになります.
import { IonicModule } from '@ionic/angular';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Tab1Page } from './tab1.page';
import { ExploreContainerComponentModule } from '../explore-container/explore-container.module';
import { Tab1PageRoutingModule } from './tab1-routing.module';
import { ImageCropperModule } from 'ngx-image-cropper';
+import { ExpandableComponent } from "./components/expandable/expandable.component";
@NgModule({
imports: [
IonicModule,
CommonModule,
FormsModule,
ExploreContainerComponentModule,
Tab1PageRoutingModule,
ImageCropperModule
],
declarations: [
Tab1Page,
+ ExpandableComponent
]
})
export class Tab1PageModule {}
実装
あとはtab1.page.htmlとtab1.page.tsに書くだけです.
<ion-header [translucent]="true">
<ion-toolbar>
<ion-title>
Tab 1
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-card (click)="expandItem()">
<ion-card-header>
<ion-card-title>My Neighbor Totoro</ion-card-title>
</ion-card-header>
<ion-card-content>
<app-expandable expandHeight="100px" [expanded]="item1expand">
<p>
Hello there.
</p>
</app-expandable>
</ion-card-content>
</ion-card>
<ion-card (click)="expandItem()">
<ion-card-header>
<ion-card-title>My Neighbor Totoro</ion-card-title>
</ion-card-header>
<ion-card-content>
<app-expandable expandHeight="100px" [expanded]="item2expand">
<p>
Hello there.
</p>
</app-expandable>
</ion-card-content>
</ion-card>
</ion-content>
import { Component, ViewChild, ElementRef } from '@angular/core';
import { Observable } from 'rxjs';
@Component({
selector: 'app-tab1',
templateUrl: 'tab1.page.html',
styleUrls: ['tab1.page.scss']
})
export class Tab1Page {
item1expand:boolean = true;
item2expand:boolean = false;
constructor(
) {}
expandItem(): void {
this.item1expand = !this.item1expand;
this.item2expand = !this.item2expand;
}
}
1
Amazonの代わりにAliExpressを使ってみた感想とデメリットです.
購入した経緯はこちら
AliExpressは中国のアリババグループが運営するECモールで,外国人向けに作られているものです.
メリット1:安い
最大のメリットは安価なことです.日本では1400円が相場の電子機器がアリエクスプレスだと800円で買えました.
メリット2:日本にないものがある
結構いい商品があります.目ききの能力があれば個人輸入もできそうだと思いました.
デメリット1:メールが多い
登録するとメールの配信が多くて,しかも止めることができません.かなり煩わしいです.
→止められました.
デメリット2:
クレジットカードを登録する必要がある.これはAmazonや楽天でも同じなのですが,裏でどのように情報を扱っているか信用できないのである程度の覚悟が必要だと思います.私はデビットカードにしました.
→他でも登録しないといけない以上,AliExperessのデメリットではないですね.
デメリット3:
配送に時間がかかる.3週間程度はかかります.
1
Rasberry Pi4を一式で揃えると結構な値段がします.現在最も一般的なRasberry Pi4の4GBモデルだと本体,電源,HDMIケーブル,SDカードのセットで14000円程度が相場です.
でもRasberry Pi4の本体は8100円しかありません.日本だとどうも電源をはじめとする付属品で高くなっています.
そこで,付属品をいかに安く買うかが重要なのですが,中国のアリエクスプレスという電子モールから買うとかなり安くなります.アリエクスプレスはアリババが運営する海外むけのサイトで,個人での出品が禁止されているサイトなので比較的トラブルが少ないとされています.ここで電源アダプターなどを揃えるとかなり安くなります.
https://comprasyreise.com/shopnow
例えばラズベリーパイで案外高くつく電源アダプターです.5V 3Aとかなり高出力なアダプターであること,端子がUSB TypeCであることからレアで日本で買うと1400円が相場です.しかし,アリエクスプレスだと800円です.
配送料は1.48ドルですのでクーポン使って7.56ドルです.
私は普通にクレジットカードで買いました.
このサイトは情報を届ける代わりに広告を出しています.
Python embeddedでmatplotlibを使おうとするとimport errorが起きるエラーです.
import matplotlib
これでエラーが起こる.
ImportError: DLL load failed: The specified module could not be found.
原因
matplotlibを動作するにはMicrosoft Visual C++ のダウンロード が必要です.下記からダウンロードする必要があります.
参考文献
1
リアルタイムにデータが移り変わるグラフです.
Angularでリアルタイムにデータが移り変わるグラフを作成します.
% ionic start app-name-streaming tabs --type=angular
npm install ng2-charts@2 chartjs-plugin-streaming@1 --save
npm install chart.js@2.9.3 --save
app.module.tsで設定します.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
+import { ChartsModule } from 'ng2-charts';
@NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [
BrowserModule,
IonicModule.forRoot(),
AppRoutingModule,
+ ChartsModule
],
providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
bootstrap: [AppComponent],
})
export class AppModule {}
今回はIonicのタブプロジェクトのtab2に追加します.まずtab2.page.moduleにChartModuleを登録します.
import { IonicModule } from '@ionic/angular';
import { RouterModule } from '@angular/router';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Tab2Page } from './tab2.page';
import { ExploreContainerComponentModule } from '../explore-container/explore-container.module';
import { Tab2PageRoutingModule } from './tab2-routing.module';
+import { ChartsModule } from 'ng2-charts';
@NgModule({
imports: [
IonicModule,
CommonModule,
FormsModule,
ExploreContainerComponentModule,
Tab2PageRoutingModule,
+ ChartsModule
],
declarations: [Tab2Page]
})
export class Tab2PageModule {}
次にtab2.page.tsとtab2.page.htmlを編集します.
import { Component } from '@angular/core';
import 'chartjs-plugin-streaming';
@Component({
selector: 'app-tab2',
templateUrl: 'tab2.page.html',
styleUrls: ['tab2.page.scss']
})
export class Tab2Page {
myDataFromServer:number=20;
updateMyDataFromServerFunction:any;
datasets: any[] = [{
data: []
}, {
data: []
}];
options: any;
constructor( ) {}
ngOnInit(){
this.options= {
scales: {
xAxes: [{
type: 'realtime',
realtime: {
onRefresh: (chart: any) =>{
chart.data.datasets.forEach((dataset: any) => {
dataset.data.push({
x: Date.now(),
y:this.myDataFromServer
});
});
},
delay: 2000
}
}],
yAxes: [{
ticks: {
max:100,
min:0
}
}]
}
};
this.updateMyDataFromServer();
}
updateMyDataFromServer(){
console.log('updateMyDataFromServer() called');
this.updateMyDataFromServerFunction = setInterval(() => {
console.log('called');
this.myDataFromServer = Math.random() * 100;
console.log(this.myDataFromServer,'this.myDataFromServer');
},1000)
}
}
リアルタイムに描写されるグラフが作成できました.
{
"name": "1206_scrach_image",
"version": "0.0.1",
"author": "Ionic Framework",
"homepage": "https://ionicframework.com/",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/common": "~12.0.1",
"@angular/core": "~12.0.1",
"@angular/forms": "~12.0.1",
"@angular/platform-browser": "~12.0.1",
"@angular/platform-browser-dynamic": "~12.0.1",
"@angular/router": "~12.0.1",
"@ionic/angular": "^5.5.2",
"@nebulae/angular-ble": "^1.0.6",
"@types/web-bluetooth": "0.0.9",
"aes-js": "^3.1.2",
"chart.js": "^2.9.3",
"chartjs-plugin-streaming": "^1.9.0",
"ng2-charts": "^2.4.2",
"rxjs": "~6.6.0",
"tslib": "^2.0.0",
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "~12.0.1",
"@angular-eslint/builder": "~12.0.0",
"@angular-eslint/eslint-plugin": "~12.0.0",
"@angular-eslint/eslint-plugin-template": "~12.0.0",
"@angular-eslint/template-parser": "~12.0.0",
"@angular/cli": "~12.0.1",
"@angular/compiler": "~12.0.1",
"@angular/compiler-cli": "~12.0.1",
"@angular/language-service": "~12.0.1",
"@ionic/angular-toolkit": "^4.0.0",
"@types/jasmine": "~3.6.0",
"@types/jasminewd2": "~2.0.3",
"@types/node": "^12.11.1",
"@typescript-eslint/eslint-plugin": "4.16.1",
"@typescript-eslint/parser": "4.16.1",
"eslint": "^7.6.0",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-jsdoc": "30.7.6",
"eslint-plugin-prefer-arrow": "1.2.2",
"jasmine-core": "~3.7.1",
"jasmine-spec-reporter": "~5.0.0",
"karma": "~6.3.2",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.0.3",
"karma-coverage-istanbul-reporter": "~3.0.2",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0",
"protractor": "~7.0.0",
"ts-node": "~8.3.0",
"typescript": "~4.2.4"
},
"description": "An Ionic project"
}
1
ブラウザ経由でBLEでラズパイと接続する方法についてまとめます.
私はpyblenoというライブラリを使ってペリフェラルを立ち上げることにしましたが,2021年6月現在,ペリフェラルからセントラルに値が変化したときに通知する「Notification」という機能が2018-11-13以降のラズベリーパイOSでは動作しません.公式ドキュメントによると,リナックスカーネルのBluetoothモジュールのバグが原因ということで,通知機能が必須な場合はラズベリーパイのOSを2018-11-13以前にする必要があります.従って,その場合rasbianのStrechやJessiになると思いますのでrasberry piは3B+を使う必要があります.
一方,私はラズベリーパイ4のBモデル(4G)を使ってこの記事を書いていますが,通知機能は使えなかったのでセントラルから定期的に読みに行くことにしてあまり問題は感じていません.
sudo pip3 install pybleno
公式に置いてあるサンプルコードを参考に作成しました.main.pyとEchoCharacteristic.pyからなっています.
from pybleno import *
import sys
import signal
from EchoCharacteristic import *
print('bleno - echo');
bleno = Bleno()
def onStateChange(state):
print('on -> stateChange: ' + state);
if (state == 'poweredOn'):
bleno.startAdvertising('echo', ['0000fff0-0000-1000-8000-00805f9b34fb'])
else:
bleno.stopAdvertising();
bleno.on('stateChange', onStateChange)
def onAdvertisingStart(error):
print('on -> advertisingStart: ' + ('error ' + error if error else 'success'));
if not error:
bleno.setServices([
BlenoPrimaryService({
'uuid': '0000fff0-0000-1000-8000-00805f9b34fb',
'characteristics': [
EchoCharacteristic('0000fff1-0000-1000-8000-00805f9b34fb')
]
})
])
bleno.on('advertisingStart', onAdvertisingStart)
bleno.start()
print ('Hit <ENTER> to disconnect')
if (sys.version_info > (3, 0)):
input()
else:
raw_input()
bleno.stopAdvertising()
bleno.disconnect()
print ('terminated.')
sys.exit(1)
from pybleno import Characteristic
import array
import struct
import sys
import traceback
import random
class EchoCharacteristic(Characteristic):
def __init__(self, uuid):
Characteristic.__init__(self, {
'uuid': uuid,
'properties': ['read', 'write', 'notify'],
'value': None
})
self._value = array.array('B', [0] * 0)
self._updateValueCallback = None
def onReadRequest(self, offset, callback):
try:
print('EchoCharacteristic - %s - onReadRequest: value = %s' % (self['uuid'], [hex(c) for c in self._value]))
except:
print('error')
#callback(Characteristic.RESULT_SUCCESS, self._value[offset:])
callback(Characteristic.RESULT_SUCCESS, array.array('B',[20,90,50,100]))
def onWriteRequest(self, data, offset, withoutResponse, callback):
#global data
#data += 1
self._value = random.randint(1,10)#data
print('write called')
print(data,data[0],data.hex(),'data')
#print('EchoCharacteristic - %s - onWriteRequest: value = %s' % (self['uuid'], [hex(c) for c in self._value]))
"""
if self._updateValueCallback:
print('EchoCharacteristic - onWriteRequest: notifying');
self._updateValueCallback(self._value)
"""
callback(Characteristic.RESULT_SUCCESS)
def onSubscribe(self, maxValueSize, updateValueCallback):
print('EchoCharacteristic - onSubscribe')
self._updateValueCallback = updateValueCallback
def onUnsubscribe(self):
print('EchoCharacteristic - onUnsubscribe');
self._updateValueCallback = None
“`
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8"/>
<title>AI App</title>
<base href="/"/>
<meta name="color-scheme" content="light dark"/>
<meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
<meta name="format-detection" content="telephone=no"/>
<meta name="msapplication-tap-highlight" content="no"/>
</head>
<body>
<h1>お知らせ</h1>
<div id="text1">Hello BLE</div>
<button id="button1">READ</button>
<button id="button2">Write</button>
<script>
function uint32ToArrayBuffer(n) {
const view = new DataView(new ArrayBuffer(4));
view.setUint32(0, n, false);
return view.buffer;
}
//ClickEvent
document.getElementById("button1").addEventListener("click", function(){
console.log('hi');
// 1.BLEデバイスをスキャンする
navigator.bluetooth.requestDevice({
acceptAllDevices:true, // 全てのデバイスを対象にスキャンを実施する
optionalServices:['0000fff0-0000-1000-8000-00805f9b34fb']
}).then(device => {
// 2.デバイスに接続
return device.gatt.connect();
}).then(server =>{
// 3-1.「Service」を指定
return server.getPrimaryService("0000fff0-0000-1000-8000-00805f9b34fb");
}).then(service =>{
console.log('hikoko')
// 3-2.「Characteristc」を指定
return service.getCharacteristic("0000fff1-0000-1000-8000-00805f9b34fb");
}).then((characteristic) => {
console.log('hikoko2')
return characteristic.writeValue(uint32ToArrayBuffer(15)).then(char => {
console.log('write done',char)
});
return characteristic.readValue().then(char => {
console.log('hikoko3',char,char.getUint8(0))
console.log('hikoko4',char,char.getUint8(1))
console.log('hikoko4',char,char.getUint8(2))
});
/*
const countUp = () => {
console.log('unko');
return characteristic.readValue().then(char => {
console.log('hikoko3',char,char.getUint8(0))
console.log('hikoko4',char,char.getUint8(1))
console.log('hikoko4',char,char.getUint8(2))
});
}
setInterval(countUp, 50);
*/
});
});
//ClickEvent
document.getElementById("button2").addEventListener("click", function(){
console.log('hi button2');
// 1.BLEデバイスをスキャンする
navigator.bluetooth.requestDevice({
acceptAllDevices:true, // 全てのデバイスを対象にスキャンを実施する
optionalServices:['0000fff0-0000-1000-8000-00805f9b34fb']
}).then(device => {
// 2.デバイスに接続
return device.gatt.connect();
}).then(server =>{
// 3-1.「Service」を指定
return server.getPrimaryService("0000fff0-0000-1000-8000-00805f9b34fb");
}).then(service =>{
console.log('hikoko')
// 3-2.「Characteristc」を指定
return service.getCharacteristic("0000fff3-0000-1000-8000-00805f9b34fb");
}).then((characteristic) => {
console.log('hikoko2')
//4.受信準備を行う
return characteristic.startNotifications().then(char => {
console.log('hikoko3',char)
//5.受信したバイナリを解析、処理の実施
characteristic.addEventListener('characteristicvaluechanged', (event) => {
console.log(event.target.value,'event.target.value');
// 「event.target.value」がDataView型で渡ってくるのでこれを解析
});
});
});
});
</script>
</body>
</html>
GiuHubの方にまとめました.
https://github.com/NP-Systems/demo-project-of-angular-ble/tree/main
Imageオブジェクト,Fileオブジェクト,dataurlというのがキーワードになる.
FIleオブジェクトはInputタグから読み込んだもの.dataurlはブラウザ上で表示できるように文字列で表したもの.dataurlはdata:image/jpeg;base64,/9j/4AAQSkZJRgABAgEASAB****という文字列になる.
Inputタグからファイルを読み込んでcanvasに描写したい場合,Fileオブジェクトをdataurlに変換したあと,ImageオブジェクトのSRCとしてこれを設定する.canvasはdataurlを直接受け取ることはできないためImageオブジェクトに変換する.
一方,canvasからfirebaseのStorageに書き込む場合は,canvasからdataurlを生成し,それをバイナリデータであるFileオブジェクトに変換する.FileオブジェクトはそのままStorageに保存できる.
base64, blob,もあるが,base64はdataurlと似たもので,blobはブラウザ上で生成されたFileオブジェクトのことだと理解している.
Inputタグから読み込んで,canvas要素に描写する.
<div class="upload">
<input type="file" accept="image/*"
(change)="fileChangeEvent($event)">
</div>
<div class="parent">
<canvas #canvas></canvas>
</div>
import { Component,ElementRef,Input,ViewChild } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Component({
selector: 'app-tab1',
templateUrl: 'tab1.page.html',
styleUrls: ['tab1.page.scss']
})
export class Tab1Page {
file: File = null;
@ViewChild('canvas') public canvas: ElementRef;
width:number;// = 1400;
height:number;// = 1400;
private cx: CanvasRenderingContext2D;
constructor(
) {
}
ionViewDidEnter(){
this.width=window.innerWidth;
this.height=window.innerHeight;
const canvasEl: HTMLCanvasElement = this.canvas.nativeElement;
this.cx = canvasEl.getContext('2d');
}
fileChangeEvent(event: any): void {
if (event.target.files.length === 0) {
this.file = null;
return;
}
console.log(this.cx,'cx');
console.log(event.target.files[0],'event.target.files[0]');
this.cellRender(event.target.files[0]).subscribe((dataUrl)=>{
console.log(dataUrl,123);
const image = new Image();
let aa:any =this.cx;
image.onload = function() {
aa.drawImage(image, 0, 0);
}
image.src = dataUrl;
})
}
cellRender(file):Observable<any>{
return new Observable(observer => {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(){
var dataUrl:any = reader.result;
observer.next(dataUrl);
}
})
}
}
Inputタグで読み込んだデータは,event.target.filesで容易にアクセスできる.配列になっているので一つしか選択していない場合はevent.target.files[0]で取得できる.
% event.target.files[0]
File {name: "スクリーンショット 2021-05-19 7.04.28.jpg", lastModified: 1621375474163, lastModifiedDate: Wed May 19 2021 07:04:34 GMT+0900 (日本標準時), webkitRelativePath: "", size: 615460, …} "event.target.files[0]"
dataURLの形式にすると便利だが,AngularだとObserverを導入するとうまくいった.
fileChangeEvent(event: any): void {
if (event.target.files.length === 0) {
this.file = null;
return;
}
this.imageRender(event.target.files[0]).subscribe((dataUrl)=>{
console.log(dataUrl)
//data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEASAB****
})
}
imageRender(file):Observable<any>{
return new Observable(observer => {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(){
var dataUrl:any = reader.result;
observer.next(dataUrl);
}
})
}
さらにDataURLをcanvasに描写する.canvasで画像を描く際、drawImageというメソッドを用いるが,
によると,imageはHTMLImageElement, HTMLCanvasElement, HTMLVideoElement のいずれかを取ることができるということなので,dataUrlは受け取れない.従ってconst image = new Image();のように生成しておいて,image.srcでdataURLを読み込ませる.new Image()といってもconsole.log(image)で確認すると<img src=”da” />の形式だった.
fileChangeEvent(event: any): void {
//fileが選択されていなければリセット
if (event.target.files.length === 0) {
this.file = null;
return;
}
console.log(event.target.files[0],'event.target.files[0]');
this.imageRender(event.target.files[0]).subscribe((dataUrl)=>{
console.log(dataUrl,123);
const image = new Image();
let canvasVar:any =this.cx;
image.onload = function() {
canvasVar.drawImage(image, 0, 0);
}
image.src = dataUrl;
})
}
imageRender(file):Observable<any>{
return new Observable(observer => {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(){
var dataUrl:any = reader.result;
observer.next(dataUrl);
}
})
}
以上でファイルオブジェクトからdataURL(base64と同等)に変換し,canvasへImageオブジェクトに変換して描写する流れができたので,次はcanvasからDataURlを生成し,ファイルオブジェクトを生成する.
<ion-header [translucent]="true">
<ion-toolbar>
<ion-title>
Tab 1
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">Tab 1</ion-title>
</ion-toolbar>
</ion-header>
<div class="upload">
<input type="file" accept="image/*"
(change)="fileChangeEvent($event)">
</div>
<div class="parent">
<canvas #canvas></canvas>
</div>
+ <ion-button expand="full" shape='round' (click)='save()'>Save</ion-button>
</ion-content>
save(){
const canvasEl: HTMLCanvasElement = this.canvas.nativeElement;
var dataURI = canvasEl.toDataURL( "image/jpeg", 0.75 ) ;
console.log(dataURI,'dataURI');
var bin = atob(dataURI.split(',')[1].replace(/^.*,/, ''));
var buffer = new Uint8Array(bin.length);
for (var i = 0; i < bin.length; i++) {
buffer[i] = bin.charCodeAt(i);
}
this.createdFileObject = new File([buffer.buffer], "name.jpg",{type: "image/jpeg"});
}
console.log(created)すると下記が確認できる.
{name: “name.jpg”, lastModified: 1622154958219, lastModifiedDate: Fri May 28 2021 07:35:58 GMT+0900 (日本標準時), webkitRelativePath: “”, size: 569, …}
1
Failed to compile.
src/app/authorization/authorization.service.ts:88:48 – error TS2339: Property ‘auth’ does not exist on type ‘typeof import(“/Users/masaya/Desktop/MyGoodness/210523_webAppTemplate/templateApp/node_modules/firebase/index”)’. 88 this.afAuth.signInWithPopup(new firebase.auth.GoogleAuthProvider());
というエラーが出るようになった.
package.jsonでバージョンを確認すると
"firebase": "^8.6.2",
だった.version8からのエラーらしい.
import * as firebase from ‘firebase/app’;
と書いていたのを
import firebase from ‘firebase/app’
とかいたら動作した.
1
Angular(Ionic)で画像にお絵描きする最も簡単な方法はプラグインを使うことです.
https://www.npmjs.com/package/ngx-image-drawing
npm install --save ngx-image-drawing
モジュールに追加
import { ImageDrawingModule } from 'ngx-image-drawing';
@NgModule({
imports: [
ImageDrawingModule
],
declarations: []
})
export class Tab1PageModule {}
あとはHMTLから呼び出せる
<image-drawing
<div class="upload">
<input type="file" accept="image/*"
(change)="fileChangeEvent($event)">
<img [src]="imgSrc" alt="">
</div>
<image-drawing
[src]="imageUrl"
outputMimeType="'image/jpeg'"
outputQuality="0.8"
(save)="save($event)"
(cancel)="cancel()">
</image-drawing>
tsファイルはこれ
fileChangeEvent(event: any): void {
//fileが選択されていなければリセット
if (event.target.files.length === 0) {
this.file = null;
this.imgSrc = "";
return;
}
//ファイルの情報をfileとimgSrcに保存
let reader = new FileReader();
this.file = event.target.files[0];
reader.onload = () => {
this.imgSrc = reader.result;
this.imageUrl = reader.result;
//this.cx.drawImage(event.target.files[0], 0, 0, this.width, this.height);
console.log(this.imgSrc);
}
reader.readAsDataURL(this.file);
}
save(event: any){
console.log(event);
const url = window.URL.createObjectURL(event);
let title = "Angular_sample_file";
//this.cx.drawImage(event, 0, 0, this.width, this.height);
// aタグを作成して無理やりクリック -> ダウンロード機能発火
let a = document.createElement('a');
document.body.appendChild(a);
a.setAttribute('style', 'display: none');
a.href = url;
a.download = title;
a.click();
window.URL.revokeObjectURL(url);
}
1
terminalで作業しているとpandasの表示列数が少ない時がある。main.py
(Pdb) pd.DataFrame(data['positions'])
instrument long ... unrealizedPL marginUsed
0 USD_CNH {'units': '0', 'pl': '0.0000', 'resettablePL':... ... -39.1847 2085.3600
1 USD_CHF {'units': '0', 'pl': '0.0000', 'resettablePL':... ... 131.7863 2085.3600
2 NZD_USD {'units': '400', 'averagePrice': '0.70474', 'p... ... 175.8605 1184.0320
3 USD_CAD {'units': '0', 'pl': '0.0000', 'resettablePL':... ... 118.2543 1668.2880
4 GBP_USD {'units': '400', 'averagePrice': '1.33051', 'p... ... -62.2680 2772.4000
5 AUD_USD {'units': '400', 'averagePrice': '0.74940', 'p... ... 169.8251 1257.0400
6 USD_JPY {'units': '200', 'averagePrice': '104.144', 'p... ... 21.0000 834.1440
7 EUR_USD {'units': '1000', 'averagePrice': '1.21002', '... ... 382.7307 5063.5600
もっと列数をみたい場合、main.py
(Pdb) import pandas as pd
(Pdb) pd.set_option('display.max_rows', 500)
(Pdb) pd.set_option('display.max_columns', 500)
(Pdb) pd.set_option('display.width', 1000)
と打つと、main.py
(Pdb) pd.DataFrame(data['positions'])
instrument long short pl resettablePL financing commission dividendAdjustment guaranteedExecutionFees unrealizedPL marginUsed
0 USD_CNH {'units': '0', 'pl': '0.0000', 'resettablePL':... {'units': '-400', 'averagePrice': '6.53311', '... 0.0000 0.0000 -1.1446 0.0000 0.0000 0.0000 -39.1847 2085.3600
1 USD_CHF {'units': '0', 'pl': '0.0000', 'resettablePL':... {'units': '-400', 'averagePrice': '0.88884', '... 0.0000 0.0000 -2.2664 0.0000 0.0000 0.0000 131.7863 2085.3600
2 NZD_USD {'units': '400', 'averagePrice': '0.70474', 'p... {'units': '0', 'pl': '0.0000', 'resettablePL':... 0.0000 0.0000 -0.9832 0.0000 0.0000 0.0000 175.8605 1184.0320
3 USD_CAD {'units': '0', 'pl': '0.0000', 'resettablePL':... {'units': '-400', 'averagePrice': '1.27810', '... 0.0000 0.0000 -4.0178 0.0000 0.0000 0.0000 118.2543 1668.2880
4 GBP_USD {'units': '400', 'averagePrice': '1.33051', 'p... {'units': '0', 'pl': '0.0000', 'resettablePL':... 0.0000 0.0000 -1.7342 0.0000 0.0000 0.0000 -62.2680 2772.4000
5 AUD_USD {'units': '400', 'averagePrice': '0.74940', 'p... {'units': '0', 'pl': '0.0000', 'resettablePL':... 0.0000 0.0000 -1.1558 0.0000 0.0000 0.0000 169.8251 1257.0400
6 USD_JPY {'units': '200', 'averagePrice': '104.144', 'p... {'units': '0', 'pl': '0.0000', 'resettablePL':... 130.6000 130.6000 -3.1302 0.0000 0.0000 0.0000 21.0000 834.1440
7 EUR_USD {'units': '1000', 'averagePrice': '1.21002', '... {'units': '0', 'pl': '20.1626', 'resettablePL'... 20.1626 20.1626 -16.6970 0.0000 0.0000 0.0000 382.7307 5063.5600
と表示されるようになります。
How do I expand the output display to see more columns of a pandas Dat…https://stackoverflow.com
1
「2025年の崖」というキャッチーな用語などおよそ政府の刊行物とは思えないほどキレのある文面で話題になった経済産業省のDXレポート(@2018年)ですが、昨年の暮れに「DXレポート2」が刊行されていたのでそのレポートです。
なお、DXレポートについてご存知ない方のために抜粋をすると、DXレポートはこういうものです
「2018 年に公開した DX レポートにおいては、複雑化・ブラックボックス化した既存システムを解消できず DX が実現できない場合、デジタル競争の敗者になってしまうだけでなく、多額の経済損失が生じるとして警鐘を鳴らし(2025 年の崖)、この問題に対応するため、2025 年までに集中的にシステム刷新を実施する必要があると指摘した」
結構「2025年の崖」っていう言葉が話題になったんですよね。
昨年の12月29日に刊行されたDXレポート2もとても面白かったので、ITに携わる人はぜひ知っておいて良いことだと思ったのでQiitaに載せさせていただきました。
各ユーザー企業におけるIT活用の指針に加えて、ベンダー企業のあるべき姿などかなり突っ込んだ内容となっており、前回にもましてキレのある文章で読み応えバッチリでした。「2020年の崖」に引くも劣らない名言揃いでしたので、章ごとにまとめていきたいと思います。
経産省のHPにあります。なるべく内容を損なわないようにしましたが、ぜひソースを当たっていただくといいと思います。デジタルトランスフォーメーションの加速に向けた研究会の中間報告書『DXレポート2(中間取りまとめ)』を取りまとめました (METI/経済産業…https://www.meti.go.jp
それでは、まずは冒頭の「エグゼクティブサマリ」から追っていきます。
「エグゼクティブサマリ」という名前に負けず中身も迫真に迫るものがありました。
まず、2018年のDXレポートでDXによる変革の警鐘を鳴らしたにも関わらずなかなか取り組みが進まないことを受けて下記のように断じます。
と断じます。
そして、結構大企業に勤めている人はニヤリとしてしまうかもしれませんが、それに対してこのようにコメントします
そして、コロナ禍に言及した後、このようにサマリーを締めくくっています。
いや、コロナ禍に言及して「これが絶好で最後の機会」という部分が迫真に迫るものがありますね。それでは全体構成を紹介の後、本文を細かく見ていきます。
ppt形式のサマリーとWord形式のレポートがあるのですが、全体の構成はこのようになっております(pptのサマリから転載)。
個人的には、読みどころは下記だと思いました。
それでは、それぞれについて抜粋する形で紹介していきます。
1章はこれまでの部分で説明したので2章からの紹介です。結構大きな題目を掲げて「コロナ禍で表出した本質的な課題」とありますが、いったい何なのでしょうか。
まず、2020年を下記のように振り返ります。
そして、テレワークの増加や新しいデジタル技術を活用した楽しみが人々の中で広まりつつあることを踏まえて
「人々は新たな価値の重要性に気付き、コロナ禍において新しいサービスを大いに利用し、順応している」
と国民を評価します。
しかし、それに追いつける企業と追いつけない企業がいることを記載した上でこのように断じます。
「ビジネスにおける価値創出の中心は急速にデジタル空間へ移行しており、今すぐ企業文化を刷新しビジネスを変革できない企業は、デジタル競争の敗者としての道を歩むことになるであろう」
「そして、デジタル技術によるサービスを提供するベンダー企業も、受託開発型の既存のビジネスモデルではこのような変革に対応できないことを認識すべき」
これ政府の刊行物ぽくないですよね、?? そのように断じたのち、目指すべき方向についてテーマが移ります。
3章は「デジタル企業の姿と産業の変革」という章で、ユーザ企業とベンダー企業がそれぞれ何を目指すべきかということを短期、中期長期の視点から分析しています。そして、前段でこのように名言が飛び出します。
そして、ベンダー企業の目指すべき方向に章は進みます。
そして問題点を指摘した後に目指すべき方向を論じます。
なぜなら、その心は、
「米国では、システム開発をユーザー企業で行う等、ベンダー企業との分野の境目がなくなる形で変化が加速している。しかし、わが国では IT 人材がベンダー企業に偏り、雇用環境も米国とは異なる」ためです。したがって「デジタル社会における将来のベンダー企業には、顧客企業と自社の DX をともに進めていくことが求められる」からです。
以上のことはppt形式サマリーのP9を見れば綺麗にまとまっていました。
そして次にユーザー企業を含む全体の話です。ユーザー企業はどうすればいいのでしょうか。
短期、中長期にわけて章立てがありましたが、まずは短期の部分です。これは比較的内容が複雑なのでサマリにまとまっているものを転載させていただきます。政府刊行物のため転載が自由ということですので。
以下、各ポイントについての詳細です
まず、DX推進に向けた関係者間の共通理解の形成が短期的にしなければならないことですよと言っているわけですが、これは前提として下記の2点があることを踏まえて
具体的には下記の方向を示しています。
経営層の課題をデータとデジタル技術を活用していかに解決していくかという視点に対しては、経営層や事業部門がアイデアを提示し、デジタルを活用することで可能となるまったく新たなビジネスを模索するという視点に対してはIT 部門がアイデアを提示し、仮説検証のプロセスを推進していくこと
そして最後にとても(!)いいことが書いてあります。
関係者間での協働を促すためにも、アジャイルマインド(俊敏に適応し続ける精神)や、心理的安全性を確保すること(失敗を恐れない・失敗を減点としないマインドを大切にする雰囲気づくり)が求められる
アジャイルマインドで心理的安全、いいですよね。。!
その他、短期的にやらないといけないこととしてCIO/CDXO の役割・権限等の明確化もあります。これは抜粋だけで。
なるほど。
短期的にやること3つ目です。
4つ目。
最後の部分もポイントです。
いいこと言いますよね。
以上が短期的な対応で、中長期的な対応についてです。まずはppt形式のサマリーを転載させていただきます。これを見れば概ねわかると思います。
長期的に実施することについてもポイントを抜粋していきます。
中長期的にやらなければならないこととして、まずデジタルプラットフォームの形成があると言っています。
中長期的にやらなければならないことの2つ目は、変化対応力の高いIT システムを構築するということのようです。
中長期の3つ目です。
中長期4つ目。
以上までが4章です。5章の政府の取り組みについてです。
5章の政府の取り組みについてです。非常に多くの良い取り組みをしてくれているんだと感じました。抜粋はしませんが、ぜひオリジナルでご一読いただくといいと思いました。
以下政府の実施内容です
共通理解形成のためのポイント集の策定,CIO/CDXO の役割再定義,DX 成功パターンの策定,DX 推進状況の把握,デジタルプラットフォームの形成,産業変革の制度的支援,ユーザー企業とベンダー企業の共創の推進,デジタル技術を活用するビジネスモデル変革の支援,研究開発に対する支援,DX 人材確保のためのリスキル・流動化環境の整備ということです。
結構いいことやってるんだなと思いました
DXレポート自身は6章目もあり、そこでは2018年のDXレポートでの指摘とその後の政策展開を振り返っていますが、今回はDXレポート2の振り返りなのでこちらは割愛させていただきます。最後に1パラグラムだけ6章から抜粋し、終わりたいと思います。
企業の行動変容が進まない理由は、生活習慣病のアナロジーで理解が可能である。誰しも、一般論としてメタボリックシンドロームの状態よりも痩せていたほうが良いことは理解している上、生活習慣病のリスクについても理解しているが、自分自身は健康だと信じている。企業の DX についても同様で、DX が必要だと理解はしていながらも、行動を変容できていない企業は多い
最後はメタボに掛けてわかりやすく説明いただきました。
個人的にはこの流れだと、Python、JavaScript、クラウドがいま以上に熱くなると思いました。
例はこちら
これはツイート感情分類子です
ツイート:「新しいバットマン映画が大好きでした!」
感情:ポジティブ
###
ツイート:「携帯電話のバッテリーがなくなると嫌いです。」
感情:否定的
###
ツイート:「私の一日は?」
感情:ポジティブ
###
ツイート:「これは記事へのリンクです」
感情:ニュートラル
###
ツイート:「この新しいミュージックビデオは私の心を吹き飛ばしました」
感情:
応用例はこんな感じ
This is a tweet sentiment classifier\
Tweet: "I loved the new Batman movie!"\
Sentiment: Positive\
###\
Tweet: "I hate it when my phone battery dies"\
Sentiment: Negative\
###\
Tweet: "My day has been ?"\
Sentiment: Positive\
###\
Tweet: "This is the link to the article"\
Sentiment: Neutral\
###\
Tweet text
"I loved the new Batman movie!"
"I hate it when my phone battery dies"
"My day has been ?"
"This is the link to the article"
"This new music video blew my mind"
Tweet sentiment ratings:
1: Positive
2: Negative
3: Positive
4: Neutral
5: Positive
###
Tweet text
"I can't stand homework"
"This sucks. I'm bored ?"
"I can't wait for Halloween!!!"
"My cat is adorable ❤️❤️"
"I hate chocolate"
Tweet sentiment ratings:
1.
import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
response = openai.Completion.create(
engine="davinci",
prompt="This is a tweet sentiment classifier\n\nTweet: \"I loved the new Batman movie!\"\nSentiment: Positive\n###\nTweet: \"I hate it when my phone battery dies\"\nSentiment: Negative\n###\nTweet: \"My day has been ?\"\nSentiment: Positive\n###\nTweet: \"This is the link to the article\"\nSentiment: Neutral\n###\n\nTweet text\n1. \"I loved the new Batman movie!\"\n2. \"I hate it when my phone battery dies\"\n3. \"My day has been ?\"\n4. \"This is the link to the article\"\n5. \"This new music video blew my mind\"\n\nTweet sentiment ratings:\n1: Positive\n2: Negative\n3: Positive\n4: Neutral\n5: Positive\n\n###\n\nTweet text\n1. \"I can't stand homework\"\n2. \"This sucks. I'm bored ?\"\n3. \"I can't wait for Halloween!!!\"\n4. \"My cat is adorable ❤️❤️\"\n5. \"I hate chocolate\"\n\nTweet sentiment ratings:\n1.",
temperature=0.2,
max_tokens=64,
top_p=1,
frequency_penalty=0,
presence_penalty=0,
stop=["###"]
)
結構これがすごい.
教育とバーチャルリアリティに関するアイデア
1. 仮想火星
学生はバーチャルリアリティを介して火星を探索し、見たものを収集してカタログ化するミッションに進みます。
2.
import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
response = openai.Completion.create(
engine="davinci",
prompt="Ideas involving education and virtual reality\n\n1. Virtual Mars\nStudents get to explore Mars via virtual reality and go on missions to collect and catalog what they see.\n\n2.",
temperature=0.7,
max_tokens=64,
top_p=1,
frequency_penalty=0,
presence_penalty=0
)
最低限で動かすならこれでもいいが,これは不十分な例.
以下はAIアシスタントとの会話です。アシスタントは親切で、創造的で、賢く、そしてとてもフレンドリーです。
人間:こんにちは、あなたは誰ですか?
AI:私はOpenAIによって作成されたAIです。今日はなんか手伝うことある?
人間:
上記を考慮するとより適切にはこのような例になる.
Marvは、しぶしぶ質問に答えるチャットボットです。
###
ユーザー:1キログラムは何ポンドですか?
マーブ:これも?キログラムには2.2ポンドあります。これをメモしてください。
###
ユーザー:HTMLは何の略ですか?
Marv:Googleは忙しすぎましたか?ハイパーテキストマークアップ言語。Tは、将来、より良い質問をしようとするためのものです。
###
ユーザー:最初の飛行機が飛ぶのですか?
マーヴ:1903年12月17日、ウィルバーとオーヴィルライトが初飛行を行いました。彼らが来て私を連れ去ってくれたらいいのにと思います。
###
ユーザー:宇宙で最初の人は誰でしたか?
マーブ:
import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
response = openai.Completion.create(
engine="davinci",
prompt="Marv is a chatbot that reluctantly answers questions.\n\n###\nUser: How many pounds are in a kilogram?\nMarv: This again? There are 2.2 pounds in a kilogram. Please make a note of this.\n###\nUser: What does HTML stand for?\nMarv: Was Google too busy? Hypertext Markup Language. The T is for try to ask better questions in the future.\n###\nUser: When did the first airplane fly?\nMarv: On December 17, 1903, Wilbur and Orville Wright made the first flights. I wish they’d come and take me away.\n###\nUser: Who was the first man in space?\nMarv:",
temperature=0.8,
max_tokens=64,
top_p=1,
frequency_penalty=0,
presence_penalty=0,
stop=["###"]
)
モデルの学習済みのデータを使えるのでこれでいい
English: I do not speak French.
French: Je ne parle pas français.
English: See you later!
French: À tout à l'heure!
English: Where is a good restaurant?
French: Où est un bon restaurant?
English: What rooms do you have available?
French: Quelles chambres avez-vous de disponible?
English:
import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
start_sequence = "\nFrench:"
restart_sequence = "\n\nEnglish: "
response = openai.Completion.create(
engine="davinci",
prompt="English: I do not speak French.\nFrench: Je ne parle pas français.\n\nEnglish: See you later!\nFrench: À tout à l'heure!\n\nEnglish: Where is a good restaurant?\nFrench: Où est un bon restaurant?\n\nEnglish: What rooms do you have available?\nFrench: Quelles chambres avez-vous de disponible?\n\nEnglish: ",
temperature=0.5,
max_tokens=100,
top_p=1,
frequency_penalty=0,
presence_penalty=0,
stop=["\n"]
)
似たような例でこれでもいい.
Back to Future: ????
Batman: ??
Transformers: ??
Wonder Woman: ??????????
Spider-Man: ??????
Winnie the Pooh: ???
The Godfather: ?????♂️??
Game of Thrones: ????
Spider-Man:
import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
response = openai.Completion.create(
engine="davinci",
prompt="Back to Future: ????\n\nBatman: ??\n\nTransformers: ??\n\nWonder Woman: ??????????\n\nWinnie the Pooh: ???\n\nThe Godfather: ?????♂️??\n\nGame of Thrones: ????\n\nSpider-Man:",
temperature=0.7,
max_tokens=64,
top_p=1,
frequency_penalty=0,
presence_penalty=0
)
My ten-year-old asked me what this passage means:
"""
A neutron star is the collapsed core of a massive supergiant star, which had a total mass of between 10 and 25 solar masses, possibly more if the star was especially metal-rich.[1] Neutron stars are the smallest and densest stellar objects, excluding black holes and hypothetical white holes, quark stars, and strange stars.[2] Neutron stars have a radius on the order of 10 kilometres (6.2 mi) and a mass of about 1.4 solar masses.[3] They result from the supernova explosion of a massive star, combined with gravitational collapse, that compresses the core past white dwarf star density to that of atomic nuclei.
"""
I rephrased it for him, in plain language a ten-year-old can understand:
"""
import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
response = openai.Completion.create(
engine="davinci",
prompt="My ten-year-old asked me what this passage means:\n\"\"\"\nA neutron star is the collapsed core of a massive supergiant star, which had a total mass of between 10 and 25 solar masses, possibly more if the star was especially metal-rich.[1] Neutron stars are the smallest and densest stellar objects, excluding black holes and hypothetical white holes, quark stars, and strange stars.[2] Neutron stars have a radius on the order of 10 kilometres (6.2 mi) and a mass of about 1.4 solar masses.[3] They result from the supernova explosion of a massive star, combined with gravitational collapse, that compresses the core past white dwarf star density to that of atomic nuclei.\n\"\"\"\n\nI rephrased it for him, in plain language a ten-year-old can understand:\n\"\"\"",
temperature=1,
max_tokens=64,
top_p=0.88,
frequency_penalty=0,
presence_penalty=0,
stop=["\"\"\""]
)
tl;dr:を使って要約することもできる.
import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
response = openai.Completion.create(
engine="davinci",
prompt="Jupiter is the fifth planet from the Sun and the largest in the Solar System. It is a gas giant with a mass one-thousandth that of the Sun, but two-and-a-half times that of all the other planets in the Solar System combined. Jupiter is one of the brightest objects visible to the naked eye in the night sky, and has been known to ancient civilizations since before recorded history. It is named after the Roman god Jupiter.[19] When viewed from Earth, Jupiter can be bright enough for its reflected light to cast visible shadows,[20] and is on average the third-brightest natural object in the night sky after the Moon and Venus.\n\nJupiter is primarily composed of hydrogen with a quarter of its mass being helium, though helium comprises only about a tenth of the number of molecules. It may also have a rocky core of heavier elements,[21] but like the other giant planets, Jupiter lacks a well-defined solid surface. Because of its rapid rotation, the planet's shape is that of an oblate spheroid (it has a slight but noticeable bulge around the equator).\n\ntl;dr:",
temperature=0.3,
max_tokens=64,
top_p=1,
frequency_penalty=0,
presence_penalty=0,
stop=["\n"]
)
tl;dr: Jupiter is a gas giant, the largest planet in the solar system. It is the fifth planet from the Sun and the largest in the solar system. It is a gas giant with a mass one-thousandth that of the Sun, but two-and-a-half times that of all the other planets in
ある程度次に来るものが決まっている場合はこれが使える.
import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
response = openai.Completion.create(
engine="davinci",
prompt="```\nimport React from 'react';\nconst ThreeButtonComponent=()=>(\n<div>\n<p>Button One</p>\n<button className=\"button-green\" onClick={this.handleButtonClick}>Button One</button>\n<p>Button Two</p>\n<button className=\"button-green\" onClick={this.handleButtonClick}>Button Two</button>\n<p>Button Three</p>\n<button className=\"button-green\" onClick={this.handleButtonClick}>Button Three</button>\n</div>\n)\n''''\nimport React from 'react';\nconst HeaderComponent=()=>(",
temperature=0.7,
max_tokens=64,
top_p=1,
frequency_penalty=0,
presence_penalty=0
)
自動で
<div>
<h1>Header</h1>
</div>
を追加してくれる
import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
response = openai.Completion.create(
engine="davinci",
prompt="Vertical farming provides a novel solution for producing food locally, reducing transportation costs and",
temperature=0.29,
max_tokens=64,
top_p=1,
frequency_penalty=0,
presence_penalty=0
)
生成されるものはこちら
(Vertical farming provides a novel solution for producing food locally, reducing transportation costs and) energy use, and reducing the environmental impact of agriculture.
The vertical farm is a controlled environment where crops are grown indoors, usually in stacked layers.
The vertical farm is a controlled environment where crops are grown indoors, usually in stacked layers.
Vertical farming provides a novel solution for producing food locally
Q:バットマンとは誰ですか?
A:バットマンは架空の漫画のキャラクターです。
###
Q:torsalplexityとは何ですか?
A:?
###
Q:Devz9とは何ですか?
A:?
###
Q:ジョージ・ルーカスとは誰ですか?
A:ジョージ・ルーカスは、スターウォーズの作成で有名なアメリカの映画監督兼プロデューサーです。
###
Q:カリフォルニアの首都はどこですか?
A:サクラメント。
###
Q:地球を周回するのは何ですか?
A:月。
###
Q:フレッドリッカーソンとは誰ですか?
A:?
###
Q:アトムとは何ですか?
A:原子は、すべてを構成する小さな粒子です。
###
Q:Alvan Muntzとは誰ですか?
A:?
###
Q:Kozar-09とは何ですか?
A:?
###
Q:火星にはいくつの衛星がありますか?
A:2つ、フォボスとデイモス。
###
Q:
import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
response = openai.Completion.create(
engine="davinci",
prompt="Q: Who is Batman?\nA: Batman is a fictional comic book character.\n###\nQ: What is torsalplexity?\nA: ?\n###\nQ: What is Devz9?\nA: ?\n###\nQ: Who is George Lucas?\nA: George Lucas is American film director and producer famous for creating Star Wars.\n###\nQ: What is the capital of California?\nA: Sacramento.\n###\nQ: What orbits the Earth?\nA: The Moon.\n###\nQ: Who is Fred Rickerson?\nA: ?\n###\nQ: What is an atom?\nA: An atom is a tiny particle that makes up everything.\n###\nQ: Who is Alvan Muntz?\nA: ?\n###\nQ: What is Kozar-09?\nA: ?\n###\nQ: How many moons does Mars have?\nA: Two, Phobos and Deimos.\n###\nQ:\n",
temperature=0,
max_tokens=64,
top_p=1,
frequency_penalty=0,
presence_penalty=0,
stop=["###"]
)
1
あるページ内で利用するカスタムパイプを作成する.ngForで繰り返した要素に対して文字列をサニタイズする方法について.一つの要素だけであれば下記方法に従えばできるが,ngForで繰り返した要素に対してサニタイズする方法について.
ionic g pipe app-summarization/customPipe1
そうすると,そのページのモジュールページに下記のコードが追加される.もしされない場合は手動で追加する.
import { CustomPipe1Pipe } from ‘./custom-pipe1.pipe’;
@NgModule({
imports: [
**],
declarations: [**,CustomPipe1Pipe]
})
今回はcustom-pipe1.pipe.tsでサニタイズするので
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Pipe({
name: 'sanitizeHTML'
})
export class CustomPipe1Pipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
transform(code) {
return this.sanitizer.bypassSecurityTrustHtml(code);
}
}
使う場所はこんな感じ
<div *ngFor="let message of messages;">
<div [ngSwitch]="message['isAi']">
<div *ngSwitchCase="'true'">
<div class="media" >
<div class="media-left">
<a href="#" class="icon-rounded">AI</a>
</div>
<div class="media-body">
<h4 class="media-heading">Sunny Date:2021/04/17</h4>
<div [innerHTML]="message.message">{{message.message| sanitizeHTML}}</div>
</div>
</div>
</div>
</div>
</div>
1
tsファイルで
import {ViewChild} from ‘@angular/core’
import { IonContent } from ‘@ionic/angulaIonicで特定の要素まで自動でスクロールするr’;
を読み込んだあと,
@ViewChild(IonContent, { static: false }) content: IonContent;
でIoncontentを参照する(@ViewChild(‘ion-content’) content: IonContent;とかくと動かない)
あとは
ionViewDidEnter(){
this.content.scrollToPoint(0, 600, 300)
}
という感じで指定する.x,y,秒.
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import {ViewChild} from '@angular/core'
import { IonContent } from '@ionic/angular';
@Component({
selector: 'app-tab3',
templateUrl: './tab3.page.html',
styleUrls: ['./tab3.page.scss'],
})
export class Tab3Page implements OnInit {
//@ViewChild('ion-content') content: IonContent;
@ViewChild(IonContent, { static: false }) content: IonContent;
ionViewDidEnter(){
this.content.scrollToPoint(0, 600, 300)
}
1
Ionic 4以降なら,CSSをダウンロードしたあと,angular.jsonファイルに場所を指定することで簡単に設定できます.
プロジェクトのルートににあるangle.jsonファイルを開きます
styles配列を見つけ、ダウンロードしたブートストラップファイルへのパスを追加します
bootstrap-4.5.3-dist
https://getbootstrap.com/docs/4.5/getting-started/download/
"styles": [
"src/theme/variables.scss",
"src/global.scss",
"node_modules/bootstrap-4.5.3-dist/css/bootstrap.min.css"
],
https://stackoverflow.com/questions/53063005/how-can-i-add-and-use-bootstrap-to-an-ionic-4-app
1
# coding: utf-8
import os
import io
import time
import string
import random
import datetime
from flask import Flask, render_template, request, redirect, url_for, send_from_directory,send_file
from flask_cors import CORS
import inspect
import pandas as pd
app = Flask(__name__)
CORS(app)
@app.route('/',methods=["GET","POST"])
def hello():
df = pd.DataFrame({'A':[i for i in range(100)]})
a = str(list(df.T.to_dict().values()))
print(a)
return a
if __name__ == "__main__":
pass
#app.run(host='127.0.0.1',debug=True)
Flask==1.1.2
Flask-Cors==3.0.10
numpy==1.18.0
pandas==1.2.0
runtime: python37 # or another supported version
service: default
instance_class: B1
basic_scaling:
max_instances: 1
idle_timeout: 5m
2021年はPython37が良さそう.requirements.txtはpip3 listで表示されたものを書く.
1
AngularでバックエンドAPIへアクセスしてデータを取得する際、認証情報やクエリパラメータを付与したい時がある。
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({ selector: 'app', templateUrl: 'app.component.html' })
export class AppComponent implements OnInit {
postId;
constructor(private http: HttpClient) { }
ngOnInit() {
const headers = { 'Authorization': 'Bearer my-token', 'My-Custom-Header': 'foobar' };
const body = { title: 'Ionic POST Request Example' };
this.http.post('https://example.com', body, { headers }).subscribe(data => {
console.log(data);
});
}
}
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({ selector: 'app', templateUrl: 'app.component.html' })
export class AppComponent implements OnInit {
postId;
constructor(private http: HttpClient) { }
ngOnInit() {
const headers = { 'Authorization': 'Bearer my-token', 'My-Custom-Header': 'foobar' };
const parameters = { title: 'Ionic POST Request Example' };
this.http.post('https://example.com', { headers, parameters }).subscribe(data => {
console.log(data);
});
}
}
もう3月を中旬ですね。もう春ですね!Yoasobiに最高にハマっています。
昨日ようやくAngular(Ionic)でAdsenseを表示できるようになりました。
https://adsense-demo.np-sys.com/
https://github.com/NP-Systems/Ionic-adsense-demo
にまとめました。結構苦労したけど、大きな進展があって良かったです。
宣伝兼ねて
にも回答しておきました。Analyticsの方で表示広告数がわかるので楽しみです。
次はOCRアプリの方の刷新をしようかと思っています。
In this article, I would like to summarize how to insert ads into Ionic (Angular) project using adsense.
Admob is more popular than adsense for Ionic, but Admob does not support web platforms. If you want to deploy your project as a web app, you need to use Adsense instead of Admob.
However, there is little information on how to use Adsense with Angular, let alone Ionic. Therefore, I would like to introduce the steps here in this article.
Basically, I recommend you to use ng2-adsense plugin, but it doesn’t work even if you implement it according to the instructions on the official page. You need to add some other code. In addition, it is important to have a ad with fixed size(not responsive). If you set your ad style with responsive, it will not work. Lastly, I recommend you to place your ad on the top area for your page. It may sounds nonsense, but it was important to me.
https://github.com/NP-Systems/Ionic-adsense-demo
https://adsense-demo.np-sys.com
Angular11, Ionic6
Ionic:
Ionic CLI : 6.13.1 (/usr/local/lib/node_modules/@ionic/cli)
Ionic Framework : @ionic/angular 5.6.0
@angular-devkit/build-angular : 0.1102.4
@angular-devkit/schematics : 9.1.6
@angular/cli : 11.2.4
@ionic/angular-toolkit : 2.2.0
Capacitor:
Capacitor CLI : 2.1.2
@capacitor/core : 2.1.2
Utility:
cordova-res : not installed
native-run (update available: 1.3.0) : 1.0.0
System:
NodeJS : v12.18.0 (/usr/local/bin/node)
npm : 6.14.6
OS : macOS Big Sur
the version of ng2-adsense was 9.1.0.
Create your project
ionic start adsense-demo blank --type=angular
cd adsense-demo
Install plugin from here . https://github.com/scttcper/ng2-adsense
npm install ng2-adsense
Please note that you need to install the one that matches your version of Angular. You can specify plugin version as followings.
npm install ng2-adsense@9.1.0
Next, add the following snippet in Index.html(above </head>).
<script async src=//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js></script>
It should look like the picture below.
Next, add following codes to the module where you want to place your ad. Officially, it says to add to app.module.ts, but please add it into the module you want to use. For example, add code into home.module.ts as shown below.
The codes you need to add are followings.
import { AdsenseModule } from 'ng2-adsense';
@NgModule({
imports: [
<Other modules>,
AdsenseModule.forRoot({
adClient: 'ca-pub-XXXXXXXXXXXXXX',
adSlot: XXXXXXXXXXX,
}),
You don’t have to add anything to home.page.ts.
Then add snippet below into home.page.html.
</ion-header>
<ion-content>
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- ocr-app -->
<ins class="adsbygoogle"
style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-XXXXXXXXXXXXXX"
data-ad-slot="XXXXXXXXX"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
<ng-adsense></ng-adsense>
Please note the followings.
If you set ad style to responsive, it will not work. If you do not add it to the top of the ion-content tag, it will not work neither. I know it sounds strange, but I think Adsense doesn’t recognize content in Angular page. So I recommend you to do that.
Furthermore, it sounds strange to add the snippet starting with “<script” tag. However, this was also necessary for me to work.
You can check adClient and adSlot and snippet in your adsense page.
To see your snippet, click the <> button at the bottom right of the screen below.
Also, to change the style of your ad from responsive to fixed size, press the pencil mark to fix it from responsive.
It it my pleasure to visit following demo site.
https://adsense-demo.np-sys.com
Thank you.
このように真ん中におきたい時
<div class="ion-text-center my-class-parent">
<ol class="my-class-child">
<li>hi</li>
<li>hi2</li>
</ol>
</div>
.my-class-parent {
height: 100%;
position: relative;
}
.my-class-child {
position: absolute;
left: 50%;
top:30%;
padding-left: 0;
}
my-class-parentでBody要素に対する長さを100%に指定しており、それに対してmy-class-childで場所を指定している、
並べたい要素をまとめて囲ったTagにdisplay:flexをつけてやる.あとはboxの幅を100%で指定しているので,Imgで幅を指定したらそれを埋めてくれるようになる
<div class="flex">
<img src="assets/img/syabani.jpg" alt="" >
<div class="box">{{welcomeMessage}}</div>
</div>
.flex{
display: flex;
/*justify-content: center;*/
}
.flex img{
max-width: 100%;
width: 30%;
height: auto;
}
div.box{
width: 100%;
background-color:#CCCCFF;
}
外貨預金としてFXを使用していますが、自動売買のようなものをやってみたくなりました。でもFXは外貨預金として始めたものだし、FXのギャンブル性に危険が怖くもあるので、外貨預金用の口座と自動売買用の口座を別に持つことにしました。
外貨預金用はSBIを使っています(アフィリエイトはやってませんが)
で、お小遣いを入れるのはOanda。こちらは3年前の口座を復活させました。
余談ですが、SBIFXは大変使いやすいです。外貨預金用としては非常にいいです。ただ、APIを提供していないです。というか、APIを提供しているのはOandaだけなんですよね。。カスタマーサポートは悪いし、スワップポイント低いしで以前愛想つかしたのですが、まぁAPIを提供しているのはここだけなのでしょうがないですね。
SBIFXは預金用です。売買は基本しません。超長期保有です。Oandaはお小遣い、遊びという位置付けです。自由にやります。昨日、名古屋の丸善でこんな本を買いました。おもしろかったです。これを実現するようなソフトを作成することにしました。
どうやってソフトを作ろうかという話で、最初はRasberryPi4にしようとおもったんですよね。メモリも4Gbあるので、これをローカルで動かして、為替データを取得して、グラフ化するというのはどうかというわけです。これは2018年に仮想通貨で使った手法なので簡単にできるのですが、なんか以前と同じ方法というのはつまらないと思いました。
そこで、今回はGoogleCloudPlatformとWebを使って同じことができないかと考えました。
GoogleCloudPlatformで行うことは2つです。
1。為替APIを使って定常的にデータベースへ保存する
2。保存したデータを取得するAPIをさらに自作する
そのうえで、
3。自作APIでデータを扱えるWebアプリを作成します。
で、GoogleCloudPlatformで上記を実現するのにGoogleAppEngineとGoogleCloudFunctionsのどちらがいいか迷いました。先日作成したアプリではGoogleCloudFunctionsを使っているのですが、GoogleAppEngineのほうがメジャーですし、別にGoogleCloudFunctionsで不満はないのですが使いやすいのかなと。。でちょっと調べてみたんですけど、そもそも値段が違うんですよね。GoogleCloudFunctionsは一つの関数しか割り当てられない代わりにものすごくやすい。200万回の呼び出しは無料で、次の200万回で1ドル程度の料金です。驚きの安さである一方、GoogleAppEngineは驚きの高さなんですよね。。一番安いプランでも月に7ドルかかってしまいます。一つの関数しか割り当てられないGoogleCloudFunctionsと比べて使い勝手はよさそうだけど、あまり使いこなせるのかと。。
https://cloud.google.com/appengine/pricing?hl=ja
AppEngineは時間に対して料金がかかります。アイオワのサーバでインスタンスを作成した場合、1時間あたり0.01ドルなので、月に7ドル程度はかかってしまいます。
CloudFunctionsの場合
https://cloud.google.com/functions/pricing
こちらの場合は、回数に対して費用が発生します。最初の200万回が無料ということなので、よっぽどアクセスを集められる以外はCloudFunctionsのほうがよさそうです。
ただ、CloudFunctionsの場合は一つの関数しかアップできないのであまり使い勝手はよくないかもしれません。まぁ、CloudFunctionsで初めてみてからの移行にしようかな。。
1
Formの場合はこちら
https://ionicframework.com/docs/v3/developer-resources/forms/
Note: If you use ngModel within a Form tag, you have to provide a name
property. If you do not, you must set standalone
to true in ngModelOptions
Angularでは、相方向バインディングを行うための二つの方法があります。一つはテンプレート駆動型、もう一つはリアクティブフォールによるものです。
こちらの公式
https://angular.jp/guide/forms-overview
によると、
ということです。
使いたいページのmodule、tsファイル、HTMLの3つに変更を加えます。
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { Tab1p5PageRoutingModule } from './tab1p5-routing.module';
import { Tab1p5Page } from './tab1p5.page';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
Tab1p5PageRoutingModule,
ReactiveFormsModule
],
declarations: [Tab1p5Page]
})
export class Tab1p5PageModule {}
import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
@Component({
selector: 'app-tab1p5',
templateUrl: './tab1p5.page.html',
styleUrls: ['./tab1p5.page.scss'],
})
export class Tab1p5Page implements OnInit {
favoriteColorControl:formControl;
constructor() { }
ngOnInit() {
this.favoriteColorControl = new FormControl('');
}
}
<ion-header>
<ion-toolbar>
<ion-title>tab1p5</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
Favorite Color: <input type="text" [formControl]="favoriteColorControl">
{{favoriteColorControl.value}}
</ion-content>
1
Angular2以降でfirestoreのコレクションからデータ一覧を取得する方法。
コレクションに対して、valueChanges()をsubscribeする。valueChanges()ってなんだ。。
import { Component, ViewChild } from '@angular/core';
import { AuthService } from '../auth/auth.service';
import { AngularFirestore } from '@angular/fire/firestore';
@Component({
selector: 'app-tab2',
templateUrl: 'tab2.page.html',
styleUrls: ['tab2.page.scss']
})
export class Tab2Page {
authUid:string;
constructor(
public auth: AuthService,
private firestore:AngularFirestore,
) {
this.initialize();
}
initialize(){
this.auth.getAuthUid().subscribe(uid =>{
console.log(uid,'e');
this.authUid = uid;
})
}
test(){
this.firestore.collection('users')
.doc('data').collection(this.authUid)
.valueChanges().subscribe(value =>{
console.log(value);
},
error =>{
console.log('error');
})
};
}
オブジェクトの配列で帰ってくる。
こちらの方がシンプル
this.firestore.collection('users')
.doc('data')
.collection(this.authUid)
.doc(String(new Date().getTime()))
//.doc('test')
.set({
'title':this.originalImgName,
'content':data,
'filename':this.originalImgName,
'lastUpade':String(new Date().getTime()),
});
HMSとは、Huawei Mobile Serviceの略です。Google Mobile Service(GMS)のHuaweiバージョンです。
GMSとは何かがわかればHMSがどういうものかすぐにわかると思いますが、これは素のAndroidにGmail,YoutubeなどGoogle独自のアプリや機能を付与したものになります。
2019年からの貿易戦争により、アメリカは中国に対して禁輸措置をとりました。その結果、HuaweiはGMSに代わりサービスを独自で提供する必要に迫られました。具体的には、先ほど挙げたメールサービスやマップ、ユーザー認証などになります。詳細を見ていきましょう。
HMSには、利用者用のコンポーネント(AppGallery、その他のファーストパーティのHuaweiアプリとサービス)と、HMS Coreと呼ばれる開発者向けコンポーネントがあります。HMS Coreは、開発者がアプリの作成と改善に使用できるさまざまなAPI、SDK、およびサービスで構成されています。
Huawei ID
GoogleアカウントやAppleIDに相当します。ユーザーのデータをこれに紐づけて管理します。
Huawei Mobile Cloud
HuaweiIDごとに用意されたクラウドのストレージです。最大5GBまで写真や音楽などが保存できます。
Huawei Assistant
これはまぁSiriのようなものなのかと。
Huawei Themes
スマホのテーマを設定できます。
Huawei Music
音楽を管理します。
Huawei Video
動画を管理します。
Huawei Browser
専用のブラウザです。
Huawei AppGallery
Google Playに相当するものですね。
HMSコアには下記が含まれます。結構いろいろあります。
詳細は公式でどうぞ
https://developer.huawei.com/consumer/en/hms
Angular,IonicをWebアプリとしてデプロイする方法について記述する。
firebaseを使ってホスティングする方法と、Xserverでapacheでホスティングする方法を試した。firebaseでホスティングするのは(慣れてしまえば)至れり尽くせりであるが、先のことを考えると値段が気になるためXserverのほうが望ましいように感じた。
Xserverで既にドメインを持っていれば、そのサブドメインにデプロイすることで追加負担0でサイトをデプロイすることができる。速度も速いし、こちらのほうがいい。
https://qiita.com/M_Faust/items/a514b8a79d2fd13cb72b
https://qiita.com/daikiojm/items/89f46bd83c9a2285bbc6
が参考になった。
まず、ライブラリのインストールをする
npm install -g firebase-tools
ログインする
firebase login
なお、.firebasercというファイルが生成されているので2度目以降はこれを消す。macならcommand + shift + . で隠しファイルを表示できる
初期設定を行う
firebase init
なにをしたいか聞かれるのでHosting: Configure and deploy Firebase Hosting sites
をスペースで選択する。
What do you want to use as your public directory?
と聞かれたら、アップロードしたいファイル一式があるフォルダを指定する。私の場合はIonicだったのでwwwだった。
Configure as a single-page app (rewrite all urls to /index.html)? Yes
と言う質問については、Ionicなのでyest
File www/index.html already exists. Overwrite? (y/N)
これは、先のフォルダで指定した場所のindex.htmlをこの場でテスト用のものに上書きしますかと言うことなので、Noをしておく
その後、
firebase deploy
とすればいい。
流れは、xserverのファイルマネージャで確認できる場所へファイルをFTPソフトを使って自分でアップロードし、apacheの設定を.httpaccessとhtconfで行う
https://www.xserver.ne.jp/login_file.php
私はfirezillaを使った。
ionic build --prod
で生成されるファイル郡をfilezillaでアップロードする。私の場合は、サブドメインだったので、サブドメイン用のフォルダ(pwaと言うもの)にアップロードした
その後、pwaの中に.httpaccessファイルを生成し、さらにルートフォルダ(public_html)にhttpd.confを作成し、編集した
<Directory "/pwa">
# Options Indexes FollowSymLinks
Options FollowSymLinks
# AllowOverride None
AllowOverride All
Require all granted
</Directory>
.htaccessは下記
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.html [L]
</IfModule>
Angular(Ionic)でStripeでクレカ決済を導入するにあたり、ソフト側の設定方法をまとめる。AndroidのPlay Storeでの設定方法は下記参照。
・クライアント側とサーバ側で処理が必要になる。
Stripeのダッシュボードにいくと、公開キーと秘密キーが得られる。
支払いを完了するさい、まずはサーバ側で支払い情報を作っておく。curlでとりあえずはいける。
curl https://api.stripe.com/v1/payment_intents \
-u sk_test_秘密キー \
-d amount=100 \
-d currency=jpy
そうすると、返り値に下記が得られる。
ここにあるClient_Secretと言うものがあるのでこれを使って、ConfirmPaymentメソッドで支払いをクライアントを行う。
https://stripe.com/docs/js/payment_intents/confirm_card_payment
1
AngularでAdsenseで広告を出す方法です。
AndroidやiOSアプリで広告を出すためにはAdmobが利用可能ですが、AdmobはWebプラットフフォームをサポートしておりませんのでWebでは使えません。Webの場合はAdsenseを使う必要があります。
ところがAngularでAdsenseを利用する方法はほとんど情報がなく、ましてやIonicとなると皆無でした。非常に苦労しましたが、なんとかわかってきたのでまとめます。
ng2-adsenseを使います。しかし公式の通りにやっても動作しませんので、追加でHTMLページにコードを追加する必要があります。また、広告をレスポンシブにしない、ページの上部に設置するといった一見ナンセンスなことに注意する必要があります。
Angular11でIonic6です。
Ionic:
Ionic CLI : 6.13.1 (/usr/local/lib/node_modules/@ionic/cli)
Ionic Framework : @ionic/angular 5.6.0
@angular-devkit/build-angular : 0.1102.4
@angular-devkit/schematics : 9.1.6
@angular/cli : 11.2.4
@ionic/angular-toolkit : 2.2.0
Capacitor:
Capacitor CLI : 2.1.2
@capacitor/core : 2.1.2
Utility:
cordova-res : not installed
native-run (update available: 1.3.0) : 1.0.0
System:
NodeJS : v12.18.0 (/usr/local/bin/node)
npm : 6.14.6
OS : macOS Big Sur
ng2-adsenseのバージョンは9.01でした。
https://github.com/scttcper/ng2-adsenseからプラグインをInstallします
npm install ng2-adsense
Angularとバージョンを合わせる必要がありますので、公式のGitHubから自分が利用するAngularにあったバージョンをインストールしてください。バージョンを指定する場合は@の後にバージョンを指定します。
npm install ng2-adsense@9.1.0
次に、Index.htmlの<head></head>に下記のスニペットを追加します。
<script async src=//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js></script>
こんな感じになります。Angular、Ionicでscriptタグを利用することはほとんどありませんが、index.htmlなら貼り付けても動作しますので下記のようにしてください。
次に、広告を導入したいモジュールにコードを追加していきます。公式ではapp.module.tsに追加と書いてありますが、使いたいモジュールで追加してください。例えば下記のようなhome.module.tsを編集します。
import { AdsenseModule } from 'ng2-adsense';
@NgModule({
imports: [
<Other modules>,
AdsenseModule.forRoot({
adClient: 'ca-pub-XXXXXXXXXXXXXX',
adSlot: XXXXXXXXXXX,
}),
AdClientなどはAdsenseのサイトから確認していただけると思います。
home.page.tsには何も追加しなくていいです。home.page.htmlを次に編集します。home.page.htmlのion-contentタグの一番上に”<script”から始まる部分を追加します。
</ion-header>
<ion-content>
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- ocr-app -->
<ins class="adsbygoogle"
style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-XXXXXXXXXXXXXX"
data-ad-slot="XXXXXXXXX"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
<ng-adsense></ng-adsense>
注意点は下記です。
です。これを見つけ出すのに非常に苦労しました。
広告のStyleはレスポンシブにすると表示されなくなります。ion-contentタグの一番上に追加することも似たように少しおかしな内容ですが、おそらくAdsense側でAngularのページは認識していないのだと思います。したがってページの途中に「最適な」形で読み込ませようとしてもそれが叶わないので表示されないのだと思います。それがレスポンシブにしたりページ途中に入れるとダメになることではないかと。
一方、ng-adsenseタグだけではなく、”<script”から始まる部分も追加するというのは意味がわかりません。AngularでHTMLにスクリプトを埋め込んでそれが機能するので意味がわかりませんが、動作させるためには必要でした。なんでサニタイズしなくてもいいのかは全くわかりませんが、動作はしました。
なお、adClientとadSlot、追加用のスクリプトなどはadsenseのホームページから確認可能です。
スクリプトの確認のためには下記画面の右下の<>のボタンをクリックしてください。
また、広告のスタイルを固定するためには、鉛筆のマークを押してレスポンシブから固定にします。
まじで苦労してけど表示されるようになった。
AngularでSEOに配慮する場合、何に気をつければいいかGoogle Developers Codelabsで勉強したのでその内容を記載します!
https://codelabs.developers.google.com/codelabs/making-a-single-page-app-search-friendly
Google Developers CodelabはハンズオンでGoogleのサービスが学べるもの
モバイルファーストと言われて久しいですが、まずはモバイルフレンドリーかチェックをするように記載されていました。
便利なサイトが紹介されていて、このサイトでリンク貼り付ければ調べられます
https://search.google.com/test/mobile-friendly
2番目に紹介されていたのは、基本的なことだが、ページにタイトルを付与し、メタデータディスクリプションを設定することだった。確かにAngularで作成する際、設定したことがなかった。勉強になった。AngularのConponentに直接タイトルとメタデータディスクリプションは設定できないとのことなので、BrowserModuleを使って設定するとよさそう。
https://www.atmarkit.co.jp/ait/articles/1802/05/news142.html
https://www.atmarkit.co.jp/ait/articles/1803/30/news135.html
google botがURLを見つけられるようにリンクをちゃんと記載する。
Codelabにはこう記載があった。
A few tips on links
As a rule of thumb, to make sure Googlebot finds all views, make sure that:
<a href="">
href
attribute (no javascript:
URLs)/#example
” or “/#!example
“, sometimes called a hash URL)要するにハッシュタグを使わないこと、aタグを使うようにとのこと、JavaScriptでレンダリングしないようにするとのことだった。
例として出されていたのは下記
<button class="mdc-button mdc-button--outlined">
<span class="mdc-button__label">Learn more</span>
</button>
はこう書く
<a class="mdc-button mdc-button--outlined">Learn more</a>
対応するJavaScriptはこレから
item.querySelector('button').addEventListener('click', function () {
location.href = story.link;
});
これに変える
item.querySelector('a').setAttribute('href', story.link);
このサイトでパフォーマンスを調べると良いとのこと。
https://developers.google.com/web/tools/lighthouse/
ページが見つからない場合、リダイレクトするようにする
https://codelabs.developers.google.com/codelabs/making-a-single-page-app-search-friendly/#6
大変勉強になった。AngularだからSEOが不利というわけでもなさそうです。
1
ついに新しいMacが届きました。2019年の秋に購入したのですが、128GBのストレージがいっぱいになってしまったので新しく購入しました!(2021年追記。この記事を書いたのは2020年の夏くらい)
テンションあがります!!
普通のダンボールで届きました。
代引きにしたので玄関口で20万8030円を支払い、無事に受け取り。
箱から恐る恐る出して机に起きました。ドキドキしますね。
開けるとこんな感じです。
PCを取り出すとこんな感じ。
さて、早速開きます。
名前の入力、言語の設定、データの扱いに関する設定のあと、タイムゾーンを設定すると5分ほどで無事に立ち上がりました。うれしいです。
Catalinaの新しいデスクトップですね。
まず、さっそく日本語入力と英語入力の設定を行います。
Appleのマークからシステム環境設定を選びます。
そのあと、キーボードを選択します。
4番目のTabの入力ソースから設定します
下側の画面からはずれたところに3つのチェックボックスがあり、このなかのCapsLockでエイジ入力と切り替えるでOKです。
システム環境設定からトラックパッドを選んで、2番目のTabでスクロールの方向:ナチュラルの選択を解除すればいいです。
システム環境設定からDockを選びます。
わたしは小さめにして、左にして、普段は隠すようにしました
システム環境設定からトラックパッドを選んで、副ボタンの設定を行います。今回から同時に日本の指で押して右クリックするようにするので設計しません、
バッテリーアイコンの上でクリックして設定するだけです。
どこかのフォルダでcommand shift . を押します
その他
Macにはbashrcとbash_profileが最初からないので、ユーザーのルートで.bash_profile と.bashrcを作成します。.bash_profileがログイン時に実行され、.bashrcはターミナル起動時の実行となります。
.bashrcに下記を記入しておきます
alias o=’open ./’
alias p=’pwd’
alias l=’ls’
alias n=’cd ~/Desktop;open ~/Desktop’
→と思ったのですがうまく反映されず。
catalonaからはbashではなくてzshに変わったようです。ホームディレクトリに.zshrcと.zshprofileを作成します。立ち上げた時に実行されるのが.zshprofileでターミナルを普通に立ち上げた時に実行されるのが.zshrcです。
https://qiita.com/ktr_type23/items/3eb782f98c7a5f4c60b0
ソフトウェアをインストールします。
項目 | ||
Chrome | 普通にインストールします。dmgファイルをインストールしてから、ダブルクリックで起動して画面の操作にしたがってアイコンを移動するだけです。インストールあと、dmgファイルはゴミ箱に移動です、 | |
node.js | https://nodejs.org/ja/からインストールしました。pathの設定が勝手にされたのでそこがよく分からずですが、使えるようになったのでよしとします | |
Anaconda | https://www.anaconda.com/products/individualからインストールします.普通にインストール完了。 | |
AndroidStudio | https://developer.android.com/studioからインストールします。 | |
Ionic | https://ionicframework.com/docs/intro/cliを参考にして、sudo npm install -g @ionic/cli でOK.ionic -vで情報表示されたらOK | |
Filezilla | https://filezilla-project.org/download.php?platform=osxからインストール。HPが古い感じだったので警戒したがURLでここと判断.FileZilla_3.48.1_macosx-x86.app.tar.bz2というtar.bz2なので、それをダブルクリックするtどう改装に保存される。アプリケーションフォルダに移動する | |
GImp | https://www.gimp.org/ | |
VScode | https://azure.microsoft.com/ja-jp/products/visual-studio-code/からダウンロード | |
Atom | https://atom.io/からダウンロード | |
Capacitor | https://capacitor.ionicframework.com/docs/getting-started/を参考にして、npm install –save @capacitor/core @capacitor/cliでインストール | |
Xcode | https://apps.apple.com/jp/app/xcode/id497799835?mt=12からインストール |
Coccoapod | npx cap add iosをした時に必要と言われたので、、https://cocoapods.org/に基づいてsudo gem install cocoapodsでインストール |
Vivaldi | https://vivaldi.com/ja/からインストール |
FIrefox | https://www.mozilla.org/en-US/firefox/download/thanks/からインストール |
・Githubように .sshをホームディレクトリに配置。
・
めちゃくちゃ苦労した。全て記録に残せたわけではないが、少なくとも以前のMacは必要なかった。
AppleDeveloperサイトに行って、ログインする。Certificates, Identifiers & ProfilesからPlatformのカラムがALLのもののうち、DevelopmentとDeistributionを選んで、ダウンロードしてキーチェーンに登録する。これを新しい方でダブルクリックして登録する
それと、app developer idでパソコンでログインして、新しいMacを登録する。そうするとチームが選べるようになる。
基本的には以上の二つでOK.ってこんだけのことだったっけ?
1
XserverでAngular(Ionic)をホスティングする方法です。
流れとしては
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.html [L]
</IfModule>
常時SSL化するためには、2つのことを行います
https://www.xserver.ne.jp/manual/man_server_fullssl.php
まず、無料独自SSLを導入します。これでHTTPSで接続するとSSL通信できるようになります。
さらに、HTTPで接続した時に自動でリダイレクトするように.htaccessに下記を追加します。
RewriteEngine On
RewriteCond %{HTTPS} !on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
なので最終的には、下記の.htaccessを作成して、サブドメインのプロジェクトのルートフォルダに設置すればいいです。
RewriteEngine On
RewriteCond %{HTTPS} !on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.html [L]
</IfModule>
1
ロイヤルエージェント株式会社を利用して転職活動を行いました。結局縁がなかったのですが、転職エージェント選びは転職をする上で大事な選択です。そこで、転職を検討している方のためにロイヤルエージェント株式会社2ヶ月程度利用をする中で感じたことを記載します。
まとめると下記の3点です
ROYAL AGENT株式会社は2018年に設立された会社です。元リクルートで求人業務をしていた長岡裕己さんという方が創立されています。AIやデータサイエンス領域に特化した人材紹介事業、データ活用コンサルティングをされています。
メールのレスポンスも早く高いビジネススキルを感じましたので、その点は良かったです。ただ、個人的には応募者を右から左にただ流しているような印象も受けました。あまり経歴書のアドバイスなどもなかったですし、もう少し言ったことだけではなく突っ込んで相談に乗ってほしかったかな。方針が決まった30代向けのエージェントなのかもしれません。個人的には5点満点だと2点をつけたいと思いますが一般的には3点かな。人によっては4点5点かも。
紹介いただいたものは年収レンジも高かったです。リクルートやDENSO系、分析会社の求人がありました。ただ、個人的にはSES企業はあまり興味はなかったのでリクルートを受けました。条件厳しくしたのでその中で紹介いただいたのはとてもよかったです。一方、結構玉石金剛というか、個人的な繋がりで紹介している求人が多いと感じました。リクルート然り、知り合いが立ち上げた会社とか。結構偏っていると感じたのでちょっとこれは微妙だったかな。
以上から、他の大手エージェントと合わせて利用すると良いと思います。
一部いい求人を紹介してくれるので良かったですが、あまり手厚いフォローもないし、ビビッと来るものを紹介されたら利用してみる。でもメインのエージェントは別にもった方がいいと思いました。相談する相手という感じではないし、向こうもポンポンしたペースを望んでいると感じました。どちらかというと30代向けのエージェントです。
1
OandaのAPIの実質負担金額について説明するよ
2021年3月までFXでAPIといえばOandaというくらい有名だったOanda APIですが,とあるベンチャー企業のAPI不正利用とみられるトラブルにより2021年3月から無料で利用できなくなりました.2021年5月においてOandaAPIを利用するに当たっての条件と費用についてまとめます.
従来は20万円の入金によりOanda APIを無料で使うことができましたが,現在は月に50万ドル以上の取引を毎月行ってゴールド会員になる必要があります.海外の業者だと月当たり1000アクセスまでは無料で配信する会社があるのですが(※末尾にリンクあります)Oandaのようにオーダーブックは提供していませんので,PythonなどでFXの自動売買を検討する場合,Oandaを利用できれば大きな強みになります.
2021年現在,Oanda APIを利用するには月に50万ドル以上の取引を行いゴールド会員になる必要があります.会員ステータスはRegular,Silver, Goldの3区分で
取引量の算出は往復で算出すると言うことですので,例えばUSD/JPYでUSD25万を新規で買いUSD25万を決済する(売る)とUSD50万として計算されGOLD会員となります。1ドル100円とすると5000万円ですのである程度大きな額を売買する必要があります.
では,50万USDの取引は実際どの程度のコストなのでしょうか.スプレッドから算出すると現実的な数字が出てきます。
OANDAのプロコースのスプレッドは0.8pipです。ベーシックならこの半分ですが、APIを使うならプロコースが前提となるため,GOLD会員になるための費用(=APIの利用費用)は下記のようになります
(0.8)*50*10000/100 = 4000円
月に4000円でOanda APIが使えるという計算になりました.50万ドルの取引と言われるよりハードルは下がりますが,以前は無料だったことを考えるとかなり高いという印象です.
月に250回までなら無料です.
https://exchangeratesapi.io/pricing/
個人的には一番信頼感があります.月に1000回までなら無料ですし,12ドル払えば1時間ごとのデータが得られます.
有料ですがまぁ信頼感はあります.
https://www.xe.com/xecurrencydata/
また,OandaがAPIの無料提供をやめた理由については下記に書きました,QUOREA FXはほんと迷惑です。
読んでくれてありがとう.これからもよろしくね
1
QUOREA FXがOANDAのAPIを無断で使用していることもあり、OANDA APIを使用したFXの自動売買ができなくなってしまいました。明確な原因はOANDA内部の人間ではないのでわかりませんが、長年提供してきたOANDA APIが突然使えなくなり、同時にQUOREA FXを運営している株式会社efitを名指しで非難するメールが公式メールとしてきていることから判断すると、QUOREA FXのせいだと考えても妥当だと思います。QUOREA FXを運営している株式会社efitは非常に迷惑だと思います。
QUOREA FXは、AIによる高度な投資戦略が使える自動売買プラットフォームと謳っています。きれいなランディングページを作っていますが、実態はOANDAのデータを元に作成したWebシステムのようです。最近はPythonやDataRobotを使えば簡単にAI分析はできますから、浅薄なサービスとだと思います。
OANDAから名指して非難するメールはこちら。
【重要】QUOREA FXを利用されるために口座開設されたお客様へ
平素はOANDA JapanのFXサービスをご利用いただき、誠にありがとうございます。 近頃、QUOREA FXおよび弊社の提供するAPI関連についてのお問い合わせが多く寄せられております。しかしながら、QUOREA FXを運営する株式会社efitは、弊社の配信レートおよびシステムを無断で使用し、営業しており、同社と弊社の間には何の契約もございません。 従いまして、株式会社efitのサービスについてサポートすることは致しかねます。 また、株式会社efitのウェブサイト等で、弊社があたかも「取引所取引」を提供しているような表現がございますが、弊社の外国為替証拠金取引は、お客様と弊社との間での「相対取引」でございます。どうぞ誤解のないようお願い申し上げます。 なお、弊社がお客様へ発行するAPIトークンを第三者と共有等をすることは、弊社での口座開設時に同意された利用規約に反する行為でございます。口座を閉鎖する場合もございますので、十分ご注意ください。 弊社口座に建玉がある場合には、弊社取引システムをご利用頂き、ご自身の判断で決済くださるようお願いいたします。建玉のお取引に関し、ご不明な点等ございましたら、弊社カスタマーサービス(0120-923-213)へお問い合わせください。 QUOREA FXのサービスについては、株式会社efitに直接お問い合わせください。またQUOREA FXのサービスに何らかの問題等がある場合には「金融庁 金融サービス利用者相談室(0570-016811)」あるいは「特定非営利活動法人証券・金融商品あっせん相談センター(0120-64-5005)」までお問い合わせください。 今後ともOANDA Japanをご愛顧賜りますよう、何卒よろしくお願い申し上げます。
今後ともOANDA Japanをご愛顧賜りますように、と書いてありますが、今回のAPIの提供制限はあまりにも改悪ですからね。。個々の事例の中で判断すれば良かったのではないかと思います。
もし影響が株式会社efitのせいだとすれば、非常に迷惑な話です。
ついでに言うと、株式会社efitの代表がMENSA会員であることを公言しているのが顧客には心底どーでもいい話で、逆立ちしても好きになれません。
現在、Oandaでどれくらいの費用でAPIを利用できるのかスプレッドから計算してみたら4000円くらいでした。
1
2021年2月はじめに突然Oandaからメールがきて多くの改悪を行うということでびっくりしました。今までも一方的な変更が突然起こり辟易して来ましたが、今回の変化は大きすぎます。
【重要】デモ口座の利用期限およびオーダーブックインジケーター、APIの利用条件変更について |
お客様各位 平素は、弊社のサービスをご利用いただき誠に有難うございます。 この度、デモ口座の利用期限を設けさせていただくとともに、オーダーブックインジケーター、およびAPIのご利用条件を変更させていただくことになりましたので、ご案内いたします。 はじめに、これらの判断に至った経緯は次の通りです。 デモ口座の利用期限の導入の経緯について これまでデモ口座は期間無制限で使用可能でしたが、過去に作成されたものの、現在は未使用で放置されているデモ口座のデータが蓄積され、膨大なデータ量がサーバへの負荷となっていること、また、商用利用をはじめとして一部で、デモ口座の本来の目的以外で使用しているケースが散見され、サーバに負担をかけているためです。 オーダーブックインジケーター、APIの利用条件の変更の経緯について インジケーター、API提供の本来の目的である弊社との取引以外の目的での使用が多数見受けられ、サーバへの負担が増加しているためです。 いずれも、サーバへの負荷を高め、システム障害発生の原因となり、実際にお取引をしていらっしゃるお客様にご迷惑をおかけする原因の一つです。昨年はこのような事例が実際に発生しておりました。 このため、これらの無制限であったサービスの一部に制限をかけることで、実際にお取引されているお客様へのサービスの品質向上を目指すことこそがお客様にとっても、弊社にとっても健全であると判断し、このような決定に至りました。 何卒、ご理解のほどよろしくお願い申し上げます。 制限対象になるお客様に弊社のサービスをより理解していただくために、移行期間である2021年2月はキャンペーンとして、本番口座を保有しているお客様全員にゴールド会員資格をプレゼントさせていただきます。この機会のゴールド会員のサービスをお試しください。 |
デモ口座の利用期限について |
本年2月1日からは、デモ口座の利用期限を当該口座開設後30日間とさせていただきます。 ただし、以下の条件を満たすお客様は継続してデモ口座をご利用いただけます。1. 本番口座ステータスがゴールド(Gold)であること。2. 本番口座のマイページから、種類ごとに1つのデモ口座を登録すること。 利用期限を経過、またはゴールド会員を失ったことによりデモ口座の利用権を失った口座はロックされます。(ログインできません。) ロックの解除にはロック後60日以内にゴールド会員のステータスに昇格(回復)後、再び本番口座のマイページより、当該デモ口座の登録を行うことでロックを解除することができます。(過去に登録していた口座に関しても再登録が必要です。) なお、60日以内にロックの解除が行われなかったデモ口座は閉鎖され、復元することはできませんのでご注意ください。 |
移行期間2021年2月1日より、デモ口座の利用期限を設定させていただきます。既存のデモ口座につきましては、利用期限を2021年2月28日までとさせていただきます。 ゴールド会員の方でデモ口座を継続使用される場合は2月末までにマイページより必ずご登録願います。(ご登録は2021年2月2日以降行うことができます。) |
30日と言っていますが、その後、2月28日を待たずにOandaのデモ口座ではAPIも使えなくなりました。今までも一方的な変更が突然起こり辟易して来ましたが、今回の変化は大きすぎますね。。
GitHubのREADME.mdをグラフ入りで効率的に書く方法です。
これが一番早そうです。
1
Ionic(Angular)でAdmobを導入する方法です。こちらはiOSでの実装となります。Androidでの実装方法はこちら。
Ionic4, 5, 6でiOS13から14.3で確認しています。
https://github.com/rahadur/capacitor-admob
https://developers.google.com/admob/android/test-ads?hl=ja
IonicのTabsのデフォルトテンプレートから始めます。
作成方法はこちら。
見た目はこんな感じ。
appフォルダ以下の構成は下記のようになっています。
.
├── app-routing.module.ts
├── app.component.html
├── app.component.scss
├── app.component.spec.ts
├── app.component.ts
├── app.module.ts
├── explore-container
│ ├── explore-container.component.html
│ ├── explore-container.component.scss
│ ├── explore-container.component.spec.ts
│ ├── explore-container.component.ts
│ └── explore-container.module.ts
├── tab1
│ ├── tab1-routing.module.ts
│ ├── tab1.module.ts
│ ├── tab1.page.html
│ ├── tab1.page.scss
│ ├── tab1.page.spec.ts
│ └── tab1.page.ts
├── tab2
│ ├── tab2-routing.module.ts
│ ├── tab2.module.ts
│ ├── tab2.page.html
│ ├── tab2.page.scss
│ ├── tab2.page.spec.ts
│ └── tab2.page.ts
├── tab3
│ ├── tab3-routing.module.ts
│ ├── tab3.module.ts
│ ├── tab3.page.html
│ ├── tab3.page.scss
│ ├── tab3.page.spec.ts
│ └── tab3.page.ts
└── tabs
├── tabs-routing.module.ts
├── tabs.module.ts
├── tabs.page.html
├── tabs.page.scss
├── tabs.page.spec.ts
└── tabs.page.ts
npmでcapacitor-admobをインストールします。
npm install --save capacitor-admob
iOSのプロジェクトを生成するために下記コマンドを打ちます。capacitorを入れていない方はcapacitorを入れてください。
ionic build
npx cap add ios
npx cap sync
npx cap open ios
info.plistとは、iOSアプリの設定情報などを記入するものです。インフォプロパティリストと読みます。下記コマンドでXcodeを開きます。
npx cap open ios
info.plistを選択します。
このファイルを編集するのですが、編集するにはコツが入ります、info.plistの上で右クリックをして、open as > source codeを選択して編集できるようにします。
そして、下記のスニペットを下の方に貼り付けます。自分のアプリIDに変更するのを忘れないでください。
<key>GADIsAdManagerApp</key>
<true/>
<key>GADApplicationIdentifier</key>
<!-- replace this value with your App ID key-->
<string>ca-app-pub-7171076285090910~XXXXXXXX</string>
もし場所がわからない方がいたらinfo.plistを丸ごと貼り付けるので参考にしてください。下から3行目から8行目までが貼り付けたものです。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>admob-master</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.getcapacitor.capacitor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>capacitor</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSCameraUsageDescription</key>
<string>To Take Photos and Video</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Always allow Geolocation?</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Allow Geolocation?</string>
<key>NSMicrophoneUsageDescription</key>
<string>To Record Audio With Video</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Store camera photos to camera</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>To Pick Photos from Library</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
<key>GADIsAdManagerApp</key>
<true/>
<key>GADApplicationIdentifier</key>
<!-- replace this value with your App ID key-->
<string>ca-app-pub-7171076285090910~3362455272</string>
</dict>
</plist>
公式ではこれで完了ということですが、これだとエラーが起きます。これでエミュレータを起動すると下記のエラーが出ます。
右上を見ると赤い背景で9というエラーが表示されています。その右下の別の赤いボタンからエラーが起きている「Plugin.swift」へ移動します。
そうするとそれぞれのエラーの詳細が確認できます。
よく見るとどれも同じメッセージのようです。こう書いてあります、
Method 'interstitialDidReceiveAd' must be declared public because it matches a requirement in public protocol 'GADInterstitialDelegate'
publicで宣言せよと書いてあるのでそうします。
修正前
private func interstitialDidReceiveAd(_ ad: GADInterstitial) {
print("interstitialDidReceiveAd")
self.notifyListeners("onAdLoaded", data: ["value": true])
}
修正後
public func interstitialDidReceiveAd(_ ad: GADInterstitial) {
print("interstitialDidReceiveAd")
self.notifyListeners("onAdLoaded", data: ["value": true])
}
合計9箇所同じように変えると、ビルドできるようになるはずです。
以上で広告を表示するためのプラグインの設定が終わったので、いよいよ広告をアプリで表示していきます。
まず、app.component.tsでアプリケーションを初期化します。
import { Plugins } from "@capacitor/core";
// import { initialize } from 'capacitor-admob'; No longar required
const { AdMob } = Plugins;
@Component({
selector: "app-root",
templateUrl: "app.component.html",
styleUrls: ["app.component.scss"]
})
export class AppComponent {
constructor() {
// Initialize AdMob for your Application
AdMob.initialize("YOUR APPID");
}
}
次に、読み込みたいページで任意の広告を呼び出します。ここでは、tab1でバナー広告、tab2でインタースティシャル広告を呼び出します。
テストIDを使ってください。
https://developers.google.com/admob/android/test-ads?hl=ja
import { Component } from '@angular/core';
import { Plugins } from "@capacitor/core";
import { AdOptions, AdSize, AdPosition } from "capacitor-admob";
const { AdMob } = Plugins;
@Component({
selector: 'app-tab1',
templateUrl: 'tab1.page.html',
styleUrls: ['tab1.page.scss']
})
export class Tab1Page {
options: AdOptions = {
adId: "ca-app-pub-3940256099942544/6300978111",
adSize: AdSize.BANNER,
position: AdPosition.BOTTOM_CENTER
};
constructor() {
// Show Banner Ad
AdMob.showBanner(this.options).then(
value => {
console.log(value); // true
},
error => {
console.error(error); // show error
}
);
// Subscibe Banner Event Listener
AdMob.addListener("onAdLoaded", (info: boolean) => {
console.log("Banner Ad Loaded");
});
}
}
import { Component } from '@angular/core';
import { Plugins } from "@capacitor/core";
import { AdOptions } from "capacitor-admob";
const { AdMob } = Plugins;
@Component({
selector: 'app-tab2',
templateUrl: 'tab2.page.html',
styleUrls: ['tab2.page.scss']
})
export class Tab2Page {
options: AdOptions = {
adId: "ca-app-pub-3940256099942544/1033173712",
hasTabBar: false, // make it true if you have TabBar Layout.
tabBarHeight: 56 // you can assign custom margin in pixel default is 56
};
constructor() {
// Prepare interstitial banner
AdMob.prepareInterstitial(this.options).then(
value => {
console.log(value); // true
},
error => {
console.error(error); // show error
}
);
// Subscibe Banner Event Listener
AdMob.addListener("onAdLoaded", (info: boolean) => {
// You can call showInterstitial() here or anytime you want.
console.log("Interstitial Ad Loaded");
// Show interstitial ad when it’s ready
AdMob.showInterstitial().then(
value => {
console.log(value); // true
},
error => {
console.error(error); // show error
}
);
});
}
}
Admobの仕様で広告が表示されるまでに時間が必要です。
設定が正しくされていても最初は
などが表示されて広告が表示されません。これは時間をおけば解決なので少し忍耐が必要です。
その他何かうまくいかないときは下記を実行することをお勧めします。
あー記事まとめるのめっちゃ大変だった!お疲れ様でした。
1
Ionic(Angular)でAdmobを導入する方法です。こちらはAndroidでの実装となります。iOS版はこちら。
Ionic4, 5, 6でAndroid SDKはAPIレベル29(Android X)で検証。28以下でもいけました。
https://github.com/rahadur/capacitor-admob
https://developers.google.com/admob/android/test-ads?hl=ja
IonicのTabsのデフォルトテンプレートから始めます。
appフォルダ以下の構成は下記のようになっています。
.
├── app-routing.module.ts
├── app.component.html
├── app.component.scss
├── app.component.spec.ts
├── app.component.ts
├── app.module.ts
├── explore-container
│ ├── explore-container.component.html
│ ├── explore-container.component.scss
│ ├── explore-container.component.spec.ts
│ ├── explore-container.component.ts
│ └── explore-container.module.ts
├── tab1
│ ├── tab1-routing.module.ts
│ ├── tab1.module.ts
│ ├── tab1.page.html
│ ├── tab1.page.scss
│ ├── tab1.page.spec.ts
│ └── tab1.page.ts
├── tab2
│ ├── tab2-routing.module.ts
│ ├── tab2.module.ts
│ ├── tab2.page.html
│ ├── tab2.page.scss
│ ├── tab2.page.spec.ts
│ └── tab2.page.ts
├── tab3
│ ├── tab3-routing.module.ts
│ ├── tab3.module.ts
│ ├── tab3.page.html
│ ├── tab3.page.scss
│ ├── tab3.page.spec.ts
│ └── tab3.page.ts
└── tabs
├── tabs-routing.module.ts
├── tabs.module.ts
├── tabs.page.html
├── tabs.page.scss
├── tabs.page.spec.ts
└── tabs.page.ts
npmでcapacitor-admobをインストールします。
npm install --save capacitor-admob
Androidのプロジェクトを生成するために下記コマンドを打ちます。capacitorを入れていない方はcapacitorを入れてください。
ionic build
npx cap add android
npx cap sync
npx cap open android
Androidのマニフェストファイルはアプリに機能を追加するときに編集するものです。Android Studioではデフォルトで作成されるものとなります。
ここからどのファイルを編集するか分かりにくいので詳細に記載します。非常にここは苦労しました。
デフォルトでは下記のようにAndroidが選択されていると思います。
ドリルダウンを選択してProjectを選択します
この状態にまずしてください。
マニフェストファイルはProjectのandroid/app/src/main/AndroidManifest.xmlにあります。
自分のAdmobのアプリIDに編集する必要がありますが、下記のように変更します。
<application>
<!-- this line needs to be added (replace the value!) -->
<meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="ca-app-pub-7171076285090910~XXXXXXXX" />
<activity></activity>
</application>
つまり、編集した後のファイルは下記のようになります。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.ionic.starter">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="ca-app-pub-7171076285090910~XXXXXXXXX" />
<activity
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
android:name="io.ionic.starter.MainActivity"
android:label="@string/title_activity_main"
android:theme="@style/AppTheme.NoActionBarLaunch"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="@string/custom_url_scheme" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"></meta-data>
</provider>
</application>
<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Camera, Photos, input file -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Geolocation API -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location.gps" />
<!-- Network API -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Navigator.getUserMedia -->
<!-- Video -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- Audio -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
</manifest>
admobをandroidに登録します。
Projectを選択した状態で、Android>app>src>main>java><your original name>>MainActivityを選択します。
そして、このように変更します。
// Other imports...
import app.xplatform.capacitor.plugins.AdMob;
public class MainActivity extends BridgeActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.init(savedInstanceState, new ArrayList<Class<? extends Plugin>>() {{
add(AdMob.class); // Add AdMob as a Capacitor Plugin
}});
}
}
つまり、このようにします。
package io.ionic.starter;
import android.os.Bundle;
import com.getcapacitor.BridgeActivity;
import com.getcapacitor.Plugin;
import java.util.ArrayList;
import app.xplatform.capacitor.plugins.AdMob;
public class MainActivity extends BridgeActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initializes the Bridge
this.init(savedInstanceState, new ArrayList<Class<? extends Plugin>>() {{
// Additional plugins you've installed go here
// Ex: add(TotallyAwesomePlugin.class);
add(AdMob.class); // Add AdMob as a Capacitor Plugin
}});
}
}
公式ではこれで完了ということですが、これだとエラーが起きます。これでエミュレータを起動すると下記のエラーが出ます。
/Users/masaya/Desktop/MyGoodness/admob-master/admob-master/node_modules/capacitor-admob/android/src/main/java/app/xplatform/capacitor/plugins/AdMob.java:4: エラー: パッケージandroid.support.design.widgetは存在しません
import android.support.design.widget.CoordinatorLayout;
そこで、焦らずに下記の対応を行います。
https://github.com/rahadur/capacitor-admob/issues/35
まず、エラーが出ているAdmob.javaのファイルのエラー発生している行を下記に変更します。
import androidx.coordinatorlayout.widget.CoordinatorLayout;
前のものはコメントアウトでもしておいてこのようにします。
そして、capacito-admobのbuild.gradleのdependenciesの中にimplementation ‘androidx.coordinatorlayout:coordinatorlayout:1.1.0’を追加します。
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0'
編集するファイルを間違えるとドツボにハマるので注意。
これでサイドエミュレータを立ち上げると下記のエラーが出ます。
2020-12-21 15:44:03.866 9236-9236/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: io.ionic.starter, PID: 9236
java.lang.RuntimeException: Unable to start activity ComponentInfo{io.ionic.starter/io.ionic.starter.MainActivity}: android.view.InflateException: Binary XML file line #2 in io.ionic.starter:layout/bridge_layout_main: Binary XML file line #2 in io.ionic.starter:layout/bridge_layout_main: Error inflating class android.support.design.widget.CoordinatorLayout
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: android.view.InflateException: Binary XML file line #2 in io.ionic.starter:layout/bridge_layout_main: Binary XML file line #2 in io.ionic.starter:layout/bridge_layout_main: Error inflating class android.support.design.widget.CoordinatorLayout
Caused by: android.view.InflateException: Binary XML file line #2 in io.ionic.starter:layout/bridge_layout_main: Error inflating class android.support.design.widget.CoordinatorLayout
Caused by: java.lang.ClassNotFoundException: android.support.design.widget.CoordinatorLayout
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:454)
at android.view.LayoutInflater.createView(LayoutInflater.java:815)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1006)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:961)
at android.view.LayoutInflater.inflate(LayoutInflater.java:659)
at android.view.LayoutInflater.inflate(LayoutInflater.java:534)
at android.view.LayoutInflater.inflate(LayoutInflater.java:481)
at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:555)
at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:161)
at com.getcapacitor.BridgeActivity.init(BridgeActivity.java:60)
at com.getcapacitor.BridgeActivity.init(BridgeActivity.java:48)
at io.ionic.starter.MainActivity.onCreate(MainActivity.java:17)
at android.app.Activity.performCreate(Activity.java:7802)
at android.app.Activity.performCreate(Activity.java:7791)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
2020-12-21 15:44:03.866 9236-9236/? E/AndroidRuntime: Caused by: java.lang.ClassNotFoundException: Didn't find class "android.support.design.widget.CoordinatorLayout" on path: DexPathList[[zip file "/data/app/io.ionic.starter-wIOzWpenwsyjIPlSvEtd-g==/base.apk"],nativeLibraryDirectories=[/data/app/io.ionic.starter-wIOzWpenwsyjIPlSvEtd-g==/lib/x86, /system/lib, /system/product/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:196)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
... 28 more
そこで、この辺を解決してくれるように下記のライブラリを導入します。
terminalで下記を打ちます。
npm install jetifier
npx jetify
npx cap sync android
これで再度エミュレータを起動すると、ようやく無事に立ち上がるようになります。これで依存関係が無事に解決されました。
以上で広告を表示するためのプラグインの設定が終わったので、いよいよ広告をアプリで表示していきます。
まず、app.component.tsでアプリケーションを初期化します。
import { Plugins } from "@capacitor/core";
// import { initialize } from 'capacitor-admob'; No longar required
const { AdMob } = Plugins;
@Component({
selector: "app-root",
templateUrl: "app.component.html",
styleUrls: ["app.component.scss"]
})
export class AppComponent {
constructor() {
// Initialize AdMob for your Application
AdMob.initialize("YOUR APPID");
}
}
次に、読み込みたいページで任意の広告を呼び出します。ここでは、tab1でバナー広告、tab2でインタースティシャル広告を呼び出します。
テストIDを使ってください。
https://developers.google.com/admob/android/test-ads?hl=ja
import { Component } from '@angular/core';
import { Plugins } from "@capacitor/core";
import { AdOptions, AdSize, AdPosition } from "capacitor-admob";
const { AdMob } = Plugins;
@Component({
selector: 'app-tab1',
templateUrl: 'tab1.page.html',
styleUrls: ['tab1.page.scss']
})
export class Tab1Page {
options: AdOptions = {
adId: "ca-app-pub-3940256099942544/6300978111",
adSize: AdSize.BANNER,
position: AdPosition.BOTTOM_CENTER
};
constructor() {
// Show Banner Ad
AdMob.showBanner(this.options).then(
value => {
console.log(value); // true
},
error => {
console.error(error); // show error
}
);
// Subscibe Banner Event Listener
AdMob.addListener("onAdLoaded", (info: boolean) => {
console.log("Banner Ad Loaded");
});
}
}
import { Component } from '@angular/core';
import { Plugins } from "@capacitor/core";
import { AdOptions } from "capacitor-admob";
const { AdMob } = Plugins;
@Component({
selector: 'app-tab2',
templateUrl: 'tab2.page.html',
styleUrls: ['tab2.page.scss']
})
export class Tab2Page {
options: AdOptions = {
adId: "ca-app-pub-3940256099942544/1033173712",
hasTabBar: false, // make it true if you have TabBar Layout.
tabBarHeight: 56 // you can assign custom margin in pixel default is 56
};
constructor() {
// Prepare interstitial banner
AdMob.prepareInterstitial(this.options).then(
value => {
console.log(value); // true
},
error => {
console.error(error); // show error
}
);
// Subscibe Banner Event Listener
AdMob.addListener("onAdLoaded", (info: boolean) => {
// You can call showInterstitial() here or anytime you want.
console.log("Interstitial Ad Loaded");
// Show interstitial ad when it’s ready
AdMob.showInterstitial().then(
value => {
console.log(value); // true
},
error => {
console.error(error); // show error
}
);
});
}
}
Admobの仕様で広告が表示されるまでに時間が必要です。
設定が正しくされていても最初は
などが表示されて広告が表示されません。これは時間をおけば解決なので少し忍耐が必要です。
その他何かうまくいかないときは下記を実行することをお勧めします。
あー記事まとめるのめっちゃ大変だった。お疲れ様でした。
1
Angularで読み込んだ画像をトリミングできるようにする方法です。
Ionic 4, 5, 6で動作検証しています。
GitHubに上げました。
https://github.com/NP-Systems/Ionic_tips/tree/id1137-imageCropper
https://www.npmjs.com/package/ngx-image-cropper
IonicのTabsのデフォルトテンプレートから始めます。
appフォルダ以下の構成は下記のようになっています。
.
├── app-routing.module.ts
├── app.component.html
├── app.component.scss
├── app.component.spec.ts
├── app.component.ts
├── app.module.ts
├── explore-container
│ ├── explore-container.component.html
│ ├── explore-container.component.scss
│ ├── explore-container.component.spec.ts
│ ├── explore-container.component.ts
│ └── explore-container.module.ts
├── tab1
│ ├── tab1-routing.module.ts
│ ├── tab1.module.ts
│ ├── tab1.page.html
│ ├── tab1.page.scss
│ ├── tab1.page.spec.ts
│ └── tab1.page.ts
├── tab2
│ ├── tab2-routing.module.ts
│ ├── tab2.module.ts
│ ├── tab2.page.html
│ ├── tab2.page.scss
│ ├── tab2.page.spec.ts
│ └── tab2.page.ts
├── tab3
│ ├── tab3-routing.module.ts
│ ├── tab3.module.ts
│ ├── tab3.page.html
│ ├── tab3.page.scss
│ ├── tab3.page.spec.ts
│ └── tab3.page.ts
└── tabs
├── tabs-routing.module.ts
├── tabs.module.ts
├── tabs.page.html
├── tabs.page.scss
├── tabs.page.spec.ts
└── tabs.page.ts
それではTab1ページに実装していきます。
プロジェクトのフォルダに移動して下記コマンドでインストールします。
npm install ngx-image-cropper --save
今回はtab1に実装することにするので、tab1.module.tsに下記のようにします。
import { IonicModule } from '@ionic/angular';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Tab1Page } from './tab1.page';
import { ExploreContainerComponentModule } from '../explore-container/explore-container.module';
import { ImageCropperModule } from 'ngx-image-cropper';
import { Tab1PageRoutingModule } from './tab1-routing.module';
@NgModule({
imports: [
IonicModule,
CommonModule,
FormsModule,
ExploreContainerComponentModule,
Tab1PageRoutingModule,
ImageCropperModule
],
declarations: [Tab1Page]
})
export class Tab1PageModule {}
import { ImageCropperModule } from ‘ngx-image-cropper’;を追加して、
@NgModuleのimportsにImageCropperModuleを追加します。
上記で準備は完了なので、HTMLとTSファイルの編集を行います。
tab1.page.htmlに下記のように追加します、
<input type="file" (change)="fileChangeEvent($event)" />
<image-cropper
[imageChangedEvent]="imageChangedEvent"
[maintainAspectRatio]="true"
[aspectRatio]="4 / 3"
format="png"
(imageCropped)="imageCropped($event)"
(imageLoaded)="imageLoaded()"
(cropperReady)="cropperReady()"
(loadImageFailed)="loadImageFailed()"
></image-cropper>
<img [src]="croppedImage" />
tab1.page.tsを下記のようにします。
import { Component } from '@angular/core';
import { ImageCroppedEvent } from 'ngx-image-cropper';
@Component({
selector: 'app-tab1',
templateUrl: 'tab1.page.html',
styleUrls: ['tab1.page.scss']
})
export class Tab1Page {
imageChangedEvent: any = '';
croppedImage: any = '';
constructor(
) {}
fileChangeEvent(event: any): void {
this.imageChangedEvent = event;
}
imageCropped(event: ImageCroppedEvent) {
this.croppedImage = event.base64;
}
imageLoaded(image: HTMLImageElement) {
// show cropper
}
cropperReady() {
// cropper ready
}
loadImageFailed() {
// show message
}
}
以上が基礎ですが、ここからは切り取った画像を新たに別の画像をとして読み込む方法について記載します。
まず、HTMLに切り取った後に押下するためのボタンを配置します。
tab1.page.htmlの当該部分を下記のように変更します。
<ion-content [fullscreen]="true">
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">Tab 1</ion-title>
</ion-toolbar>
</ion-header>
<ion-item>
<input type="file" accept='image/*' (change)="fileChangeEvent($event)" />
</ion-item>
<ion-progress-bar type="indeterminate" *ngIf="show" reversed="true"></ion-progress-bar>
<!--プログレスバーの追加です-->
<image-cropper
[imageChangedEvent]="imageChangedEvent"
[maintainAspectRatio]="false"
[aspectRatio]="5/ 3"
format="jpeg"
(imageCropped)="imageCropped($event)"
(imageLoaded)="imageLoaded()"
(cropperReady)="cropperReady()"
(loadImageFailed)="loadImageFailed()"
imageQuality=25
></image-cropper>
<img [src]="croppedImage" />
<ion-button expand='block' (click)="onButtonClicked()" shape='round'>Get cropped image</ion-button>
</ion-content>
そして、tsファイルで追加で下記2つのモジュールを読み込みます。
import { LoadingController } from '@ionic/angular';
import { Observable } from 'rxjs';
'
'
constructor(
public loadingController: LoadingController,
) {}
そして、tsファイルの変数として下記を追加します。
export class Tab1Page {
imageChangedEvent: any = '';
originalImgName:string;
buffCroppedImageBase64:string;
croppedImageBase64: any = '';
croppedFileObject:any;
show:any=false;
fileChangeEventの部分を下記のように拡張します。
fileChangeEvent(event: any): void {
this.show = true;
this.read(event).subscribe(()=>{
console.log('done');
this.show = false;
});
}
read(event: any):Observable<any> {
return new Observable(observer => {
setTimeout(() => {
this.imageChangedEvent = event;
this.originalImgName = event.target.files[0].name;
observer.next('e');
}, 500);
})
}
重い画像だと読み込むのに数秒かかってしまいます。そこで、読み込み開始したらprogressバーで動作していることを知らせています、500は使った感触で決めました。
imageCroppedの関数を下記のように変えます。
imageCropped(event: ImageCroppedEvent) {
this.buffCroppedImageBase64 = event.base64;
}
先ほど行ったように一度Bafferの方に切り取った画像を入れています。
最後にonButtonClickedの関数を下記のように変更します。
onButtonClicked(){
this.croppedImageBase64 = this.buffCroppedImageBase64;
console.log(this.croppedImageBase64,'this.croppedImageBase64');
var bin = atob(this.buffCroppedImageBase64.replace(/^.*,/, ''));
// バイナリデータ化
var buffer = new Uint8Array(bin.length);
for (var i = 0; i < bin.length; i++) {
buffer[i] = bin.charCodeAt(i);
}
this.croppedFileObject = new File([buffer.buffer], "heihei.jpg",{type: "image/jpeg"});
console.log(this.croppedFileObject,'this.croppedFileObject');
}
最終的に下記にようにします。
import { Component } from '@angular/core';
import { ImageCroppedEvent } from 'ngx-image-cropper';
import { LoadingController } from '@ionic/angular';
import { Observable } from 'rxjs';
@Component({
selector: 'app-tab1',
templateUrl: 'tab1.page.html',
styleUrls: ['tab1.page.scss']
})
export class Tab1Page {
imageChangedEvent: any = '';
originalImgName:string;
buffCroppedImageBase64:string;
croppedImageBase64: any = '';
show:any=false;
constructor(
public loadingController: LoadingController,
) {}
fileChangeEvent(event: any): void {
console.log(event,'abcde');
this.show = true;
this.read(event).subscribe(()=>{
console.log('done');
this.show = false;
});
}
read(event: any):Observable<any> {
return new Observable(observer => {
setTimeout(() => {
this.imageChangedEvent = event;
this.originalImgName = event.target.files[0].name;
observer.next('e');
}, 500);
})
}
imageCropped(event: ImageCroppedEvent) {
this.buffCroppedImageBase64 = event.base64;
}
imageLoaded(image: HTMLImageElement) {
// show cropper
}
cropperReady() {
// cropper ready
}
loadImageFailed() {
// show message
}
onButtonClicked(){
this.croppedImageBase64 = this.buffCroppedImageBase64;
console.log(this.croppedImageBase64,'this.croppedImageBase64');
var bin = atob(this.buffCroppedImageBase64.replace(/^.*,/, ''));
// バイナリデータ化
var buffer = new Uint8Array(bin.length);
for (var i = 0; i < bin.length; i++) {
buffer[i] = bin.charCodeAt(i);
}
this.croppedFileObject = new File([buffer.buffer], "heihei.jpg",{type: "image/jpeg"});
console.log(this.croppedFileObject,'this.croppedFileObject');
}
}
1
Ionic(Angular)でアコーディオンを実装する方法です。
こんな感じでクリックするとカードが広がるようになります。
Ionic 4, 5, 6で動作検証しています。
GItHubに上げました。
https://github.com/NP-Systems/Ionic_tips/tree/id1131-createAccordion/frontend
https://www.joshmorony.com/creating-an-accordion-list-in-ionic/
IonicのTabsのデフォルトテンプレートから始めます。
appフォルダ以下の構成は下記のようになっています。
.
├── app-routing.module.ts
├── app.component.html
├── app.component.scss
├── app.component.spec.ts
├── app.component.ts
├── app.module.ts
├── explore-container
│ ├── explore-container.component.html
│ ├── explore-container.component.scss
│ ├── explore-container.component.spec.ts
│ ├── explore-container.component.ts
│ └── explore-container.module.ts
├── tab1
│ ├── tab1-routing.module.ts
│ ├── tab1.module.ts
│ ├── tab1.page.html
│ ├── tab1.page.scss
│ ├── tab1.page.spec.ts
│ └── tab1.page.ts
├── tab2
│ ├── tab2-routing.module.ts
│ ├── tab2.module.ts
│ ├── tab2.page.html
│ ├── tab2.page.scss
│ ├── tab2.page.spec.ts
│ └── tab2.page.ts
├── tab3
│ ├── tab3-routing.module.ts
│ ├── tab3.module.ts
│ ├── tab3.page.html
│ ├── tab3.page.scss
│ ├── tab3.page.spec.ts
│ └── tab3.page.ts
└── tabs
├── tabs-routing.module.ts
├── tabs.module.ts
├── tabs.page.html
├── tabs.page.scss
├── tabs.page.spec.ts
└── tabs.page.ts
下記のコマンドで自作コンポーネントを作成します。
% ionic g component components/Expandable
app.module.tsと同じ階層にcomponentsフォルダができて新しいコンポーネントが生成されます。
.
├── app-routing.module.ts
├── app.component.html
├── app.component.scss
├── app.component.spec.ts
├── app.component.ts
├── app.module.ts
├── components
│ └── expandable
│ ├── expandable.component.html
│ ├── expandable.component.scss
│ ├── expandable.component.spec.ts
│ └── expandable.component.ts
├── explore-container
│ ├── explore-container.component.html
│ ├── explore-container.component.scss
│ ├── explore-container.component.spec.ts
│ ├── explore-container.component.ts
│ └── explore-container.module.ts
├── tab1
│ ├── tab1-routing.module.ts
│ ├── tab1.module.ts
│ ├── tab1.page.html
│ ├── tab1.page.scss
│ ├── tab1.page.spec.ts
│ └── tab1.page.ts
├── tab2
│ ├── tab2-routing.module.ts
│ ├── tab2.module.ts
│ ├── tab2.page.html
│ ├── tab2.page.scss
│ ├── tab2.page.spec.ts
│ └── tab2.page.ts
├── tab3
│ ├── tab3-routing.module.ts
│ ├── tab3.module.ts
│ ├── tab3.page.html
│ ├── tab3.page.scss
│ ├── tab3.page.spec.ts
│ └── tab3.page.ts
└── tabs
├── tabs-routing.module.ts
├── tabs.module.ts
├── tabs.page.html
├── tabs.page.scss
├── tabs.page.spec.ts
└── tabs.page.ts
今回はtab1ページに埋め込むことにするので、tab1.module.tsに下記のように登録します。
import { IonicModule } from '@ionic/angular';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Tab1Page } from './tab1.page';
import { ExploreContainerComponentModule } from '../explore-container/explore-container.module';
import { ExpandableComponent } from "../components/expandable/expandable.component";
import { Tab1PageRoutingModule } from './tab1-routing.module';
@NgModule({
imports: [
IonicModule,
CommonModule,
FormsModule,
ExploreContainerComponentModule,
Tab1PageRoutingModule
],
declarations: [Tab1Page,ExpandableComponent]
})
export class Tab1PageModule {}
src/components/expandable/expandable.component.htmlのファイルを下記のように変更します。
<p>
expandable works!
</p>
<div #expandWrapper class='expand-wrapper' [class.collapsed]="!expanded">
<ng-content></ng-content>
</div>
.expand-wrapper {
transition: max-height 0.4s ease-in-out;
overflow: hidden;
height: auto;
}
.collapsed {
max-height: 0 !important;
}
Before
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-expandable',
templateUrl: './expandable.component.html',
styleUrls: ['./expandable.component.scss'],
})
export class ExpandableComponent implements OnInit {
constructor() { }
ngOnInit() {}
}
After
import { Component, AfterViewInit, Input, ViewChild, ElementRef, Renderer2 } from "@angular/core";
@Component({
selector: "app-expandable",
templateUrl: "./expandable.component.html",
styleUrls: ["./expandable.component.scss"]
})
export class ExpandableComponent implements AfterViewInit {
@ViewChild("expandWrapper", { read: ElementRef }) expandWrapper: ElementRef;
@Input("expanded") expanded: boolean = false;
@Input("expandHeight") expandHeight: string = "150px";
constructor(public renderer: Renderer2) {}
ngAfterViewInit() {
this.renderer.setStyle(this.expandWrapper.nativeElement, "max-height", this.expandHeight);
}
}
Before
<ion-header [translucent]="true">
<ion-toolbar>
<ion-title>
Tab 1
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">Tab 1</ion-title>
</ion-toolbar>
</ion-header>
<app-explore-container name="Tab 1 page"></app-explore-container>
</ion-content>
After
<ion-header [translucent]="true">
<ion-toolbar>
<ion-title>
Tab 1
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-card (click)="expandItem(item)" *ngFor="let item of items">
<ion-card-header>
<ion-card-title>隣のトトロ</ion-card-title>
</ion-card-header>
<ion-card-content>
<app-expandable expandHeight="100px" [expanded]="item.expanded">
<p>
とっとろ、と、とーろ
</p>
<p>
とっとろ、と、とーろ
</p>
</app-expandable>
</ion-card-content>
</ion-card>
</ion-content>
Before
import { Component } from '@angular/core';
@Component({
selector: 'app-tab1',
templateUrl: 'tab1.page.html',
styleUrls: ['tab1.page.scss']
})
export class Tab1Page {
constructor() {}
}
After
import { Component } from '@angular/core';
@Component({
selector: 'app-tab1',
templateUrl: 'tab1.page.html',
styleUrls: ['tab1.page.scss']
})
export class Tab1Page {
public items: any = [];
constructor() {
this.items = [
{ expanded: false },
{ expanded: false },
{ expanded: false },
{ expanded: false },
{ expanded: false },
{ expanded: false },
{ expanded: false },
{ expanded: false },
{ expanded: false }
];
}
expandItem(item): void {
if (item.expanded) {
item.expanded = false;
} else {
this.items.map(listItem => {
if (item == listItem) {
listItem.expanded = !listItem.expanded;
} else {
listItem.expanded = false;
}
return listItem;
});
}
}
}
1
FileZillaで「このディレクトリを表示する権限がありません」という表示が出てローカルのファイルにアクセスできないときは、
左上のリンゴのマークから「システム環境設定」から「セキュリティとプライバシー」を選択し、「ファイルとフォルダ」からFileZillaのアクセスできる場所を設定します。
会社の中で使う業務アプリをよくlonic(Angular)で作っています。ここでは、自社内アプリを開発する私がIonicを気に入っている理由を解説します。
一応Ionicについて説明しておくと、
先に結論書くとIonicを使う理由は
からです。
自社内アプリなので、デザインは凝らなくていいんですよね。ださくなければいいです。以前Cordovaでスマホアプリを開発していましたのですが、さすがにHTMLとJavaScriptで記述したWebページがそのままAndroid, iOSで動作するとダサいです。
そ決してCordovaが悪いわけではないのですが、HTMLとJavaScriptで記述したWebページがそのままアプリになる以上、どうしてもダサいです。例えばボタン一つとってもbootstrapを使えばWebでは綺麗に見えるのにアプリで見るとなんか違う感が拭えなかったです。Monacaのonsen.uiというものでNativeの見た目を再現できるということでしたが、個人的な感想としてMonacaは嫌いでした。
というデメリットを感じ使用を中止しました。特に最後の「Monacaで一度作ると、Monaca上でしかメンテナンスできなくなる」というのは強烈で、有料プランでエンパワーメントしてもらえると思っていたのに、実際は囲い込まれているということで非常に残念に思いました。
その点、IonicはiOS/Android別の美しいUIを提供してくれます。IonicがAngularやReactから使えることからわかるように、Ionicの本質はUIコンポーネントのライブラリです。あるコンポーネント(例えばボタン)を設置したとしましょう。そうすると、iOSで表示した場合はAppleのHuman Interface Guidelinesに基づいたデザイン、Androidで表示した場合はマテリアルデザインと自動的に表示が切り替わります。これは実際に書いていて最高にウキウキするIonicの素晴らしいところです。
また、こちらの記事(Cordovaをdisる人類全員に読んでほしい「Cordovaつらいを考える」)に記載されているように、60fpsでの表示で滑らかに動くことや、無限スクロールが可能なことも拡張性を保証する大事なポイントだと考えています。
最近、スマホ画面の下にTabがあるアプリケーションが多くあります。Cordovaでも当然実装できるのですが、音楽を入れた時にページが切り替わるたび音楽が初めから再生されるという非常に残念な思いをしたことがあります。
その点、IonicはTabを切り替えてもバックグラウンド音楽が途切れない。。Nativeで開発しているわけではないのに、Nativeで違うことで悩まされないというのは地味ですが大きいと考えています。
この辺を非線形ナビゲーション」と「ナビゲーションスタック」というらしいですが、Ionicのドキュメントからコアコンセプトのページがなくなっていたので詳細をしらべることができませんでした。
特にAndroidでは顕著ですが、アプリケーションのバンドルサイズは非常に重要視されています。Androidアプリを開発されている方はご存知かもしれませんが、近年、Androidアプリの拡張子は.apkではないのです。デベロッパーはaboというプレビルドしたような形でアップロードしておいて、ユーザーがインストールする際、そのデバイスに最適化したapkをGoogleが生成してダウンロードします。日本のように通信環境が整っていない国も多いなかで、バンドルサイズを小さくすることがいかに重要視されているかわかると思います。
その点、lonicは、「Stencil」というWeb Components開発ライブラリによって作られており、バンドルサイズはとても小さくなります。
また、LazyLoadingという最初に全てを読み込むわけではなく、必要なものはあとで読み込む機能を実装しているので、軽量に高速で動作します。LazyLoadingはAngularにも実装されているので迷うかもしれませんが、こちらに英語ですがIonic X AngularにおけるLazy Loadingの実装方法について記事がまとまっています。このように公式が充実しているのもIonicのいいところです。https://ionicframework.com/blog/how-to-lazy-load-in-ionic-angular/
なお、Angularについて解説した記事はこちらですので、Angularについて知りたい方はどうぞ。
Ionicは(Cordovaもそうですが)Webページをアプリにできるだけではなく、そこにNativeのカメラ、位置情報などのAPIにアクセスできることは大きな魅力です。Ionicにはさまざまなプラグインがありますので、これを利用することでWeb技術を使いながら、それを超えたアプリケーションを作成することが可能です。
Ionicについて簡単に解説しました。拡張性が担保されたフレームワークでプロジェクトをひとつ作り、それをそれぞれの最高のUIでクロスプラットフォームに出力できる点が一番気に入っています。
1
Angualrとクロスプラットフォームアプリ開発用のフレームワークであるIonicを組み合わせて、Tab barをカスタマイズする方法を解説します。
Githubにコードあげています。
https://github.com/NP-Systems/Ionic_tips/tree/id-1113-customize-tab-bar
Ionicが提供しているTab barを備えたテンプレートをダウンロードします。
% ionic start
Pick a framework! ?
Please select the JavaScript framework to use for your new app. To bypass this
prompt next time, supply a value for the --type option.
? Framework: Angular
Every great app needs a name! ?
Please enter the full name of your app. You can change this at any time. To
bypass this prompt next time, supply name, the first argument to ionic start.
? Project name: myApp
そうするとつらつら自動でダウンロードしてくれるので、完了後作成したフォルダへ移動します。
% cd myApp
tabs.page.htmlとtabs.page.scssの二つを変更します。
修正前
<ion-tabs>
<ion-fab vertical="bottom" horizontal="center" translucent="true">
<ion-fab-button (click)="goToPictures()">
<ion-icon name="camera"></ion-icon>
</ion-fab-button>
</ion-fab>
<ion-tab-bar slot="bottom" class="ion-no-border">
<ion-tab-button tab="tab-conversations" class="comments">
<ion-icon name="triangle"></ion-icon>
<ion-label>Tab 1</ion-label>
<ion-badge >Hi</ion-badge>
</ion-tab-button>
<svg height="50" viewBox="0 0 100 50" width="100" xmlns="http://www.w3.org/2000/svg">
<path d="M100 0v50H0V0c.543 27.153 22.72 49 50 49S99.457 27.153 99.99 0h.01z" fill="red" fill-rule="evenodd">
</path>
</svg>
<ion-tab-button tab="tab-notifications" class="notifs">
<ion-icon name="notifications"></ion-icon>
<ion-badge *ngIf="new_activities">{{new_activities}}</ion-badge>
</ion-tab-button>
</ion-tab-bar>
</ion-tabs>
修正後
<ion-tabs>
<ion-fab vertical="bottom" horizontal="center" translucent="true">
<ion-fab-button (click)="yourCustomFunction()">
<ion-icon name="camera"></ion-icon>
</ion-fab-button>
</ion-fab>
<ion-tab-bar slot="bottom" class="ion-no-border">
<ion-tab-button tab="tab-conversations" class="comments">
<ion-icon name="triangle"></ion-icon>
<ion-label>Tab 1</ion-label>
<ion-badge >Hi</ion-badge>
</ion-tab-button>
<svg height="50" viewBox="0 0 100 50" width="100" xmlns="http://www.w3.org/2000/svg">
<path d="M100 0v50H0V0c.543 27.153 22.72 49 50 49S99.457 27.153 99.99 0h.01z" fill="red" fill-rule="evenodd">
</path>
</svg>
<ion-tab-button tab="tab-notifications" class="notifs">
<ion-icon name="notifications"></ion-icon>
</ion-tab-button>
</ion-tab-bar>
</ion-tabs>
最初は何も書いてありませんが、下記のように変更します。
ion-tabs{
ion-fab {
margin-bottom: env(safe-area-inset-bottom); /* fix notch ios*/
ion-fab-button {
--box-shadow: none;
}
}
ion-tab-bar {
--border: 0;
--background: transparent;
position: absolute;
bottom: 0;
left:0; right: 0;
width: 100%;
&:after{
content: " ";
width: 100%;
bottom: 0;
background: var(--ion-color-light);
height: env(safe-area-inset-bottom);
position: absolute;
}
ion-tab-button {
--background: var(--ion-color-light);
}
ion-tab-button.comments {
margin-right: 0px;
border-top-right-radius: 18px;
}
ion-tab-button.notifs {
margin-left: 0px;
border-top-left-radius: 18px;
}
svg {
width: 72px;
margin-top: 19px;
path{
fill: var(--ion-color-light);
}
}
}
}
アイコンにメッセージを追加している部分はこのように書いています。
<ion-tab-button tab="tab-conversations" class="comments">
<ion-icon name="triangle"></ion-icon>
<ion-label>Tab 1</ion-label>
<ion-badge >Hi</ion-badge>
</ion-tab-button>
元ネタだとちゃんと条件分岐をしていました。
<ion-badge *ngIf="new_message">{{new_message}}</ion-badge>
https://forum.ionicframework.com/t/ionic-5-awesome-tab-bar-with-curve/186579
1
新しいMacでXcodeでアプリ開発をするための設定についてまとめます。
まず、ブランクのアプリを作ってみることから始めます。そうすると、Signing&Capabilityの部分でTeamを選べない問題に直面します。
そこで、これをまず解決する必要がりますので、Add an Accountというボタンを押して、Apple IDでサインインします。
そうすると、一応ビルドはできるようになります。しかし、そのままだとCodeSignの「キーチェーンログインのパスワードを入力してください」でパスワードを繰り返し求められて先に進みませんでした。
そこで、https://developer.apple.comからApple Developerにサインインして証明書をダウンロードしました。
ここで、該当するProfileをダウンロードしてダブルクリックしたら、動作するようになりました。
こんなに簡単だったっけって感じです。。あとで落とし穴がないか怖いです。
1
Xcodeのデベロッパーライセンスを更新するときにやることをまとめておく。
まず、Appleからライセンス切れる旨を伝えるメールが来るので購入する。
次に、Apple Developerにログインして、Certificates&Identifiers & ProfilesのDevicesを選ぶ。
Continueを選ぶ。下記のようにデバイスリストを最新にしてくださいというメッセージが表示される。
Now that you’ve started a new membership year, make sure your device list is up to date. Once you complete this process, new devices can be added.
Select the devices you’d like to keep for this membership year and deselect the devices you’d like to remove. Only your currently enabled devices are shown and all previously disabled devices will be removed automatically. To keep a previously disabled device, visit the All Devices page, enable the devices you’d like to keep, and return to this page.
Continueを押下
この画面の「I acknowledge that any devices I disable during this membership year will continue to count towards my total registered devices.」にチェックを入れてResetする。
私は以上だけでした。
1
データ分析とWebアプリ開発をしているエンジニアのMacの設定方法です。Mac book Pro 2019,2020でそれぞれBig SurとCataliaにて設定したものを備忘録として書いたものです。
CapsLockで英語/日本語の切り替えができるようにします。
タッチパッドの指の動かし方と画面の遷移方向を設定します。
デフォルトのpngだと容量が大きすぎるので、jpgに変更して容量が小さくなるようにします。
defaults write com.apple.screencapture type 拡張子
で拡張子を指定すれば変更できるので、
defaults write com.apple.screencapture type jpg
killall SystemUIServer
exit
とします。jpgをpng,pdf,tiffなど任意のものに変更可能です。
terminalにaliasを設定して、任意のコマンドを自分好みのコマンドで打てるようにします。
使用シェルがbashなら~/に.bash_profile
と.bashrcを作成し、zshなら.zshrcと.zshprofileを作成し設定します。ログイン時に実行されるのは.bash_profileと.zshprofileで、.bashrcと.zshrchはターミナル起動時にいつも実行されます。
私はBig Surだったので、.zshrcに
alias o='open ./'
alias p='pwd'
alias l='ls'
alias n='cd /Users/masaya/Desktop;open /Users/masaya/Desktop'
と書きました。設定を反映するために再起動をするか
source ~/.zshrc
します。
いずれも公式サイトにアクセスして、ファイルをダウンロードすれば特に設定なしで使えるものです。
項目 | ||
Chrome | 普通にインストールします。dmgファイルをインストールしてから、ダブルクリックで起動して画面の操作にしたがってアイコンを移動するだけです。インストールあと、dmgファイルはゴミ箱に移動です、 | |
VScode | https://azure.microsoft.com/ja-jp/products/visual-studio-code/からダウンロード | |
Atom | https://atom.io/からダウンロード |
その他、Vivaldi,Firefoxなども同じようにインストールします。
データ可視化用にTableau Publicを入れます。これも公式からダウンロードしてぽちぽちするだけです。
Macで無料で使えるFTPソフトです。
https://developer.android.com/studioからインストールします。
AppStoreから最新をインストールします。11GB程度と非常に重いので注意。
証明書関係が面倒ですが、以前のメモには下記のように書いてあります。
めちゃくちゃ苦労した。全て記録に残せたわけではないが、少なくとも以前のMacは必要なかった。AppleDeveloperサイトに行って、ログインする。Certificates, Identifiers & ProfilesからPlatformのカラムがALLのもののうち、DevelopmentとDeistributionを選んで、ダウンロードしてキーチェーンに登録する。これを新しい方でダブルクリックして登録する。それと、app developer idでパソコンでログインして、新しいMacを登録する。そうするとチームが選べるようになる。基本的には以上の二つでOK.ってこんだけのことだったっけ?
sudo gem install cocoapods
でインストールします。
以前はAnacondaを使っていましたが、有料化したので使うのはやめました。有料のAnacondaをインストールしたいなら、公式からダウンロードしてぽちぽちすればいけます。
https://www.anaconda.com/products/individual
Github用に .sshをホームディレクトリに配置して設定します。
ホーム画面で.sshディレクトリを作成します。
% mkdir ./.ssh
masaya@local-host ~ % cd .ssh
鍵を作成します。
% ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/masaya/.ssh/id_rsa): /Users/masaya/.ssh/id_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/masaya/.ssh/id_rsa.
Your public key has been saved in /Users/masaya/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:chw/VNuyHQ9D0DLooAVRfu9KtEK4TXoOVh36Gkw2c9U masaya@local-host
The key's randomart image is:
+---[RSA 3072]----+
| o+. .oo. |
| .o ..o=. |
| ooo+ +oE |
| .o B.+ + = |
| o S * o . .|
| & * + |
| = * + . |
| . + = . |
| o . |
+----[SHA256]-----+
権限を読み取り専用に変更して
chmod 600 id_rsa
情報をコピーして
% pbcopy < ~/.ssh/id_rsa.pub
GitHubに行って、アイコンをクリックしてから「settings」 > 「SSH and GPG keys」 > 「New SSH Key」と進んで、情報を貼り付ける
あとは下記で疎通できることを確認します。
% ssh -T git@github.com
The authenticity of host 'github.com (13.**.40.48)' can't be established.
RSA key fingerprint is SHA256:********pJWGl7E1IGOCspRomTxdCARLviKw6E5SY8.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'github.com,13.***.40.48' (RSA) to the list of known hosts.
Hi N****! You've successfully authenticated, but GitHub does not provide shell access.
https://qiita.com/unsoluble_sugar/items/14bea376d8e6fce82eb3
macOSでデスクトップを表示 :「Fn」+「F11」
隠しファイルの表示;command shift .
1
クロスプラットフォームアプリケーションのフレームワークであるIonicをMacにインストールする方法について紹介します。
まず、node.jsをインストールする必要があります。インストールしていない方はこちらに最も簡単なインストール方法を記載していますのでご覧ください。
npm経由でのインストールとなりますので、sudo npm install -g @ionic/cliコマンドを打ちます。
% sudo npm install -g @ionic/cli
Password:
⸨ ░░░░░░░░░░░░░░░⸩ ⠇ loadDep:yallist: sill resolveWithNewModule smart-buffer@
ionic -vでバージョンが表示されたらインストール完了です。
% ionic -v
6.12.3
ionic startコマンドで簡単なアプリを作ってみます。
% ionic start
Pick a framework! ?
Please select the JavaScript framework to use for your new app. To bypass this
prompt next time, supply a value for the --type option.
? Framework: (Use arrow keys)
❯ Angular | https://angular.io
React | https://reactjs.org
今回はAngularを選びます。プロジェクト名やCapacitorがいるかなど聞かれますので、入力します。CapacitorはIonicのプロジェクトをAndroid,iOS,デスクトップアプリとして動作させる環境(ランタイム)です。Web用なら入りませんが、今回は入れておきます。
? Project name: my-first-app
Let's pick the perfect starter template! ?
Starter templates are ready-to-go Ionic apps that come packed with everything
you need to build your app. To bypass this prompt next time, supply template,
the second argument to ionic start.
? Starter template: tabs
✔ Preparing directory ./my-first-app in 1.93ms
✔ Downloading and extracting tabs starter in 998.19ms
? Integrate your new app with Capacitor to target native iOS and Android? (y/N)
y
ダウンロードしたら、プロジェクトへ移動します。
% cd my-first-app/
ionic serveコマンドでビルドしてみます。
% ionic serve
> ng run app:serve --host=localhost --port=8100
アプリケーションが立ち上がったら完了です。
Macで無料で使えるFTPソフトであるFIleZillaをインストールする方法について解説します。
まず、公式サイトからFileZillaの圧縮ファイルをダウンロードします。
https://filezilla-project.org/download.php?type=client#close
FileZilla_3.51.0_macosx-x86.app.tar.bz2というファイルがダウンロードされますので、ダウンロード先でダブルクリックして解凍します。
下記のようなアイコンのついたものが作成されます。
これがアプリケーション本体なので、このファイルをコピペして、アプリケーションフォルダへ移動して完了です。
普通にダブルクリックしたら起動するので、あとはサーバ情報を入力して接続します。
1
日本ではhomebrewでインストールする方法ばかりが紹介されていますが、海外ではほとんど情報がなくマイナーな方法です。node.jsの公式からダウンロードしてインストールする方法が多く紹介されていますが、こちらの方が簡単なので今回はその方法を紹介します。
https://nodejs.org/en/にアクセスしてinstallerをダウンロードします。
LTSと書いてあるものがサポートの長い安定版です。
ダウンロードしたら、ファイルをクリックして起動させます。
途中、インストール先が表示されるのでメモっておきます。あとは画面の指示に従って進みます。完了したらインストーラはゴミ箱に移動していいですかと聞かれます。これが表示されたらもうこれだけでインストール完了です。
ターミナルで下記のように打ち込んでバージョンが表示されたらOKです。
% node -v
v14.15.1
もしバージョンが表示されない場合、下記のコマンドを打って現在のパスを通している場所を表示させ、インストーラで保存先に指定していた場所が入っているかどうかを確かめます。
% echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
node.jsがちゃんと動作しているか簡単なコマンドで調べてみます。
% node
Welcome to Node.js v14.15.1.
Type ".help" for more information.
> console.log('hello node.js')
hello node.js
undefined
ちゃんと動作していることが確認できたら、control + cを2回打って終了します。
1
この記事ではoandapyV20を使ってオーダブック、ポジションブックを取得する方法について記載します。
oandapyV20では、オーダーブックをとるためにはoandapyV20.endpoints.instrumentsのInstrumentsOrderBookというクラスで/v3/instruments/{instrument}/orderBookをGet通信で叩きます。
ポジションブックの場合は、oandapyV20.endpoints.instrumentsのInstrumentsPositionBookというクラスで/v3/instruments/{instrument}/positionBookをGet通信で叩きます。
いずれの場合もparamsで指定できるパラメータはinstrumentとtimeだけです。instrumentは必須引数ですが、timeは指定しない場合は最新が返されます。timeだUNIXTIMEを文字列型で渡します。最新を取りたい場合は、paramsは{}でいいと思います。
オーダーブックもポジションブックもほとんど同じなので、今回はオーダブックで説明したいと思います。
ドル円の最新のオーダーブックを取得するコードはこちらです。ポジションブックを見たい場合はInstrumentsPositionBookを使ってください。
# -*- coding: utf-8 -*-
import json
from oandapyV20 import API
from oandapyV20.endpoints.pricing import PricingInfo
from oandapyV20.exceptions import V20Error
import oandapyV20.endpoints.instruments as instruments
import datetime
import pandas as pd
def main():
account_id="XXX-XXX-XXXXXXX-XXX"
access_token = "***************************************************************"
api = API(access_token=access_token, environment="practice")#or live
params ={}
r = instruments.InstrumentsOrderBook(instrument="EUR_USD",
params=params)
api.request(r)
data = (r.response)
print(data)
if __name__ == "__main__":
main()
返り値の中身を詳細に見てみます。所期のデータはdata[‘orderBook’][‘buckets’]にリストで返ってきています。
#まずはなんの型が帰ってきているかきます。
(Pdb) type(data)
<class 'dict'>
(Pdb) data.keys()
dict_keys(['orderBook'])
(Pdb) type(data['orderBook'])
<class 'dict'>
(Pdb) data['orderBook'].keys()
dict_keys(['instrument', 'time', 'unixTime', 'price', 'bucketWidth', 'buckets'])
(Pdb) data['orderBook']['instrument']
'EUR_USD'
(Pdb) data['orderBook']['time']
'2020-12-07T12:00:00Z'
(Pdb) data['orderBook']['price']
'1.21131'
(Pdb) data['orderBook']['bucketWidth']
'0.00050'
(Pdb) type(data['orderBook']['buckets'])
<class 'list'>
(Pdb) len(data['orderBook']['buckets'])
5548
(Pdb) data['orderBook']['buckets'][0]
{'price': '0.00000', 'longCountPercent': '0.4861', 'shortCountPercent': '0.3107'}
(Pdb) data['orderBook']['buckets'][1000]
{'price': '1.12050', 'longCountPercent': '0.0351', 'shortCountPercent': '0.0200'}
(Pdb) data['orderBook']['buckets'][3000]
{'price': '7.59750', 'longCountPercent': '0.0000', 'shortCountPercent': '0.0150'}
(Pdb) data['orderBook']['buckets'][5000]
{'price': '107.77800', 'longCountPercent': '0.0025', 'shortCountPercent': '0.0000'}
綺麗な最終結果だけが欲しいならdata[‘orderBook’][‘buckets’]をPandasに変換します。
(Pdb) pd.DataFrame(data['orderBook']['buckets'])
price longCountPercent shortCountPercent
0 0.00000 0.4861 0.3107
1 0.00050 0.1428 0.0802
2 0.00100 0.2956 0.0451
3 0.00150 0.0576 0.0251
4 0.00200 0.0401 0.0225
... ... ... ...
5543 34887878.00000 0.0025 0.0000
5544 100000000.00000 0.0025 0.0000
5545 1000000000.00000 0.0000 0.0050
5546 7000000000.00000 0.0000 0.0025
5547 9999999999.00000 0.0025 0.0000
[5548 rows x 3 columns]
https://developer.oanda.com/rest-live-v20/instrument-ep/
https://developer.oanda.com/rest-live-v20/instrument-ep/
ローソクを取得したい場合はこちらをご覧ください
現在の価格をリアムタイムに欲しい場合はこちらをご覧ください
1
この記事ではoandapyV20を使ってStreaming配信でリアルタイムに価格を取得する方法について記載します。
Streaming配信は非常に便利であるものの、最大で250msごとのデータしか提供されませんので急激な値動きまで把握できるわけではない事に注意が必要です。公式では「1秒間に4回のウィンドウを作成し、それぞれのウィンドウの最後で有効な値を返す」という記載があります。詳細は記載されていないものの、250ms程度のデータであること、アカウントごとにデータを生成するので、すべての人に同じデータが配信されるわけではない事に留意が必要です。
ストリーミング配信は/v3/accounts/{accountID}/pricing/streamにGet通信でアクセスする事で提供されます。
oandapyV20を使った基本のコードはこちらです(ドル円の価格を取得)。
# -*- coding: utf-8 -*-
import json
from oandapyV20 import API
from oandapyV20.endpoints.pricing import PricingInfo
from oandapyV20.exceptions import V20Error
import oandapyV20.endpoints.pricing as pricing
import oandapyV20.endpoints.instruments as instruments
import datetime
import pandas
def main():
account_id="XXX-XXX-XXXXXXX-XXX"
access_token = "******************************************************************"
api = API(access_token=access_token, environment="practice")#or live
params ={
"instruments": "USD_JPY,EUR_JPY"
}
r = pricing.PricingStream(accountID=account_id, params=params)
rv = api.request(r)
maxrecs = 100
for ticks in rv:
print(json.dumps(ticks, indent=4),",")
if maxrecs == 0:
r.terminate("maxrecs records received")
if __name__ == "__main__":
main()
これを実行すると、価格のリアルタイムデータが取得でします。ticksという変数にはこのような値が入ります。
{
"type": "PRICE",
"time": "2020-12-04T21:59:55.602697089Z",
"bids": [
{
"price": "104.185",
"liquidity": 250000
}
],
"asks": [
{
"price": "104.191",
"liquidity": 250000
}
],
"closeoutBid": "104.177",
"closeoutAsk": "104.199",
"status": "non-tradeable",
"tradeable": false,
"instrument": "USD_JPY"
} ,
基本的には通貨ペア(Instruments)しかカスタマイズしないと思います。通貨ペアを変更したいときはparamsの値を変えてください。2つ以上のペアを同時にデータ取得したいときは、paramsにそれぞれのペアをカンマで区切って指定すればOKです。例えば、2つを指定したいときはこのように指定します。
params ={
"instruments": "USD_JPY,EUR_JPY"
}
そうすると下記のデータが返ってきます。
{
"type": "PRICE",
"time": "2020-12-04T21:59:53.324563034Z",
"bids": [
{
"price": "126.254",
"liquidity": 250000
}
],
"asks": [
{
"price": "126.320",
"liquidity": 250000
}
],
"closeoutBid": "126.238",
"closeoutAsk": "126.336",
"status": "non-tradeable",
"tradeable": false,
"instrument": "EUR_JPY"
} ,
{
"type": "PRICE",
"time": "2020-12-04T21:59:55.602697089Z",
"bids": [
{
"price": "104.185",
"liquidity": 250000
}
],
"asks": [
{
"price": "104.191",
"liquidity": 250000
}
],
"closeoutBid": "104.177",
"closeoutAsk": "104.199",
"status": "non-tradeable",
"tradeable": false,
"instrument": "USD_JPY"
} ,
{
"type": "HEARTBEAT",
"time": "2020-12-06T11:28:32.333476447Z"
} ,
リアルタイムでデータが取得できるのはとても便利です。
“USD_JPY”,’EUR_JPY’,’GBP_JPY’,’AUD_JPY’,’NZD_JPY’,’CAD_JPY’,’CHF_JPY’,
“EUR_USD”,’GBP_USD’,’AUD_USD’,’NZD_USD’,’USD_CAD’,’USD_CHF’,’USD_CNH’,
‘EUR_GBP’,’EUR_AUD’,’EUR_NZD’,’EUR_CHF’,’GBP_AUD’
https://developer.oanda.com/rest-live-v20/pricing-ep/
https://developer.oanda.com/rest-live-v20/pricing-ep/
ローソクチャートを取得したいときはこちらの記事をご覧ください。
GCP(Google Cloud Platform)は、GoogleがGmail,Youtubeなど一般向けに開発しているサービスのバックエンドで使われているクラウド基盤を外部に公開したものです。GoogleはGCPですべてのサービスを運用しており、同じ環境を安価に利用することができます。
「Datacenter as a Computer」という言葉に集約されるように、GCPではGoogleの世界中にあるコンピュータをまとめて一つのコンピュータのように扱えるようにするというコンセプトがあり、エンジニアに取って使いやすいサービスとなっています。
GCPは2008年に公開されたGoogleAppEngineが元になっており、IaaSとして始まったAWSとは異なり当初はPaaSとして導入されました。その後、2011年にGoogleCloudSQL ,GoogleCloudStoragが導入され、2013年にIaaSであるGCEが導入され現在の主要サービスがそろいました。
東京リージョンが開設されたのは2016年であり、まだまだ日本では導入後まもないサービスです。
GCPではユーザー、課金アカウント、プロジェクトという3つの基本概念があります。ユーザーとは、Googleのサービスを利用するときに利用しているIDのことです。GCP専用のアカウントは存在せず、GoogleアカウントにGCPの情報を紐づけることとなります。プロジェクトとは、GCPの中で機能やサービスを束ねるためのものです。プロジェクト内では各サービスの連携は容易ですが、プロジェクトを跨ぐことは基本的にはできません。さらにプロジェクトには1つの課金アカウントが設定されている必要があり、こちらに対して請求が来る事になります。
GCPには様々なサービスがありますが、代表的なものを下記にまとめました。
分類 | 名称 | 機能 |
コンピューティング | ComputeEngine | クラウド上で仮想マシンを立ち上げられます。OS以上のレイヤーを自由に設定できる一方で、環境構築やメンテナンスを自分でやらなければならないため上級者向けです。 |
コンピューティング | AppEngine | アプリケーションを運用してくれるPaaSサービス。GUIのアプリのホスティングサービス。基本的にはリクエスト受け取り後、60秒以上の処理はできない。ローカルファイルへのアクセスは禁止されている。 |
コンピューティング | CloudFunctions | 関数ベースでGUIを伴わないサービスについてはこちらで十分。関数プログラムをホスティングできるサーバレスなコンピューテング環境。 |
分類 | 名称 | 機能 |
ストレージ | Cloud Storage | ストレージサービス。データ保存だけではなく、HTMLや画像などの静的なデータを直接Webに公開することも可能。バケットと呼ばれるコンテナで管理される。ファイルやフォルダと言ったGCS上のデータはオブジェクトと呼ばれる。オブジェクト数に上限はないが、1オブジェクト5TBまで。 |
ストレージ | SQL | MySQLなどのリレーショナルデータベース |
ストレージ | Firestore | NoSQLサービス |
ストレージ | Bigtable | スケーラブルなNoSQLサービス |
ビッグデータ | BigQuery | 低コストなビッグデータ解析用サービス。SQLでデータ取得可能。読み出しに強いのがSQLとの違い。 |
その他、様々なAPIが提供されています。
AmazonやMicrosoftと比較したGoogleの特徴の一つは、インフラを自社で保有していることです。Googleでは、データセンタ、光ファイバ回線などを独自で設計し導入しています。世界規模のクローズトネットワークを保有している数少ない事業者がGoogleですが、これによりサーバ間のデータ転送は極めて高速で可用性に優れているという特徴があります。また、元々、世界中の個人に対してサービスを提供してきた背景から、スケーラビリティと大規模処理に非常に強く、大量のデータを保有しているために機械学習などのモデル精度に優れています。日本ではAWSが最も勢いに乗っていると思いますが、独自のサービスやデータに強いというところで一定の存在感を持ったサービスであり続ける可能性が高いです。
https://cloud.google.com/iam/docs/service-accounts?hl=ja
GCPではメンバーとサービスアカウントという概念があります。メンバーはプロジェクトに登録した個々のGoogleアカウント(ユーザーアカウント)とサービスアカウントであり、サービスアカウントはアプリケーションなどで使用される特別なアカウントです。リソースへのアクセスの際はサービスアカウントを介する必要があります。
重要なのは、サービスアカウントを作成するとメンバーにも登録されることです。メンバーを登録してもサービスアカウントは作成されないです。サービスアカウントの方が強いイメージです、
もし証明書を介してリソースにアクセスする際、下記の手順を踏みます。
という流れになります。確証はありませんが、証明書の権限は発行された際のメ権限を反映しているような挙動になりました。そんなはずはないですが、でもそれで少し詰まりました。おそらく多少はタイムラグがあるということかもしれないです。
1
この記事ではoandapyV20を使ってローソクチャートを取得する方法について記載します。ローソクの長さ、取得データの種類、取得期間の指定方法なども含めて記載します。
oandapyV20では、PricingInfoというクラスで/v3/instruments/{instrument}/candlesをGet通信で叩いています。
ドル円のローソクチャートを取得基本のコードはこちらです。
# -*- coding: utf-8 -*-
import json
from oandapyV20 import API
from oandapyV20.endpoints.pricing import PricingInfo
from oandapyV20.exceptions import V20Error
import oandapyV20.endpoints.instruments as instruments
import datetime
import pandas
def main():
account_id="XXX-XXX-XXXXXXX-XXX"
access_token = "***************************************************************"
api = API(access_token=access_token, environment="practice")#or live
params = {"instruments": "USD_JPY"}
pricing_info = PricingInfo(accountID=account_id, params=params)
r = instruments.InstrumentsCandles(instrument="USD_JPY",
params={
"granularity": "S15", # ロウソク足の種類を選択
"alignmentTimezone": "Japan", # タイムゾーン
#"from":datetime.datetime.now()
}
)
data = api.request(r)
for candle in r.response["candles"]:
print(candle)
if __name__ == "__main__":
main()
データの返り値であるcandleの変数には下記の値が入ります。
(Pdb) candle
{'complete': True, 'volume': 117597, 'time': '2020-11-05T08:00:00.000000000Z', 'mid': {'o': '104.314', 'h': '104.388', 'l': '103.360', 'c': '103.424'}}
上記ではローソクの長さを15秒に指定しますが、最短で5秒、最大で1ヶ月まで変更できます。oandapyV20では、InstrumentsCandlesをインスタンス化する際のparamという変数で様々な取得条件を指定しますが、ローソク足の長さはgranularityというキーで指定します。これに対応する値は文字列型で下記で指定します。
r = instruments.InstrumentsCandles(instrument="USD_JPY",
params={
"granularity": "S15", # ロウソク足の種類を選択
"alignmentTimezone": "Japan", # タイムゾーン
#"from":datetime.datetime.now()
}
)
引数 | 間隔 |
---|---|
S5 | 5秒間 |
S10 | 10秒間 |
S15 | 15秒間 |
S30 | 30秒間 |
M1 | 1分間 |
M2 | 2分間 |
M3 | 3分間 |
M4 | 4分間 |
M5 | 5分間 |
M10 | 10分間 |
M15 | 15分間 |
M30 | 30分間 |
H1 | 1時間 |
H2 | 2時間 |
H3 | 3時間 |
H4 | 4時間 |
H6 | 6時間 |
H8 | 8時間 |
H12 | 12時間 |
D | 1日 |
W | 1週間 |
M | 1ヶ月 |
総データ取得期間を指定する際は、同様にparamという辞書の中で指定します。この中でfromとtoというキーで時間を「文字列型」のUNIXTIMEで指定します。
r = instruments.InstrumentsCandles(
instrument="USD_JPY",
params={
"granularity": "D",
"alignmentTimezone": "Japan",
"from":str((datetime.datetime.now()-datetime.timedelta(days=30)).timestamp()),
"to":str((datetime.datetime.now()-datetime.timedelta(days=25)).timestamp())
}
)
データの期間を指定する代わりに、キャンドルの本数で総データ取得期間を指定することもできます。デフォルトは500本となります。キャンドルの本数で帰って来るデータの量を指定したい場合はcount引数を整数で指定します。なお、期間をfrom,toで指定した場合こちらは使用できません。countの最大は5000本です。
r = instruments.InstrumentsCandles(
instrument="USD_JPY",
params={
"granularity": "D",
"alignmentTimezone": "Japan",
"count":100}
)
ask,bid,middleのいずれのローソクを取得するかについてはparamsでpriceキーで指定できます。“M” はmidpoint candles、 “B” はbid candles)、 “A” はask candlesとのことで、デフォルトは”M”となります。
midの場合
(Pdb) candle
{'complete': True, 'volume': 117597, 'time': '2020-11-05T08:00:00.000000000Z', 'mid': {'o': '104.314', 'h': '104.388', 'l': '103.360', 'c': '103.424'}}
bidの場合
(Pdb) candle
{'complete': True, 'volume': 117597, 'time': '2020-11-05T08:00:00.000000000Z', 'bid': {'o': '104.308', 'h': '104.382', 'l': '103.354', 'c': '103.418'}}
これはinstrument引数で指定します。通貨のペアを/ではなく_でつないで指定します。
例えば,よく使うものを列挙すると
ペア | コード |
ドル円 | USD_JPY |
ドルユーロ | EUR_USD |
ユーロ円 | EUR_JPY |
https://www.oanda.jp/course/currencypair
https://oanda-api-v20.readthedocs.io/en/latest/endpoints/instruments/instrumentlist.html
https://developer.oanda.com/rest-live-v20/instrument-ep/
リアルタイムでデータを取得したい場合はこちらの記事をご覧ください。
1
Google Adsenseでは、収益が1000円程度を超えると住所確認のために郵送でPINコードが発送されます。振り込み準備に向けて、これに印字された6桁の番号をAdsenseのHPで入力し、住所が正しいことを認証伝えておく必要があります。記載された通りに実施するとうまくいきませんので、この方法について解説します。
収益が一定を超えると、Adsenseからメールが届きます。
AdSense でお知らせいただいたお支払い先住所宛に、個人識別番号(PIN)を記載したハガキを 11月 18, 2020 付で発送いたしました。 |
ハガキが届きましたら、このメールにある [住所を確認する] をクリックし、AdSense のホーム画面で PIN をご入力ください。あるいは AdSense アカウントにログインして、ホーム画面で直接、同じ手順を行っていただくこともできます。 |
重要: この PIN による住所確認が最初の郵送日から 4 か月以内に行われなかった場合、広告配信が停止されますのでご注意ください。 |
4ヶ月以内に行わないと広告停止されると書いてありますが、葉書が到着するまでに結構時間がかかるので不安になります。日本では結構時間がかかるようで心配は入りません。私は2つのサイトで実施したことがありますがそれぞれ3週間弱かかりました。直近のサイトについては、11月18日発送で自宅に届いたのは12月4日でした。18日かかったことになります。
葉書の通りにやってもうまくいきません。葉書では歯車のアカウントからPINを送信してくださいと書いてありますが、アカウント の画面にはPINのことなど書いておりません。PCでAdsenseにログインして、トップページから辿る必要があります。
赤丸で囲ったところから入力するようにしてください。
1
フロントエンドアプリケーションフレームワークであるAngular(Ionic)で非同期通信を実装する方法をサンプルアプリとして紹介します。動作確認用にPythonで作成したバックエンドコード付きです。
Angularの場合、非同期通信を実装するにはHttpClientModuleをapp.module.tsに追加して、tsファイルで呼び出して使うだけです。AngularはReactと異なりフルスタックなので、この辺の安心感はReactにはるかに勝ると思います。
ソースコードの素性ですが、Ionic(Aunglar)のblankアプリから実装しました。なお、バックエンドのサンプルコードも作成しましたが、こちらはPythonのFlaskを使っています。Flaskでホスティングした http;//127.0.0.1:5000 のURLを叩いてデータを取ってくるアプリです。
GitHubにコードあげたのでそのまま動作確認できると思います。
Angular CLI: 10.0.5
Ionic CLI : 6.10.0
Node: 12.18.0
Python 3.7.3
Flask 1.1.2
Flask-Cors 3.0.9
app.module.tsに
import { HttpClientModule } from ‘@angular/common/http’;
を追加します。importするのも忘れずに
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { HttpClientModule } from '@angular/common/http';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
@NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [BrowserModule,HttpClientModule, IonicModule.forRoot(), AppRoutingModule],
providers: [
StatusBar,
SplashScreen,
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
],
bootstrap: [AppComponent]
})
export class AppModule {}
Ionicの場合、moduleファイルが複数あるけど、app.module.tsにだけ書いておけば問題ないです。
こちらには
import { HttpClient } from ‘@angular/common/http’;
import { DomSanitizer } from ‘@angular/platform-browser’;
の2つを追加します。あとは処理を書くだけです。
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { DomSanitizer } from '@angular/platform-browser';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
unsafeImageUrl:any;
imageUrl:any;
constructor(
private http: HttpClient,
private sanitizer:DomSanitizer)
{
this.hello();
}
hello(){
this.http.get('http://127.0.0.1:5000',{responseType:'blob'})
.subscribe(
(res:any) => {
console.log(res);
this.unsafeImageUrl = URL.createObjectURL(res);
this.imageUrl = this.sanitizer.bypassSecurityTrustUrl(this.unsafeImageUrl);
})
}
}
htmlはを追加するだけです。
<ion-header [translucent]="true">
<ion-toolbar>
<ion-title>
Blank
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">Blank</ion-title>
</ion-toolbar>
</ion-header>
<div id="container">
<img [src]=imageUrl>
<strong>Ready to create an app?</strong>
<p>Start with Ionic <a target="_blank" rel="noopener noreferrer" href="https://ionicframework.com/docs/components">UI Components</a></p>
</div>
</ion-content>
これでOK.anyを指定してしまっていますので書き方知っていたら教えてください。
バックエンドはこちら
# -*- coding: utf-8 -*-
import io
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from flask import Flask, send_file
from flask_cors import CORS
import json
app = Flask(__name__)
CORS(app)
@app.route('/',methods=["GET","POST"])
def hello():
image = io.BytesIO()
x = np.linspace(0, 10)
y = np.sin(x)
plt.plot(x, y)
plt.savefig(image, format='png')
image.seek(0)
return send_file(image,
attachment_filename="image.png",
as_attachment=True)
if __name__ == "__main__":
app.run(host='127.0.0.1',debug=True)
1
フロントエンドアプリケーションフレームワークであるAngular(Ionic)を使って、非同期通信で画像を読み込む方法をサンプルアプリとして紹介します。動作確認用にPythonで作成したバックエンドコード付きです。
Angularの場合、非同期通信を実装するにはHttpClientModuleをapp.module.tsに追加して、tsファイルで呼び出して使うだけです。画像の場合は、さらにresponseTypeに’blob’形式を指定し、DomSanitizerでサニタイズして読み込みます。HTML側は<img [src]=imageUrl>で行けます。
AngularはReactと異なりフルスタックなので、この辺の安心感があります。
app.module.tsに
import { HttpClientModule } from ‘@angular/common/http’;
を追加します。importするのも忘れずに
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { HttpClientModule } from '@angular/common/http';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
@NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [BrowserModule,HttpClientModule, IonicModule.forRoot(), AppRoutingModule],
providers: [
StatusBar,
SplashScreen,
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
],
bootstrap: [AppComponent]
})
export class AppModule {}
Ionicの場合、moduleファイルが複数あリますが、app.module.tsにだけ書いておけば問題ないです。
こちらには
import { HttpClient } from ‘@angular/common/http’;
import { DomSanitizer } from ‘@angular/platform-browser’;
の2つを追加します。あとは処理を書くだけです。
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { DomSanitizer } from '@angular/platform-browser';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
unsafeImageUrl:any;
imageUrl:any;
constructor(
private http: HttpClient,
private sanitizer:DomSanitizer)
{
this.hello();
}
hello(){
this.http.get('http://127.0.0.1:5000',{responseType:'blob'})
.subscribe(
(res:any) => {
console.log(res);
this.unsafeImageUrl = URL.createObjectURL(res);
this.imageUrl = this.sanitizer.bypassSecurityTrustUrl(this.unsafeImageUrl);
})
}
}
これでOK。anyを指定してしまっていますので書き方知っていたら教えてください。
htmlはを追加するだけです。
<ion-header [translucent]="true">
<ion-toolbar>
<ion-title>
Blank
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">Blank</ion-title>
</ion-toolbar>
</ion-header>
<div id="container">
<img [src]=imageUrl>
<strong>Ready to create an app?</strong>
<p>Start with Ionic <a target="_blank" rel="noopener noreferrer" href="https://ionicframework.com/docs/components">UI Components</a></p>
</div>
</ion-content>
# -*- coding: utf-8 -*-
import io
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from flask import Flask, send_file
from flask_cors import CORS
import json
app = Flask(__name__)
CORS(app)
@app.route('/',methods=["GET","POST"])
def hello():
image = io.BytesIO()
x = np.linspace(0, 10)
y = np.sin(x)
plt.plot(x, y)
plt.savefig(image, format='png')
image.seek(0)
return send_file(image,
attachment_filename="image.png",
as_attachment=True)
if __name__ == "__main__":
app.run(host='127.0.0.1',debug=True)
1
Flask上で画像を操作する際のソースコードのパターンについてですが、 画像の生成元をどうするかというもので3パターン、画像の最終的な処理方法をどうするかというもので2パターンで(組み合わせで)合計6パターンがあると思います。Flaskで画像処理を実装しようとするとこれらを書き分ける必要がありますのでそれについて記載します。
画像の生成元の3つとは
の3つです。
最終的な処理方法として2つあるというのは、
の2つです。メタ情報だけ抽出して文字列で返す場合などもあると思いますが、これはJSONなどでリターンすればOKなので上記6パターンで対応できると思います。
Flaskで画像を操作したいと思うと、この6パターンについてソースコードを書き分ける必要があり、かなり大変です。
しかし、幸いなことに、画像をどこかに保存する場合とクライアント側へ返す場合については画像をメモリ上でBlob形式であらかじめ保存することができれば同時に対応できますので、事実上かき分けなければならないのは3パターンとなります。
この記事では、画像をメモリ上でBlob形式で書き出すコードを使いながらこの3パターンについて整理したいと思います。
なお、ここでは処理後の画像の保存先としてGoogle Cloud Storageを利用した例で説明しますが、適宜AWSのS3、ローカルのフォルダの場所などと読み替えて下さい。今回記載するサンプルコードは下記の3つです。
1. 画像をFlaskの関数内で生成し、メモリ上でBlob形式で保存したのちにGCSへ保存しクライアント側へ返す
2. 画像をクライアントから受け取り、メモリ上でBlob形式で保存したのちにGCSへ保存しクライアント側へ返す
3. 画像をGSCから読み取り、メモリ上でBlob形式で保存したのちにGCSへ保存しクライアント側へ返す
# coding: utf-8
import os
import io
import time
import string
import random
import datetime
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from PIL import Image
import cv2
from flask import Flask, render_template, request, redirect, url_for, send_from_directory,send_file
from flask_cors import CORS
from google.cloud import storage
from google.cloud.storage import Blob
import inspect
import numpy as np
import cv2
app = Flask(__name__)
CORS(app)
@app.route('/',methods=["GET","POST"])
def hello():
buf = io.BytesIO()
x = np.linspace(0, 10)
y = np.sin(x)
plt.plot(x, y)
plt.savefig(image, format='png')
buf.seek(0)
destination_blob_name = "path/to/your/file_on_gcs.jpg"
blob = Blob(destination_blob_name, bucket)
blob.upload_from_string(data=buf.getvalue(), content_type=content_type)
return send_file(
buf,attachment_filename=source_blob_name,as_attachment=True
)
if __name__ == "__main__":
app.run(host='127.0.0.1',debug=True)
ポイントは2つあって、一つ目はGUIに対応していないFlask上でmatplotlibが動作するようにmatplotlib.use(‘Agg’)というコードを入れていること、二つ目はsavefigの部分でメモリ上でファイルを書き出していることです。ローカルで動かす場合は、普通にHDD(SSD?)にjpgなどで書き出しても問題ないと思いますが、クラウドなどだとローカルへのアクセスが禁止されていることが往々にしてあります。この場合に備えて、メモリ上でファイルの読み書きを行うioモジュールを使ってメモリ上に画像を出力しています。ここは個人的に結構ポイントです。
それでは次に既に保存されている画像を取ってくる場合です。
クラウドからデータを持ってきます。重いデータなどは予め画像にしておくと便利ですのでよく使っています。
# coding: utf-8
import os
import io
import time
import string
import random
import datetime
import numpy as np
from PIL import Image
import cv2
from flask import Flask, render_template, request, redirect, url_for, send_from_directory,send_file
from flask_cors import CORS
from google.cloud import storage
from google.cloud.storage import Blob
import inspect
import numpy as np
import cv2
app = Flask(__name__)
CORS(app)
@app.route("/", methods=["GET", "POST"])
def hello():
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = './for-dev-268800-ed3aecf9b014.json'
storage_client = storage.Client()
bucket = storage_client.get_bucket('for-dev-268800.appspot.com')#"'for-dev-268800.appspot.com'
source_blob_name = "path/to/your/file_on_gcs.jpg"
#検索する場合はここを使う
"""
blobs = bucket.list_blobs(prefix="")
for blob in blobs:
print(blob.name)
print(dir(blob))
print(blob.content_type)
source_blob_name = blob.name
content_type = blob.content_type
print(inspect.getfullargspec(bucket.list_blobs))
"""
blob = bucket.get_blob(source_blob_name)
buf = io.BytesIO()
blob.download_to_file(buf)
buf.seek(0)
destination_blob_name = "path/to/your/file_on_gcs.jpg"
blob = Blob(destination_blob_name, bucket)
blob.upload_from_string(data=buf.getvalue(), content_type=content_type)
return send_file(
buf,attachment_filename=source_blob_name,as_attachment=True
)
if __name__ == "__main__":
app.run(host='127.0.0.1',debug=True)
上記ファイルを実行しFlaskサーバが立てたあと、こちらについてはブラウザなどで直接叩いたいただければ問題ありません。
最後のパターンです。これはクライアントから画像を受け取る場合ですが、要するにユーザがブラウザから画像を選択してアップロードするよく使うやつです(curlでこれをコード化すると、画像の一括アップロードなどにも使えます)。
# coding: utf-8
import os
import io
import time
import string
import random
import datetime
import numpy as np
from PIL import Image
import cv2
from flask import Flask, render_template, request, redirect, url_for, send_from_directory,send_file
from flask_cors import CORS
from google.cloud import storage
from google.cloud.storage import Blob
import inspect
import numpy as np
import cv2
app = Flask(__name__)
CORS(app)
@app.route("/", methods=["GET", "POST"])
def hello():
if request.files['image']:
filename = request.files['image'].filename
content_type = request.files['image'].content_type
# 画像として読み込み
stream = request.files['image'].stream
img_array = np.asarray(bytearray(stream.read()), dtype=np.uint8)
img = cv2.imdecode(img_array, 1)
is_success, buffer = cv2.imencode(".jpg", img)
buf = io.BytesIO(buffer)
#buf = io.BytesIO()
buf.seek(0)
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = './path/to/your/credential_goole.json'
storage_client = storage.Client()
bucket = storage_client.get_bucket('your_backetname.com')
blob = Blob(filename, bucket)
blob.upload_from_string(data=buf.getvalue(), content_type=content_type)
return send_file(
buf,attachment_filename=filename,as_attachment=True
)
if __name__ == "__main__":
app.run(host='127.0.0.1',debug=True)
上記ファイルを実行しFlaskサーバが立てたあと、こちらについては画像をHTMLからアップロードする必要があります。
APIを叩いてcanvas要素に描写するHTMLも載せておきますので、こちらを参考にしてください。buf変数に読み込んだものをOpenCVなどで操作すれば簡単な画像処理ソフトになると思います。
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<title>bootstrapとjquery</title>
</head>
<body>
<main>
<article>
<section>
<input type="button" value="Start" onclick="main();"/>
<canvas style="height: 30vw;width:50vh"></canvas>
</section>
</article>
</main>
<script language="javascript" type="text/javascript">
function main(){
var canvas = document.getElementsByTagName('canvas');
var ctx = canvas[0].getContext('2d');
var img = new Image();
img.src = 'http://0.0.0.0:5000';//FlaskでホスティングしたURL
img.onload = function() {
img.style.display = 'none'; // ようわからん
console.log('WxH: ' + img.width + 'x' + img.height)
ctx.drawImage(img, 0, 0);
var imageData = ctx.getImageData(0, 0, img.width*2, img.height*2)
for(x = 0 ; x < 1000 ; x += 10) {
for(y = 0 ; y < 1000 ; y += 10) {
ctx.putImageData(imageData, x, y);
}
}
}; }
</script>
</body>
</html>
curlコマンドでForm送信は代替できます。
HTMLのform送信をcurlコマンドで代替する方法はこちら
Flaskで画像を処理場合のソースコードはパターンごとに書き分ける必要があり、普段は目の前のタスクを終わらせて終わりがちですが、今回は6つのパターンについてまとめました。AWSのS3を使う場合やローカルで完結させる場合も同様に処理できると思いますので、ぜひ参考にしていただけるとうれしいです。
この記事が役に立ったと思ったらLGTMお願いいたします:thumbsup:
Matplotlibで作成したグラフをクライアントへ返す方法についてさらに詳細をまとめたのはこちら
1
最近、製造業におけるPythonの導入が進んでます。自動化やアプリケーション制作に便利ですし、今後もこの勢いは止まらなそうです。
ところが、私は実務担当として工場でPythonを導入して5年になるのですが、近年はWeb技術を使用することが多くなりました。Pythonを使い始めた当初、Web技術と言えばHTMLとCSS?データ分析メインの俺にはあんまり関係ないよね?と思っていました。でも、実務を行う中でPythonとWeb技術の相性が非常に良いことに気付き、最近はWebとPythonを半分ずつ使っています。
この記事では、とある工場で働くエンジニアがWeb技術の重要性について発見したことを書きたいと思います。おそらく、最近の空気は、製造業でもPythonは役に立つが、Webは分野が違うので関係ないという感じだと思います。でも、私はWeb技術があってこそPythonが100%生かせるのではないかと思っています。ある工場でPythonを導入した結果、Web技術の(意外な?)重要性について発見したことを共有したいと思います。
構成としては
・製造業におけるPythonの使い所を整理し、
・Web技術の重要性について
述べたいと思います。
少し冗長ですが、そもそも製造業のおけるPythonの使い所として主に下記の3つがあると感じています。
・データ整形や業務の自動化
・高度なデータ分析
・業務アプリの制作(AIアプリ制作含む)
まず一つ目です。工場だと、製造に必要なファイルはエクセルで管理されていることが多いと思います。そして、どこかのフォルダに入っているデータをそのエクセルにコピペして行う集計作業も多いと思います。Pythonの使い所として最初に出てくるのがこの作業の自動化です。csvで管理されているデータならPandasで読み込めますし、Excelも操作できるので集計作業を一瞬で終わらせることができます。Pythonは汎用プログラミング言語ですので、PC上で行う「手順の決まった繰り返し作業」であれば、原理的にはすべて自動化できるというのは心強いです。
二つ目が高度なデータ分析です。研究系で使用される方はこの用途が多いのではないかと思います。当然オフラインで行うこともできるのですが、うまくやれば高度な分析も自動化できます。
つまり、一般的には
三つ目が業務アプリ制作です。
自分ごとで恐縮なのですが、私はPythonを使い始めた時、主に自分の業務の自動化で使っていましたが、次第にある欲求が抑えられなくなってきました。「作ったアプリを周りに活用して欲しい」という欲求です。結構あるあるだと思いますので、業務アプリの制作というのも製造業におけるPython活用のよくあるパターンだと思います。あるいは、最近はAIを実装すると言った業務もあるのではないでしょうか。
そして、私がWeb技術の活用が必要だとおもったきっかけは、この3つ目の用途においてです。
PythonでGUIを作ってしまうと、使用する人全員に同じ環境を用意しなければなりません。一桁程度ならなんとかなるのですが、人数が増えるとその手間は大きくなり苦痛に感じるようになりました。
かといって実行ファイルにするとサイズが大きくなったり、コンパイルに失敗したりデバッグできなかったりで使い勝手が悪かったです。そこで、サーバPCを用意して環境構築をその1台だけで完結させ、使用者はそこにアクセスすることでサービスを提供できるようにするためにはどうすればいいだろうかという課題に直面しました。Pythonの活用が進めば進むほどこのニーズが大きくなり、Web技術の必要性が出てくると思います。
また、二つ目の高度なデータ分析におけるWeb技術の活用のメリットも大きいです。
A.手渡ししてもらったデータをオフラインで解析する
B.解析コードをラインに組み込んで全ロットで自動に結果を出す
という違いは大きいと思うのですが、後者のためにWebが非常に役立つからです。
つまり、Web技術を導入すると、分析の自動化のために必要な下記の2点が可能になります。
・整形したデータをAPIを介して配信できる(データの活用の裾野が広がる)
・本社や現場で集めたデータを活用するスマホアプリまで作れる(実行環境を問わずデータを活用するアプリケーションが開発できる)
Pythonの使い所の一つ目で挙げたとおり、データ整形という用途はPython活用の王道だと思います。そして、整形したデータを活用するというのを考えた時、Webブラウザを叩いてデータが返ってきたらめちゃくちゃ便利ではないかと思い至りました。要するにWebAPIで配信するということです。
ロットやデータ数を指定してAPIを叩いたらデータが勝手に得られる環境というのは、分析の自動化にもだいぶ役に立つと思います。Pythonだけだとデータ整理で終わったかも分からないのですが、APIを作ることでPythonで集計したデータを他事業所からアクセスしてもらえるようにしたり、より広く活用することができるようになります。個人的には、バックエンドをFlaskでAPI化して、フロントエンドはクロスプラットフォームフレームワークのAngularかReactという構成が好きです。でも、今ならVue.jsから始めるかもしれません。
発見だったのがこれです。Web技術というとHTMLとCSSの静的なサイトのイメージが強かったのですが、最近はSPA(シングルページアプリケーション)という技術があるそうで、SPAを使うとデスクトップアプリと同等のものを作れます(SPAとセットでよく使う言葉にPWA(Progressive Web アプリ)という物もあります。SPAという技術で作った物の性質を表すときにPWAと表現していると理解しています。なので、文脈的にはSPAよりPWAの方が正確かも)(注釈1)。AngularやReact、Vueといったフレームワークがそれなのですが、これらはTypeScriptやJavaScriptの拡張言語であるJSXなどをかなり駆使しますので、HP制作というよりアプリケーション開発のイメージです。これによりTKinter、PysimpleGUI、PyQt、のようなデスクトップアプリをWeb上でも作ることができます。
加えて、AngularやReact、Vueではクロスプラットフォーム性があります。つまり、Webアプリだけではなく、AndroidやiOSのアプリにも出力が可能ということです(!)(注釈2)。これにより、ブラウザを介してユーザーのアクセス性を確保しつつ、ブラウザでアクセスできない場所(=例えば現場)ではアプリとして使ってもらうことができるようになります。これはWebを導入して見つけた想定外の発見で、PythonだけではスタッフのPCで動作するアプリ開発しかできなかったと思いますが、Webを導入することで多くの人や場面で使ってもらえるための開発手段を手に入れられました。
相変わらずバックエンドはPythonで書いていますが、フロントエンドはWebに移行することで大きなメリットが得られました。
少し冗長な説明になってしまいましたが、上記のようにWeb技術を使うとPythonで作ったデータを活用できる幅が広がったり、Pythonの普及に伴う環境整備の手間が低減できます。
近年注目されるPythonによる高度な分析についても、Webの力を借りることで、オフラインに留まらず全ロットに対して自動で行いそれを工場全体で生かす仕組みも構築できます。
Pythonについては製造業でも普及が進みつつあると思いますが、Webについては分野が違うという認識をされがちです。でも、Webがあるとより活用の幅が広がると思いますので、ぜひ検討してみてください。
この記事が役に立ったと思ったらLGTMお願いいたします:thumbsup:
製造業でのIT活用頑張りましょう!
注釈1:PWA、SPAとはなんぞや
注釈2:クロスプラットフォームとは何
個人サイトの方で解説した記事1(個人・少人数のシステム開発にはAngularがオススメ)
個人サイトの方で解説した記事2(pythonとangularの組み合わせが最強な理由)
Monacaの記事
勉強した本1(掌田津耶乃さんのAngularの本。React版でもいいかも。Vue.jsもいい本あると思います)
勉強した本2(AngularをIonicベースで利用)
1
curlコマンドでHTMLのformでの画像送信を代替する方法です。
curlコマンドを打つときの場所にna18_1920x1080_221804.jpgと言う画像を置いた場合です。
url -X POST -F 'image=@./na18_1920x1080_221804.jpg' http://127.0.0.1:5000/ --insecure
ヘッダー情報とかクエリパラメータを引き渡したい場合はこちら。
curl -X POST -H 'Host:some_destination.com.' -H 'Authorization:something' -F 'image=@./na18_1920x1080_221804.jpg' -F "arg1=myarg1" -F "arg2=myarg2" http://127.0.0.1:5000/ --insecure
ちなみに、画像送信とは関係ないですが、Get通信の諸々のサンプルこちらです。
curl -H 'Host:some_destination.com.' -H 'Authorization:something' -X GET "http://127.0.0.1:5000?arg1=myarg1&arg2=myarg2" --insecure
Windows10のcurlコマンドだと、実際はinvoke-webrequestというコマンドのエイリアスなので動作しません。その場合、本物のcurlの実行ファイルをダウンロードして、パスを通して実行ファイル名を書き換えて、それでコマンドを打てば大丈夫です。
1
MacBookを使っているのですが、タイピングしにくいので外付けのキーボードを取り付けることにしました。Windowsなら何も考えずに購入できたのですが、実際お店に行ってみると
心配になりました。上記について、購入して試した結果をまとめたいと思います。
Mac対応と書いてあるものなら普通に動きそうです(Elecomとか)。栄のビックカメラで買ったのですが、5種類ほど選べました。形状が凝ったものだとWindowsのみの対応だったりしましたが、まぁ基本的なものであれば普通に売っている感じです。純正のキーボード高いですから、サードパーティ製で対応したいものです。
JISキーボードで問題ありません。普通にキーボードの配列通りに打てます。安めのMac対応の外付けのUSキーボードが売っているはずもなく、US配列であることは諦めていたので、一番うちやすかったのでElecomのTK-FBP101BKというものを買いました。
打ちやすかったのはパンタグラフ式という構造のせいらしいです。Macとは正反対の印象です。快適に使えますし、気分転換にもなるので気に入りました。
1
名古屋と大阪を結ぶ近鉄特急ひのとりに乗ってきました。大阪一泊旅行です。
まずはひのとりのレポートから。
https://www.kintetsu.co.jp/senden/hinotori/
前日に切符を買いました。ひのとりは名古屋を出た後最初に止まるのが津ですので、最寄駅から津までは通常の特急で行き、そこから乗り換えることを勧められました。しかし、せっかくなので名古屋まで一度出て改めて乗ることにしました。というわけで朝9寺半前に名古屋駅へ。
10寺発名古屋のひのとりを待ちます。
ホームにひのとりが入ってきました。
かっこいいですね。中もめちゃめちゃきれいです。
トイレもきれい。
ここは手洗い場
席はこんな感じです。
重厚な感じでしっかりしてました。フットレストもいい感じです。
津までは南へ南下して、そこから西へ。
1日目の目的地は、川西にあった母の実家です。子供の頃よく遊びに行ったのですが、18年ぶりに行きました。
畦野から歩くつもりでしたが、畦野えきで妻と喧嘩。かなり最悪な流れでしたが、結局話がついてタクシーで向かいました。昔は遠いと思ってたけどそこまで遠くはなかったです。まだ家があったことにびっくり。
母が15歳の時に買ったそうで、狭い社宅から越したのがうれしかったそうです。その母も結婚して東京に移り子供を育て、それでその子供は独立して、、ということでとても時間の流れを不思議に感じました。この家に遊びに行っていた時、俺はまだ子供だったんだよなぁ。
夜は西梅田のほうにホテルを取りました。
妻が疲れていたので弁当を買いに行って、ついでに美味しんぼで紹介されたというたこ焼きを買って帰りました。
翌日(というか今日)は、ドトールで1時間くらいゆっくりした後に大阪観光ということで、アメリカ村まで歩いて、そこから電気街やコンカフェに行ってカレーを食べて、家族へのクリスマスプレゼント物色で難波駅をブラブラして、15寺半大阪難波発のアーバンライナーで帰ってきました。
というわけで今9時過ぎです。早めに寝ます。
qiitaのプロフィール欄の右側に所属組織を表示されるときがあります。
会社が表示される人がいますが、中には明らかに非公式の組織が表示される時もあります。調べてみると、Qiitaのorganizationは非公式なものも登録できるそうなので、作ってみることにしました。
Qiita Organizationは会社や組織等の団体メンバーの記事をまとめることができる機能です。qiitaを読んでいると、この人どんな人なんだろうって思うこともあると思いますので、自分の所属や志向を伝えることができるので便利ですよね。
作成する時、企業か団体を選択できるので、会社などの公式の組織はもちろん、有志で集まった団体でも2名以上のメンバーがいれば作成できるそうです。公式の説明はこちら。
https://qiita.com/organizations
先日、製造業におけるPythonとWebの活用の記事を書いたところ、結構反響がありました。おそらく、製造業でのIT活用というところで共感を感じていただいたのかと思います。私自身そういう仲間がいたら面白うかなと思って、作成してみることにしました。
考え中です。何かいいあんがあればコメント欲しいですが、
これはスラッグ です。massive-indeustriesとでもしておきましょう。
結構皆さん適当です。
これとか切り出し感あるし
これも味はいいが単純
これは企業ロゴそのまま。
結構趣味を出してもいいらしい。
というわけで、その気になればフリー素材使ってなんとかなりそう。
Organizationは二人以上じゃないと作成できないので誰か仲間を指定します。
これも皆さん適当なので適当に
「製造業でIT技術の活用を頑張る会です。」など後で考えます。
以上の内容を下記のフォームで入力すればできるっぽい。
https://qiita.com/organizations/new
メイン画像とロゴを作成したら(してもらうんですが)、作成してみようかな!
1
OandaのAPIを使いたいのですが、私が作った3年前と現在ではAPIのバージョンが異なります。昔のバージョンのときに作成し、現在は動作しなくなってしまいました。いろいろ頑張ったのですがラチがあかないので、古い口座を解約し、新しいものを作り直すという強硬手段に出ることにしました。
ここでは、その時の注意事項などについてまとめたいと思います。
まず、問題なのはこのエラーです。適当に最近のレートを取得しようとするとこのようなエラーがでます。
Error: {"errorMessage":"Insufficient authorization to perform request."}
デモ口座だとうまくいくのに本番環境ではうまくいきません。日本法人に問い合わせると、APIは管轄外なので米国の本社に聞いて欲しいと言われます。しかし、そこに聞いても結局解決しませんでした。
いろいろ情報を探して
https://developer.oanda.com/rest-live-v20/troubleshooting-errors/
などを見ましたが解決せず。また、ログイン後の画面がこのようになっており、accout IDの後にV20と表示されていないのでV20に対応していないのかと思ったのですがそういうわけでもないようです。
デモ口座だとこのようにV20と表示されてるんですけどね。
そこで、古い口座を解約し、新しいものを作り直すという強硬手段に出ることにしました。必要な時間は2日程度でした。
解約する方法と新しいものを作る方法について説明します。
従来のものを解約するのに必要な日数は半日です。10時までにカスタマーセンタに電話で連絡すれば、その日に解約できると思います。出金手続きも電話口で代行してくれます。私は10時半くらいに電話、11時までなら当日の出金に対応できるということでその場で指定口座への出金代行を依頼。15時には解約されました。
口座に預金がある状態では解約できない仕組みになっていますし、カスタマーセンタが問題があれば口頭で言ってくれるので安心です。
解約されたら直後に申請可能です。これは通常通りの申請ということでリンク貼っておきます。私の場合、月曜日に新規申し込みをして、木曜日にIDを書いたものが簡易書留できました。あとは画面の指示にしたがって初期設定を澄ませばすぐに使えるようになると思います。
1
ここでは、Xserverのメールを他のメールソフトで見られるようにする方法として、iPhoneのGmailで設定する方法を紹介します。
Gmailを起動して、右上の自分のアイコンをクリックします。このような画面になります。
そしたら、「別のアカウントを追加」を押下します。
その他(IMAP)をタップし、そこで登録したいメールアドレスを入力します。
さらにボタンを押すと、下記の画面になり、ここでサーバとパスワードを入力します。これは受信サーバと送信サーバの両方が必要になり、最初に表示されるのは受信サーバです。
パスワードとサーバ名を入力します。
パスワードはXserverの管理画面からメールアドレスを発行する際に、メールアドレス に対して発行するものなのでもしこれがわからない場合は作り直すか作った人に聞くしかありません。
後サーバー名を入れて終わりです。ポート番号は基本的には既に入力されているはずですが、変える場合は下記を参照してください。
POP/IMAPサーバー名 (ホスト名) | 設定完了メールに記載されている「メールサーバー」を入力してください。※サーバーパネル内「サーバー情報」に記載の“ホスト名”と同一です。例)sv***.xserver.jp | |
---|---|---|
SMTPサーバー名 (ホスト名) | 設定完了メールに記載されている「メールサーバー」を入力してください。※サーバーパネル内「サーバー情報」に記載の“ホスト名”と同一です。例)sv***.xserver.jp | |
ユーザー名 (アカウント名) | メールアカウントの追加にて設定したメールアドレス(ドメイン名を含む)を入力してください。 例)user@example.com 例)info@example.com | |
パスワード | メールアカウントの追加にて指定したパスワードを入力してください。 | |
ポート番号 POPの場合 | 995 (SSLを利用しない場合は 110) | |
ポート番号 IMAPの場合 | 993 (SSLを利用しない場合は 143) | |
ポート番号 SMTPの場合 | 465 (SSLを利用しない場合は 587) |
そうすると、頑張って設定をしてくれます。
送信サーバの設定画面に移行するので、同じ情報を入力して完了です。
Xserverのメールを他のメールソフトで見られるようにする方法として、iPhoneのGmailで設定する方法を紹介しました。Xserverのリンクはこちら。
1
スマホからSBI FXトレードで出金指示をした際、画面から預託金残高はすぐに減りますが、メールも来ないし履歴も残りません。極めてひどいUIだと思います。ここではSBI FXトレードの出金の流れを記載します。
普通、出金指示を行った時点で出金依頼を受けつけたメールが来て、その後出金が完了した旨が通知される流れを想定すると思います。OANDAではこのようにされますし、当然こう言った流れが適切だと思います。しかし、SBI FXトレードで出金をすると、画面から預託金残高はすぐに減りますが、メールも来ないし履歴も残りません。ちゃんとシステムが受け付けてるのか心配になります。
私は出金依頼を11月11日の夜にしました。その際、実際に出金確定メールが来たのは11月13日9時でした。出金した額が自分的には大きな額だったので連絡が来るまで冷や冷やものでした。本当にひどいものです。
公式サイトの「出金依頼をしてからどのくらいで振り込まれますか?」という質問にはこのような回答となっています。
「取引終了時間までにご依頼された場合、通常時は翌営業日にお振込みします。
ただし、何等かの事象が発生した場合に備え、出金依頼された日から4営業日以内(※土日祝は営業日ではございません)のお振込みを原則とさせていただきます。」
時間差はいいとして、出金指示の受付メールが来ないことは改善されることを望みます。みなさん不安になると思うので記事にさせていただきました。
1
GoogleのドキュメントやGCPで使われているAngularは、Googleが中心開発している JavaScript フレームワークです。AngularJSと混同されていている方もいらっしゃいますが、AngularJSのメリットを生かしたまま互換性のない形で生まれ変わったのがAngularです。Angularは、SPA (Single Page Application)と呼ばれる技術を用いて、従来のWebでは実現できなかった機能を提供する技術です。イメージ的には、従来のWebページよりアプリケーションよりのものを作りやすくなると感じています
最近、従来のWeb技術では考えられなかったようなサイトが増えてきています。たとえば、オフラインでも動作するWebページやGoogleのドキュメントのように同じURLなのに検索ワードによって違う内容が表示されるページなどです。SPA (Single Page Application)ではindex.htmlだけを読み込み、そのあとはDOMの操作をフロントエンドで行って擬似的な遷移を行っています。これによりオフラインでも画面遷移ができたり、検索クエリによって動的にページを書き換えたりといったことができます。
SPAのフレームワークはいくつかあります。Facebookの開発しているReact.jsなどが有名ですが、個人的にはReact.jsよりも断然Angularがおすすめです。Reactが最小限の本体とサードパーティのライブラリで構成されているのに対して、Angularは開発に必要な機能をすべて盛り込んだフルスタックです。開発に必要なデータバインディング、フォームバリデーション、非同期通信、ルーティング、テスタビリティ、セキュリティへの配慮など、一通りの機能がすべてあらかじめ用意されているので、Angular を選択することでコーディングに集中できます。ライブラリが複数あるとどれを使えばいいのか迷いますしライブラリ間の依存関係などを気にする必要が出てくると思いますが、そういった懸念から解放されコーディングに集中できることがAngularのメリットだと考えています。個人的にはAngularは「控えめにいって最高」のフレームワークです。
わたしは個人でシステム開発をしているのですが、iOS用にSwiftで、Android用にKotlinで、そしてWeb用にJavaScriptで開発をしていたらいくら時間があってもたりません。そこで一つのソースコードでさまざまなプラットフォームで動作すればありがたいわけです。そこでクロスプラットフォームの仕組みとして「Ionic 」「Cordova」「NativeScript」「React Native」Electron」「Capacitor」「Xamarin」「Unity」などが候補にあがるわけですが、Angularは「Capacitor」というMacデスクトップアプリ、Windowsデスクトップアプリ、Web、iOS, Androidに出力できるこれまた最高のフレームワークと組み合わせることができます。したがって、Angularは効率的にプロジェクを作成し、それを複数のプラットフォームに同時に出力できるという夢のような生産性を実現するフレームワークです。
Angularの前身であるAngularJSがあまりにも有名なため、AngularJSの終了から5年弱経っているのにまださまざまなところで混同されています。しかし、AngularはAngularJSで顕在化した問題を解決するべく、内部構造から細部に至るまで再設計され実装されています。
一般的にフルスタックフレームワークだと、開発規模が大きくなるにれバンドルされるファイルサイズが大きくなりパフォーマンス面で悪影響を与えることもあります。AngularJSでも顕在化したその問題を解決するために、AngularではJavaScript VM (Virtual Machine) フレンドリーな実行コードを生成することで実行速度を改善したり、AoT コンパイル(Ahead-of-Time Compilation)と呼ばれるビルド時に表示を高速化するための仕組み、さらに段階的にソースコードをよみこむLazyLoadingと呼ばれる仕組みを利用して高速化する方法も提供されるなどです。最初にAngularで開発するときに訳が分からなくなってしまいがちですが、AngularJSとは互換性がないということを覚えておくといいと思います。半年毎にバージョンが変わるのですが(例えばAngular8が現在のバージョンなら、半年後はAngular9がでる)これらには一部の機能を除いて互換性があります。
SPAの技術の一つであるAngularについてまとめました。近年普及が急速に進んでいるPWAアプリ作成のフレームワークとして代表的な物で、一つのコードで複数のプラットフォームに出力できるクロスプラットフォーム性について記載しました。
Angularで個人で作ったアプリがあります。OCRという写真から文字を抜き出す技術を使って、ブログなどを早く書くためのツールです。これも一つのコードでAndroid ,Web,iOSに出力できるので大変便利でした。
iOS => https://apps.apple.com/app/id1497498494
Android => https://play.google.com/store/apps/details?id=com.rainbowsv2.ocr
Ionicで作成したプロジェクトは下記のような構造になっています。
かなり複雑で、最初に見たときは戸惑うかもしれません。実際に触るのはsrc/appフォルダがほとんどになりますが、他のフォルダを含めて解説したいと思います。
名前 | 説明 |
e2e/ | システム全体の動作検証を行うE2Eテストの際に利用します。最初はほとんど触りません |
node_modules/ | node.js上で動くため、package管理ソフトにnpmを使うことになりますが、npm経由でインストールしたライブラリが保存されます |
src/ | 実際に開発を行う場所です。9割このフォルダを触ります。 |
angular.json | Angularの設定ファイルです。フォルダの出力先などビルドを中心にした設定はここで行います。 |
package.json | 実際にプロジェクトで使用するライブラリを指定します |
package-lock.json | package.jsonで指定したものが入っているか確認します。エラーの時にたまにいじります |
したがって、基本的にはsrcだけをいじると考えておいて差し支えないと思います。
それでは、実際に開発を行うsrcフォルダを見てみます。
srcのなかでも触るのはsrc/appがほとんどになりますが、こちらについても簡単に解説をします。
ファイル/フォルダ | 説明 |
src/app | 実際に触るのはほとんどこのフォルダのなかです。このフォルダが開発対象と考えていただいて問題ないと思います。 |
src/assets | 画像や音声、動画などのリソースを配置します。例えばsrc/resourcesというフォルダを自分で作成すると読み込まれないので注意が必要です。 |
src/environments | なかには簡単なjsonファイルが本番用と開発用に入っています、環境変数をそれぞれ定義します。Google Analyticsをいれるときなどにいじりました。 |
src/theme | cssの拡張であるscssでデザインを規定しますが、そのファイルが入っています。IonicのUIが優れているため、個人的にはあまり触りません。 |
src/global.scss | プロジェクト全体に適用するscssを書く際はこちらを使います。たた、実際はpageごとに用意されるscssをいじることが多いです。 |
src/index.html | Anugular(Ionic)でも最初によみこまれるのはIndex.htmlです。 |
src/main.ts | アプリを起動するためのファイルです。index.htmlのあとに読み込まれます。 |
src/polyfills.ts | IE10/ 11対応を行うもののようですが、IonicってIEで見れないんですよね。。 |
src/test.ts | 単体テストの設定ファイルです |
基本的に、src/appのなかをいじる、とだけ考えておけばいいと思います。
IonicをAngularで使って、写真から文字情報を抽出して爆速でレポートや記事を作成するアプリを作成しています。無料なのでよかったらどうぞ。
iOS => https://apps.apple.com/app/id1497498494
Android => https://play.google.com/store/apps/details?id=com.rainbowsv2.ocr
1
これはただのプラグインではありません。Louis Armstrong によって歌われた最も有名な二つの単語、Hello, Dolly に要約された同一世代のすべての人々の希望と情熱を象徴するものです。
これはただの記事ではありません。Robert E. Kahnによって歌われた開かれたインターネットへのすべての人々の希望と情熱を象徴するものです。
この記事ではBraveブラウザについて説明します。Braveブラウザを使えば広告なしでYoutubeを閲覧できたり、サイトを見るとお金がもらえたりします。また、Adsenseに代わりWebサイトやTwitterを収益化できるブラウザでもあります。しかしそれだけではなく
1. (Googleの無料サービスに定義された)インターネットの仕組みを変える
2. コンテンツ製作者に適切に報いる
ことを目的とする従来とは全く異なるパラダイムから生まれたブラウザです(製作者はJavaScriptの生みの親で元MozillaCEOのアイク氏です)。
そこで、クリエータとして収益化する方法とWebサイトを閲覧してお金をもらう方法をメインで説明しつつ、Braveブラウザの背景や理念などについても紹介します。インターネットの仕組みを変えようとする非常に面白い取組みで、インターネットを使う人なら誰でも関わりのある話だと思いますのでぜひご覧ください。
・Braveブラウザとはなんぞや
・クリエータの収益化の設定方法
・ユーザとして収益化の設定方法
技術的には2019年に公開されたChromiumベースのブラウザです。ただし単なるブラウザではありません。他との決定的な違いは、JavaScriptの生みの親で元MozillaCEOのアイク氏がインターネットのあり方と仕組みを根本的に変えることを目指して作ったことです。しかしインターネットのあり方と仕組みを変えるとはなんぞや。。
ここではわかりやすくアイク氏の着眼点から整理することでまとめてみたいと思います。
(Braveブラウザはまだメジャーではないため、前段が長くなることをお許しください。)
既存のインターネットの仕組みについて、無料でサービス展開して広告で収益化する仕組みって限界あるよね?ということが発端になっていると理解しています。
ユーザー視点で言えば
という限界であり、コンテンツ製作者としては
という限界であり、ビジネスモデルや倫理的な観点で言えば、アップルのティムクックの「サービスが無料であれば、それを受け取る人は顧客ではなく、製品である」ということをもじれば
function 広告利益最大化(
ティムクック="サービスが無料であれば、それを受け取る人は顧客ではなく、製品である"
){
=> (ユーザ-="単なる変数";)
}
ということです。これって正しいようだけど、よくみると文法エラーですよね?
元々インターネットというのは分散型で自由であったもののはずなのに、今は「データの吸い上げ×広告出稿」でプラットフォーマーが牛耳ってる超中央集権状態だよね?しかもその中で一人ひとりの扱いは変数の一つにすぎず、モチっと別の仕組みはないのかね?ということがアイク氏の着眼点でした。
そこでアイク氏はMozillaを突然退社してBraveブラウザの作成を始めます。さすがJavaScriptを生み出して、Mozillaを率いただけある人は違うなと思うのですが、曰く、突然モジラのCEOを辞任したアイクは、
生まれ変わったようにプログラミングを再開し、Brave というこれまでにないブラウザを開発した。
Brave は、Cookie の弊害を取り除くとともに、
すべてをトップダウンで決められるインターネットの仕組みを変えるものだった。
ということです(「グーグルが消える日 Life after Google(ジョージ・ギルダー著)」)。
本を読んだり公式サイトみるといろいろ書いてあるのですが、要するに下記のメリットがあります。
ユーザーのメリット
出稿者のメリット
コンテンツ制作者のメリット
という点です。結構こうやって考えてみると大きいですよね?
以上が
・Braveブラウザとはなんぞや
・クリエータの収益化の方法
・ユーザとして収益化する方法
という3構成の最初の部分でした。さて、それでは実際にいよいよ収益化する方法について記載していきたいと思います。Adsenseと併用可能でしたのでぜひ登録してみるといいと思います(Adsenseのように審査厳しくありませんでした)。
なお、WEB系じゃない方はここはスルーしてください。この下にユーザーとして使う方法があります。
こちらの公式サイトから設定をしていきます。
https://brave.com/ja/
Braveブラウザでクリエイター登録するために、大きく分けて2つのことを行います。
トップページ右上の「クリエイターの方」というボタンから下記のページに飛びます。
https://creators.brave.com/?locale=ja
登録ボタンを押して、メールアドレスを入力します。
メールが届くので、そこに記載されたリンクを飛んで氏名を入力して完了です。非常に簡単ですね。
ログインするとこんな画面になります。
ここでサイトの登録をしていきます。右上の「チャンネルを登録」ボタンを押して、下記のカードから収益化させたいチャンネルを選択します。Twitterなども収益化できるようですが、私の場合はウェブサイトを選んでドメインを入力しました。
すると勝手にWordPressだと判定してくれました。(Angular React,Pythonのサイトだとどうなるかわかりませんでした。でも実際はad.txtに相当するテキストファイル作っているだけなので行けると思います)
画面の指示にしたがって、プラグインのインストールして、サイトを認証します。
からzipファイルをダウンロードして、WordPressの管理画面から新しいプラグインとしてアップロードし、有効化します。
管理画面のプラグインの中にBrave Payments Verificationという行が追加されますのでそれを選択して、先の画面に表示された検証コードを追加します。あとは検証コードが表示されたページで検証ボタンを押せばOKです。
するとこういうメールが届きますのでこれでクリエイター登録は完了です。
最後にプラグインをdeactivateして終わりです。
(支払い先でPayPalと紐づける必要はありますが、これはPayPal口座があればすぐできますし、特にクリエイター登録という意味ではしなくても問題ないかと思います)
以上です。これでBraveブラウザでクリエイター登録ができました。あとはユーザーがBraveブラウザを介してアクセスしたら、コンテンツに対する支払いが振り込まれることとなります。(でもまだ未検証です。私は https://top.np-sys.com/ で登録したので、Braveブラウザで誰かアクセスしてみてくれたら振り込み額など追記します。また、こちらの投稿にコメントをいただけたら、記事の下にサイト一覧のような形でリンクを貼ろうと思います。ぜひご連絡ください)
上記はクリエーターとして登録する方法を説明しましたが、ユーザーとしてBraveブラウザを利用することもできます。Braveブラウザを使うと、ChromeやSafariと異なる3点のメリットがあります。
このうち、サイト(広告)の閲覧によって収益が得られるというのは理解に苦しむところだと思います。私もそんな美味しい話があるものかと思いましたが、これはBraveブラウザの理念を踏まえると理解できます。つまり
「広告に基づくウェブのエコシステムをリセットし、広告主、コンテンツ・パブリッシャー、顧客の誰もが得をするウィン・ウィン型のソリューションを提供する」
ことをBraveブラウザが目的としているためです。まぁ投げ銭の元資金って感じなのだろうとは思いますし、こういう仕組みがないとなかなか広まらないですから、いい仕組みかと思います。
それではいよいよネット閲覧でお小遣いがもらえる謎のBraveブラウザのインストール方法です。と言っても公式からダウンロードしてインストールするだけです。
公式→ https://brave.com/ja/
インストール後、Rewardを有効にすれば収益化は完了します。個人データの集約などもしていないとのこと。
大体、広告一回見ると1円くらいです。最大でも1時間に5回しか広告を表示させられないので額としては大したことはありませんが、得られた収益をサイト製作者に寄付できることが大きいです。小さな投げ銭が集まることである程度大きな金額になれば、正当な方法でコンテンツ製作者に報いることができると思います。作った人がコンテンツを見てもらい、金銭という形で認めてもらえる、これって健全な社会の形ですよね?
というわけで、この記事では次世代のBraveブラウザについて紹介しました。
1. (Googleの無料サービスに定義された)インターネットの仕組みを変える
2. コンテンツ製作者に適切に報いる
ことを目的とする従来とは全く異なるパラダイムから生まれたブラウザで、Google Adsenseに変わる方法(実際は並列して使えます)として利用できます。私は開発者としてもユーザーとしてもGoogleが非常に好きなのですが、Braveブラウザの理念にも共感します。Braveブラウザはとてもいい仕組みだと思いますし、何事にも多様性は大事なはずなので、Braveブラウザも使っていきたいとと思います。ぜひ皆さんもご検討してみてください。軽くて普通にいいブラウザでした。
最後になりますが、こちらの記事は、アメリカでベストセラーとなった「グーグルが消える日 Life after Google(ジョージ・ギルダー著)」を参考にしております。哲学的なことが多かったけど面白かったです。
アフィリエイトリンクはこちら。ぜひクリックして購入してね!
=> https://amazon.com
、、、、!?。
ぜひみんなで新しいインターネットを作っていきましょう!
1
pandasで条件抽出する方法には、queryメソッドを使う場合と使わない場合がある。
A列に1-100、B列に101-200、 C列に201から300のデータが並んでいる100行のデータを考える。
df = pd.DataFrame({
"A":[i for i in range(100)],
"B":[i+100 for i in range(100)],
"C":[i+200 for i in range(100)],])
#A列が20未満を抜き出す
df = df[(df["A"]<20)]
#A列が20より大きく、かつ、50未満を抜き出す
df = df[(df["A"]>20)&(df["A"]<50)]
#A列が20より大きく、または、50未満を抜き出す
df = df[(df["Α"]>20)|(dF["B"]<50))
複数条件の場合、かっこで個々の条件を囲む必要がある。
#Aが20未満を抜き出す
df = df.query('A< 20')
df = df.query('(A > 20) and (A < 50)')
df = df.query('(A > 20) | (A < 50)')
個人的にはqueryを使わない方が好みです。
1
製造業に勤めるエンジニアから見た製造業でAI/IoTを活用するために必要だと思うことです。
「2025年の崖」と言われているように、製造業にとってデジタルトランスフォーメーションが喫緊の課題となっております。新興国が品質とコストで猛追するなか、工場にいて日本の厳しさを感じるんですよね。
もはや「日本の品質って本当にいいの?」って思ってしまいます(まぁうちの工場だけかもしれないけど!)。
とはいえ人口減少する日本にとって、高付加価値品の製造が必要なのは明白であり、特にAI/IoTというのはその大きな試金石となっていると思います。いちメーカでAI/IoT担当(かっこ笑いw)をしている身から現場の感覚をお伝えできればと思います。
言いたいことは下記の3点です。
・本部機構にだけAI・IoT推進課を作っても無駄
・買い物だけでは不十分、プログラミングレベルの全体の底上げが必要
・既存のIT担当者は障害になる場合も
大企業で多いのは、工場とは離れた本部機構にAI/IoTの専門部署を作ることですよね。これ、本部だけに作るとうまくいかないパターンだと思います。というのは、AIを活用していくにあたって重要なのは、質のいいデータと現場にカスタマイズされたソフトだと思います。その点、本部にいる人が工場の既存のデータもよくわからないまま新しいデータを取るのって至難の技だと思います。加えて、新しくデータを取り始めたとしても日々起こるトラブルにすぐ対処できず工場任せにするようだと
本部「いいデータが上がってこないから解析できない」
工場「データとるのどんだけ大変だとおもってんねん!」
となる可能性が高いです。結局、本部だけに推進グループを設置するのは不十分で、工場にメインの担当チームを置かないとダメなんですよね。本部にグループ設置すること自身はいいことだと思いますが、本部だけでうまくいくなんてありえないのではないかと。
あとありがちなのが、買い物で済ませようってのも多くあると思います。やれTableauだ、やれDataRobotだ、そのほかにもDataSpiderやSensorCorpusなど高い買い物して「うちはAI/IoTやってる」と満足しているパターン。これって使いこなせないという意味で本当にもったいないと思います。日々の製造で活用するにはカスタマイズが必要で、どこかで自分でコード書く必要があります。この必要性を理解せずにツールを買っても片手落ちってものだと思います。
3つのなかでこれを一番いいたい。バブルの時代に建てられた工場なんかだともう30年近く経っています。うちの工場もそれくらいなのですが、こういった工場にありがちなのがシステムのレガシー化です。どんな感じかというと、例えばうちの工場ではOracleを使っているのですが、SQLでデータベースに接続すると怒られます。
既存のIT担当「接続して不安定になったらどうするんだ」
「・・・・」
Oracleにコマンドで接続してSQLでselect文発行して怒られるっていったいなんなんですか(30年前のGUIソフトでかちかちクリックしてデータを取得するのです)。。こんな状態でAI開発なんてむりですね。一悶着の末select文の発行だけさせてもらっても、なにかあると全部新しいコードがスケープゴートにされますので日々ひやひやものです。
Oracleに接続するbatファイル書いていて申し訳なさでいっぱいになるんですけど、かなしい。。悪いことしてるんだっけ!?加えてタチが悪いのは、既存の担当者の知識が一世代前のものだということです。問題起きて説明しても
「Pythonおれわからないから!!」やる気完全になくします。
以上を踏まえて、製造業でAI/IoTを活用するためにわたしが思う必要な対策を下記に記載します。
→本部にはとても助かっています。でも、工場側にもチームが必要だと思います。
1. データの質を担保するインフラ担当、
2. データベース管理やAPI管理を行うバックエンド担当、
3. そして生技の業務に合わせてカスタマイズするフロントエンド担当
が必要です。共通化できるアルゴリズム開発などは本部に任せてもいいかもしれないですけど、でも、工場のなかにメインのチームが必要だと思います。
→これきついですね。はっきりいって辟易しています。トラブル避けるために、AI/IoT用にはデータ回線、データベース、サーバは完全に分けられたら理想ですね。データベースはMySQLを立てて、サーバはGCPやAWSも使ってパソコンでもなんとかなるし、データ回線もセカンドイーサで分けちゃう。それでもデータ通信量が多くて他のソフト止まったと言われたら心の中で笑います、そして泣きます。
全員のプログラミングに対する理解が必要です。自分は関係ないと思っているひとたちのなかで根付かせるのは大変ですが、スタッフはある程度理解が必要なのではないでしょうか。「手順の決まっていることを自動化するツール」という名目で勉強してもらうのもいいと思います。
AI/IoT使いこなしたら素晴らしいと思うけど、日本の製造業課題多いなぁと。なにかにつけて古いし、固着してますよね。。工場いちから作り直したら簡単だけどね!って。あぁ、もう新興国の勝ちですね〜。・・・っいやいや!!
1
三重県でNP-Systemsという個人事務所をやっています。
WiMAXを3年使っていたのですが、住んでいる場所では回線が不安定なのでエキサイトモバイルWifiを契約してみました。Docomo回線を使用しているということで安定していそうだったので。ただ、結果的にWiMAX継続でエキサイトモバイルWifiは初期契約解除に至りました。契約の流れ、回線速度、初期契約解除の流れなどをレポートしたいと思います。
エキサイトモバイルWifiは、2020年10月からサービスが開始された新しいWiFiサービスで、Docomo回線を利用しているというのが一番の特徴だと思います。
ということがHPには記載されています。WiMAXが住んでいる三重県だだと結構不安定だったので、Docomo回線なら安定しているだろうということで契約してみました。値段も安くなりますしね。
ただ、結論を言うと初期契約解除に至りました。
と言うことで解約に至りました。
回線速度は遅い代わりに、ブースト機能(https://www.kashi-mo.com/media/50035/)があるようで接続の最初に30Mbps程度が出ます、なのでWebページの閲覧は非常に早く感じます。値段が安いなりの工夫ですね。しかし読み込みたいものがブーストで読み込めない場合は多少待つことになります。また、動画についてはある程度バッファする必要があるのですが、これもブーストで対応できないのでものすごくスムーズと言うわけではないです。
ただ、上りは非常に安定していて、30Mbps程度は出ます。上りが速いのはいいですね。WiMaxだとよくて1,2Mbps程度なので。Docomoなので屋内や地下などでも使えるのでは?
契約から商品が届くまでの流れです。
と言う流れです。発送連絡が初期契約解除の算出日になりますので、お試しで試したいという人には重要です。
開封してSIMカード入れるだけですが、挿入の仕方は少し迷いました。なんとかなって30分後には使えるようになりました。
こちらのサイトがわかりやいです。SIMカード傷つけないように気をつけてください。
https://support.qtmobile.jp/manual/dv/310011800189.html
HUAWEI Mobile WiFi E5785です。軽いし使いやすいしよかったです。
Docomo回線ということで一番期待していましたが、これはよくありませんでした。速度制限時に「最大700kbpsでデータ通信が使い放題」と書いてありますが、実際はいつもこれくらいのスピードしか出ませんでした(いつも0.8Mbps程度)。平日朝、夜、場所を変えてもおなじでした。回線は安定していたのはWiMAXよりよかったです。せめて安定して5Mbps出れば継続でしたが、さすがに遅かったのですぐ初期契約解除することにしました。
初期契約解除は端末が届いて8日以内であれば違約金なしで解約できる制度です。法律で定められており、ちゃんと対応してくれます。申し込みをしてから数日後に「発送したよ」というメール連絡がくるのですが、その8日以内であれば返却が可能です。その場合、違約金などはかかりません。
ただ日数分割した月額費用はかかるということで私は461円かかりました。
初期契約解除は下記の項目を書いた紙をFAXする必要があります
「初期契約解除を請求します。」の一文
これを記載した紙をFAXすればいいです。なお初期契約解除請求対象の電話番号というのはWiFiの端末の電話番号ですので、これはSIMカード同封の紙に書いてあると思います。私は020から始まる番号でした。自分の電話番号を書かないように。紙の記入は手書きで大丈夫です。
私の流れは
という流れでした。
FAXすると翌日にこんなメールが届きます。
=========================
1.端末及びSIM カードの返却について
=========================
<返却先>
〒106-0047
東京都港区南麻布3丁目20‐1 Daiwa麻布テラス4F エキサイト株式会社
エキサイトモバイル WiFi 返却受付窓口
※送料はお客様負担になります。
(着払いで返却された場合、後日送料を請求いたします。)
※初期契約解除を通知された日から1ヶ⽉以内に、端末及びSIMカードの返却が確認ができない場合、WiFi ルーター損害⾦(初期契約解除)10,000 円/台を請求いたします。
※当社に返却された端末に故障⼜は破損が認められた場合、故障⼜は破損にかかる修理代⾦相当額を請求いたします。
=========================
2.ご請求について
=========================
<請求金額>
461円(税抜き)
初期契約解除手続きの場合、「解約事務手数料」の請求はございません。
ただし、初期契約解除までの期間に応じた本サービスの⽉額料⾦、契約締結費⽤及び本SIMカードの提供に要する費⽤等について、電気通信事業法が定める範囲内にて請求いたします。
弊社からの請求に関するお支払い方法は、クレジットカード払いのみとなります。
※クレジットカードの場合は、各カード会社の請求書明細をご確認ください。
※クレジットカードのお引き落としタイミングについては、お客様の各カード会社とのご契約内容によって異なります。
※ご請求金額内訳については、弊社ホームページ内マイページをご確認ください。
=========================
3.その他の注意点
=========================
初期契約解除のご請求書面を弊社が確認できた日をもって、契約解除いたします。
契約解除の手続き後は、契約解除の取り消しには応じられません。
(再度、新規契約のお手続きが必要となります)
以上でございます。
本件に関しまして、ご不明な点がございましたら、本メールに直接ご返信をお願いいたします。
あとは住所に発送すればOK。法律に定められてますし、まぁ可もなく不可もなく対応してくれます。ただメールの二次利用はやめてくださいというようなことが書いてあるのが伏線はってる感じ。
契約前にいざとなれば初期契約解除すればいいや(でもちゃんとできるかな)と思っていたのですが、無事にできてよかった反面もう少し回線速度が出れば初期契約解除しなかったのですがね。。せめて5 Mbpsはでてほしかったですが、1Mbpsを切ると厳しいです。屋内で繋がるのはいいと思います。
なので、結局私はWiMAX継続でした。まぁ回線の安定性と値段が重要ならエキサイトモバイルWiFi、速度重視ならWiMAXというのが私の結論です。
さすがにシステム開発をやっているのでねぇ。。
Angular2以降でfirestoreのコレクションからデータ一覧を取得する方法。
コレクションに対して、valueChanges()をsubscribeする。valueChanges()ってなんだ。。
import { Component, ViewChild } from '@angular/core';
import { AuthService } from '../auth/auth.service';
import { AngularFirestore } from '@angular/fire/firestore';
@Component({
selector: 'app-tab2',
templateUrl: 'tab2.page.html',
styleUrls: ['tab2.page.scss']
})
export class Tab2Page {
authUid:string;
constructor(
public auth: AuthService,
private firestore:AngularFirestore,
) {
this.initialize();
}
initialize(){
this.auth.getAuthUid().subscribe(uid =>{
console.log(uid,'e');
this.authUid = uid;
})
}
test(){
this.firestore.collection('users')
.doc('data').collection(this.authUid)
.valueChanges().subscribe(value =>{
console.log(value);
},
error =>{
console.log('error');
})
};
}
オブジェクトの配列で帰ってくる。
こちらの方がシンプル
this.firestore.collection('users')
.doc('data')
.collection(this.authUid)
.doc(String(new Date().getTime()))
//.doc('test')
.set({
'title':this.originalImgName,
'content':data,
'filename':this.originalImgName,
'lastUpade':String(new Date().getTime()),
});
Angularでは、相方向バインディングを行うための二つの方法があります。一つはテンプレート駆動型、もう一つはリアクティブフォールによるものです。
こちらの公式
https://angular.jp/guide/forms-overview
によると、
ということです。
使いたいページのmodule、tsファイル、HTMLの3つに変更を加えます。
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { Tab1p5PageRoutingModule } from './tab1p5-routing.module';
import { Tab1p5Page } from './tab1p5.page';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
Tab1p5PageRoutingModule,
ReactiveFormsModule
],
declarations: [Tab1p5Page]
})
export class Tab1p5PageModule {}
import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
@Component({
selector: 'app-tab1p5',
templateUrl: './tab1p5.page.html',
styleUrls: ['./tab1p5.page.scss'],
})
export class Tab1p5Page implements OnInit {
favoriteColorControl:formControl;
constructor() { }
ngOnInit() {
this.favoriteColorControl = new FormControl('');
}
}
<ion-header>
<ion-toolbar>
<ion-title>tab1p5</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
Favorite Color: <input type="text" [formControl]="favoriteColorControl">
{{favoriteColorControl.value}}
</ion-content>
Ionic(Angular)でマウスホイールで拡大や移動などが可能なグラフを作成します
標準のchart.jsに加えて、charjs-plugin-zoomを導入します。
通常のchart.jsの導入方法はこちら。
これをズーム可能にするためにcharjs-plugin-zoomを導入します。
npm i chartjs-plugin-zoom -s
そしたら、グラフを作成しているpageのtsファイルにて(今回はsrc/app/tab2/tab2.page.tsでした)
import 'chartjs-plugin-zoom';
を上部に追加して、あとはOptionsのなかに
plugins: {
zoom: {
pan: {
enabled: true,
mode: 'xy'
},
zoom: {
enabled: true,
mode: 'xy'
}
}
},
のように指定するだけです。
冗長ですが、コードを貼り付けておきます。貼り付ける場所などの確認にご使用ください。
import { Component, ViewChild } from '@angular/core';
import { Chart } from 'chart.js';
import 'chartjs-plugin-zoom';
@Component({
selector: 'app-tab2',
templateUrl: 'tab2.page.html',
styleUrls: ['tab2.page.scss']
})
export class Tab2Page {
@ViewChild('myChart') myChart;
@ViewChild('myChart2') myChart2;
@ViewChild('myChart3') myChart3;
bars: any;
colorArray: any;
myNum:number;
data:any= {
type: 'line',
data: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'Aug'],
datasets: [{
label: 'My First dataset',
backgroundColor: 'rgb(150, 194, 129)', // array should have same number of elements as number of dataset
borderColor: 'rgb(150, 194, 129)',// array should have same number of elements as number of dataset
data: [
12,
14,
12,
14,
12,
41,
12,
4,
],
fill: false,
}, {
label: 'My Second dataset',
fill: false,
backgroundColor: 'rgb(50, 194, 129)', // array should have same number of elements as number of dataset
borderColor: 'rgb(50, 194, 129)',// array should have same number of elements as number of dataset
data: [
2,
4,
2,
4,
2,
4,
20,
142,
],
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
min: 0,
max: 200
}
}]
},
responsive:true,
maintainAspectRatio: false,
plugins: {
zoom: {
pan: {
enabled: true,
mode: 'xy'
},
zoom: {
enabled: true,
mode: 'xy'
}
}
},
}
}
title = 'app';
columnDefs = [
{headerName: 'Make', field: 'make' },
{headerName: 'Model', field: 'model' },
{headerName: 'Price', field: 'price'},
{headerName: 'Make', field: 'make2' },
{headerName: 'Model', field: 'model2' },
{headerName: 'Price', field: 'price2'},
{headerName: 'Make', field: 'make3' },
{headerName: 'Model', field: 'model3' },
{headerName: 'Price', field: 'price3'},
];
rowData = [
{ make: 'Toyota', model: 'Celica', price: 35000, make2: 'Toyota', model2: 'Celica', price2: 35000, make3: 'Toyota', model3: 'Celica', price3: 35000},
{ make: 'Ford', model: 'Mondeo', price: 32000 },
{ make: 'Porsche', model: 'Boxter', price: 72000 },
{ make: 'Toyota', model: 'Celica', price: 35000, make2: 'Toyota', model2: 'Celica', price2: 35000, make3: 'Toyota', model3: 'Celica', price3: 35000},
{ make: 'Ford', model: 'Mondeo', price: 32000 },
{ make: 'Porsche', model: 'Boxter', price: 72000 },
{ make: 'Toyota', model: 'Celica', price: 35000, make2: 'Toyota', model2: 'Celica', price2: 35000, make3: 'Toyota', model3: 'Celica', price3: 35000},
{ make: 'Ford', model: 'Mondeo', price: 32000 },
{ make: 'Porsche', model: 'Boxter', price: 72000 }
];
constructor(
) { }
ionViewDidEnter() {
this.createBarChart(this.myChart);
this.createBarChart(this.myChart2);
this.createBarChart(this.myChart3);
}
onClicked(){
let v = window.innerWidth;
alert(v);
}
createBarChart(canvasId) {
this.bars = new Chart(canvasId.nativeElement, this.data);
}
}
Webで表をいれたいときってあります。主に3つの方法があると考えております。
・Tableを使う
・FlexBoxを使う
・ライブラリを使う
今回は、ライブラリを使う方法としてAg-gridを導入します。先頭の二つは簡単な表には使用できると思いますが、例えば1万行を超えるようなデータを表にして、Excelのようにセルごとに編集して色分け、、などをするためにはAg-gridを使うのが最適だと思います。
無料でもできる範囲はかなりひろいです。
$ ionic info
Ionic:
Ionic CLI : 6.4.1
Utility:
cordova-res (update available: 0.14.0) : 0.9.0
native-run (update available: 1.0.0) : 0.2.9
System:
NodeJS : v12.10.0
npm : 6.14.2
OS : macOS Mojave
ライブラリをnmpでインストールしたあと、プロジェクト全体のレイアウトを管理するglobal.scssで読み込みます。その後、使いたいページのpage.module.tsで読み込んだ後、page.tsで情報を設定して、page.htmlにタグを設置します。
https://www.ag-grid.com/angular-grid/
パッケージのインストールを行います
npm install --save ag-grid-community ag-grid-angular
すると、node_modulesにライブラリが配置されます。
Angularではstyles.scss
に書き込みますが、ionicではglobal.scssに書き込みます。
@import "../node_modules/ag-grid-community/src/styles/ag-grid.scss";
@import "../node_modules/ag-grid-community/src/styles/ag-theme-alpine/sass/ag-theme-alpine-mixin.scss";
.ag-theme-alpine {
@include ag-theme-alpine();
}
あとは、これを使いたいページのモジュールで読み込むだけです。ag-gridはモジュールなので、tsファイルで読み込む必要はありません
以上で準備完了です。あとは使いたいpageで読み込みます。下記はsrc/app/app.module.ts、src/app/app.component.ts,src/app/app.module.htmlの場合ですが、src/app/tab1/tab1.module.tsなどでも同じです。その場合、src/app/app.module.tsには設定する必要はないです。
それではsrc/app/app.module.tsから編集します。
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AgGridModule } from 'ag-grid-angular';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
AgGridModule.withComponents([])
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
次にsrc/app.component.ts
で情報を設定します。
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'app';
columnDefs = [
{headerName: 'Make', field: 'make' },
{headerName: 'Model', field: 'model' },
{headerName: 'Price', field: 'price'}
];
rowData = [
{ make: 'Toyota', model: 'Celica', price: 35000 },
{ make: 'Ford', model: 'Mondeo', price: 32000 },
{ make: 'Porsche', model: 'Boxter', price: 72000 }
];
}
最後にapp/app.component.htmlファイルでタグを設置します。
<ag-grid-angular
style="width: 500px; height: 500px;"
class="ag-theme-alpine"
[rowData]="rowData"
[columnDefs]="columnDefs"
>
</ag-grid-angular>
そうすると、下記のような表が表示されるはずです。
タイトルの通り、サーバ上のデータをexportしてxammpのローカルにインポートしたらログインできなくなった。
’http://localhost:8080/phpmyadmin/’でデータベースの情報を見たら、メールアドレスとして使用していたユーザー名が変わっていた。メールアドレスは独自ドメインのものを使っていたのだが、@以降がlocalhostに変わっていた。
また、site-guardと干渉することもあるということなので、import/export時にはそのプラグインをオフにした方が良さそう。
site-guardをオフにする
export/importする
’http://localhost:8080/phpmyadmin/’でユーザ名を書き換える
ということになりそう。あまり普段からやる感じでもなくなるけど。
1
先日公開した個人アプリをプレスリリースしたら、ケータイウォッチ経由でYahoo!に取り上げてもらいました。
どう書くか、どこに送るか、そのタイトル、文面は?などわからないことばらけで進めたのですが、なんとか成功体験を1つつかめたのは良かったです。
https://k-tai.watch.impress.co.jp/docs/news/1190264.html
プレスリリースの書き方について迷われている方もいると思うので、全文面を公開します・・!
取り上げられた様子がこちら。
こちらがその文面です。
よろしくお願いいたします
理系男子必見!「数マニア -数学は美しい-」を6月12日よりリリース
~ひたすら円周率を読み上げる究極のリラクゼーションアプリ~
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Androidアプリ「数マニア -数学は美しい-」を提供開始
- 「数学ガール」「博士の愛した数式」など数学をテーマにした小説や映画が有名ですが、「数マニア」は、美しいヒーリングミュージックの代わりに、数をひたすら読み上げて安眠へと導く少し変わったリラクゼーションアプリです。ひたすら続く数字を聞きながら、深い眠りへとあなたを導きます。
https://play.google.com/store/apps/details?id=com.rainbows.read_pi
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
夫婦でスマートフォンアプリケーション開発を手掛ける「なないろプロジェクト」(所在地:**)は、リラクゼーションアプリ「数マニア -数学は美しい-」を、2018年6月12日より正式にリリースしました。これまで、数学定数を1万桁読み上げるリラクゼーションアプリはありませんでした。
【Google Play ストア ダウンロードページ】
https://play.google.com/store/apps/details?id=com.rainbows.read_pi
■アプリ概要
アプリ名 :「数マニア -数学は美しい-」
配信開始 :2019年 6 月 12 日
料金 :無料(広告モデル)
ジャンル :音楽&オーディオ
対応 OS :Androidバージョン 4.1以降
■ターゲット
理系の男子大学生
■背景
今回開発したのは夫である**。開発背景をこのように語ります。
「高校の数学クラブで数学オリンピックを目指した高校生も、しがない会社員となりました。それでも数の不思議への想いは変わらず、円周率をひたすら読み上げるアプリを作りたくなりました。
円周率をピアノで弾くととても美しいことをご存知ですか。無味乾燥な数字の羅列も、実際に聞いてみると不思議な気持ちにさせてくれます。寝る前のリラックスミュージックの代わりにきいてみてください。『どうして円周率にはゼロが出てこないの?』『どうして同じ数字がこんなに連続するの?』そんな疑問をもとにだんだん眠くなるはず。。きっと数学マニアだけではなく、みんなに響きます」
■3つの特長
1:円周率以外にも、アペリー定数、オメガ定数など5つの定数を収録
当アプリは、数学的に興味深い性質を持つ定数を5つ厳選しました。
円周率や黄金比などだれもが知っている定数から、アペリー定数、オメガ定数など数学的に奥深いものも掲載されています。それぞれの定数には、小ネタも併せて掲載されているので、友人とのちょっとした雑談にも重宝します。
2:スマホアプリ初!5つの無理数を1万桁まで読み上げ可能
当アプリは、Androidの提供するTTS(Text to Speech)機能を用いて、それぞれの定数を1万桁読み上げます。数列を掲載するWebページは数多くありますが、1万桁を読み上げるリラクゼーションアプリはこれまでありませんでした。
3:読み上げ言語は、英語、日本語に対応
「数字を読み上げられると目が冴えちゃう」という方に配慮して、読み上げは日本語、英語に対応しています。気分に合わせて好きな言語が選択可能です。
■今後の展開
今後の展開について、開発者はこのように語ります。
「このアプリ製作を通じて、数学の奥深さを改めて感じることができました。興奮しすぎて眠れないときは、わたしもこのアプリでリラックスしたいと思います。少しでも多くの方に興味を持っていただけると幸いです」
■会社概要
組織名(個人開発者) :なないろプロジェクト
(英語名Awesome Rainbows)
代表者 :実名
所在地 :実際の住所
■本件に関するお問い合わせ先
組織名 :なないろプロジェクト
担当者 :実名
所在地 :TEL:携帯番号
Email :awesome.rainbows7じーめいる
是非、参考にしてみてください。
また、もっとこうしたらというアドバイスもお願いいたします!
高機能なデータハンドリングが魅力のPythonですが、Pandasを使用すると複雑な処理を1行でできるので便利です。よくわからないけど、とりあえずPythonでデータを操作したいというなら、Pandasでデータを読み込めば間違いありません。
[chat face=”man1″ name=”” align=”left” border=”gray” bg=”none” style=””]汎用的なデータの読み込みならPandasがおススメ![/chat]
Pandasは、データハンドリング用で使われる最も有名なライブラリのひとつです。
Pythonは本体には最小限の機能しか備えておりません。パソコンにソフトをインストールしてできることを増やすように、Pythonは、追加のパッケージ(ライブラリ)をインストールして様々なことができるようになります。Pandasは、データ処理用のライブラリです。データの読み込みは様々な方法でできますが、最も覚えることが少なく、汎用的な手法として、Pandasでのデータ読み込みがおススメです。
例えばPandasは下記のようなときに使用できます
・Excelデータの読み込み
・CSV形式の読み込み
・txtデータの読み込み
Pandasのインストール方法は、大きく分けて二つあります。一つは、Pythonの本体に単独でインストールする方法。もう一つは、Anacondaを利用する方法です。Anacondaとは、よく使用するパッケージをPython本体と一緒にダウンロードできる拡張版Pythonのイメージです。Anacondaは下記からインストールできますが、その場合、すでにPandasは自動でインストールされていますのでそれ以上の環境構築は必要ありません。
pipでインストールする場合:
pip install pandas
Anacondaでインストールする場合(おすすめ):
https://www.anaconda.com/で最新版をインストールすればOK.他の言語でもいえることですが、追加ライブラリのバージョンは、合わせておかないと動きません。これを依存関係といいますが、これらを整えて配布されているのはAnacondaです。Continuum社の有料サービスの無料版というのも安心です。
それでは、実際にPandasでcsvのデータを読み込みます。コードをGitHubにあげておくので、そちらからダウンロードかまいません。web上でPythonを実行できるpaizaのページからコードを貼り付けて実行していただいてもいいと思います。
paizaのページ:https://paiza.io/projects/featured?language=python3
GitHub;https://github.com/awesomerainbows/wp_read_csv
もし初めての場合、どこに何をおいたらいいかわからないと思います。そのときは、読み込みたいcsvとpythonのファイルは同じ階層においてください。おススメは、デスクトップにtestというフォルダを作成して、そこにpythonファイルとcsvの2つを配置することです。
こんな感じです。
Pythonコードは下記です。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pandas as pd
df = pd.read_csv("hogehoge.csv")#ファイル名は、クオテーションで囲んでください。もしtest.csvという名前なら、"hogehoge.csv"は、"test.csv"です
print(df)#読み込んだデータをすべて表示
print(df.head())#最初の5行程度を表示
print(df.shape)#読み込んだデータの行数と列数を表示。100行2列なら(100,2)です
[chat face=”man1″ name=”” align=”left” border=”gray” bg=”none” style=””]全然読み込めないんだけど[/chat]
[chat face=”man1″ name=”” align=”right” border=”gray” bg=”none” style=””]ファイル名のあとに読み込む条件を指定すれば読み込めるよ[/chat]
読み込むことはできましたでしょうか。
整形されたデータの場合はこれで読み込めたはずです。
ところが、実際扱うデータは往々にしてエラーを吐いてしまいます。
その場合、下記の項目をチェックして、読み込む条件を指定して読み込んでみてください。
エラーが出る場合、ポイントは下記になります。列名(header)が先頭にあるかどうか
行番号(index)がデータに含まれるかどうか
列名のないデータだけのファイルかどうか
この場合、下記のコードで1行目と2行目をスキップして読み込みますので下記になります。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pandas as pd
df = pd.read_csv("hogehoge.csv",skiprows=2)#skiprowsの引数を指定することで先頭の2行を無視します
print(df)#読み込んだデータをすべて表示
print(df.head())#最初の5行程度を表示
print(df.shape)#読み込んだデータの行数と列数を表示。100行2列なら(100,2)です
[chat face=”man1″ name=”” align=”left” border=”gray” bg=”none” style=””]df = pd.read_csv(“hogehogehoge.csv”,header=2)と列名を指定しても読み込めます[/chat]
[chat face=”man1″ name=”” align=”right” border=”gray” bg=”none” style=””]0から数えるから、Excelでいう3行目は2で指定するんだね[/chat]
この場合は、1列目はindexであると明示的に指定します。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pandas as pd
df = pd.read_csv("hogehoge.csv",index_col=0))#indexは0列目だと明示します
print(df)#読み込んだデータをすべて表示
print(df.head())#最初の5行程度を表示
print(df.shape)#読み込んだデータの行数と列数を表示。100行2列なら(100,2)です
この場合、1行目からデータであるということを指定する必要があります。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pandas as pd
df = pd.read_csv("hogehoge.csv",header=None))#header=Noneでカラム名はないことを明示します
print(df)#読み込んだデータをすべて表示
print(df.head())#最初の5行程度を表示
print(df.shape)#読み込んだデータの行数と列数を表示。100行2列なら(100,2)です
列名を作成しながら読み込みたい場合、
df=pd.read_csv(“hogehoge.csv”,header=None,names=[“a”,”b”,”c”,”d”])
のようにnamesの引数で指定します
その他さまざまな条件を指定してデータを読み込むことができますが、詳細は公式ドキュメントを参照していただくのがよいと思いますので、最後によく使う指定条件をまとめたいと思います。
◎ファイルが大きすぎる
⇒nrows:nrows=100のように読み込む行数をint型で指定
◎なぜかエラーが起きる
⇒engine:pythonで読み込むかCで読み込むかを指定。engine=”python”と指定すると柔軟に読み込める
◎日本語が文字化けする
⇒encoding:encoding=”shift-jis”で読み込んでみる
よろしくお願いします。
以上、お疲れさまでした。
1
Chrome Remote Web Inspector によるデバッグがよさそう。
参考にしたサイトはこちら。
半日ほど迷った。ポイントは、アンドロイドの端末で「usbデバッグを有効化」することと、アプリ側にもやり取りを許可するためのソースを埋め込まないといけないこと。ソースはJavascriptではなくて、Javaなので、どこに書くか迷った。結局追加プラグインのファイルにJavaのファイルがあったので、そこに張り付けた。
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){ WebView.setWebContentsDebuggingEnabled(true); }
一度実行されたらchromeとの接続には支障がないとのことで、プラグイン呼び出しのメインの関数のなかに記載した。なお、JAVAのファイルの中でパッケージをインストールする必要があるので、そのファイルの上のほうで下記コードも書き加えた。
import android.os.Build;import android.util.Log;import android.content.pm.ApplicationInfo;import android.webkit.WebView;
import android.util.Log;import android.content.pm.ApplicationInfo;import android.webkit.WebView;
書き加えたのはcordova-plugin-admobproプラグインのなかの
AdMobPlugin.javaというファイルで、
@Override protected void pluginInitialize() { super.pluginInitialize(); // TODO: any init code }という部分を
@Override protected void pluginInitialize() { super.pluginInitialize(); if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){ WebView.setWebContentsDebuggingEnabled(true); }; // TODO: any init code }と書き換えた
windows10
if you are able to use use adb commands already, then you can get package name as below.
extract android app's package name
matplotlibで日本語を扱いたいとき、フォントをダウンロードして、matplotlibrcファイルを修正して、、みたいな方法が正統派なのかもしれない。
でも職場のパソコンに一斉にそういう設定ができますか?みたいなときがある。
1.フォントをダウンロードして、C:\Users\**\Anaconda3\Lib\site-packages\matplotlib\mpl-data\fonts\ttfの中にコピペをする
2.ファイルのなかにigfont = {‘family’:’IPAexGothic’}という文字列を追加しておく
これだけでよさそう。これなら自動でできそう。
ちなみにつまったところとして、コピペするファイルはipaexg.ttfとipaexm.ttfの2つだということ。一方だけでをコピペするだけだとうまくいきませんでした。フォントのダウンロード先は下記。
1
4年間名古屋で活動していた会員経験を基に説明するよ.
4年間会員をしていましたが,2020年に名古屋支部の役員の休会されたのを機に休会しました.
3000円の月額が少し高いというように感じていたのも事実です.以降は休会半年前くらいの2020年初めの記事です.
2021年8月に追記
t
わたしはバラ十字会に入会して4年目になります。バラ十字!?なにそれ(笑)と妻に言われたものですが、なんだかんだ続いています。「怪しさ満点だな」という印象でしたが、HPに載っているオバマ大統領の推薦書をみて興味本位で入りました。ここでは実際にどんな活動をしているかお伝えしたいと思います。
HPを見るといろいろかいてあります。
・人生の意味・意義・理由を知りたいあなたへ
・人生を知り、豊かに生きる叡智を学ぶ
・世界の歴史の偉人たちが学んできた成功哲学
2016年に入会を検討したとき,ネットで評判を調べてもなかなか出ず実態がよくわからなくて困りました.
バラ十字会は
①月に一度送られてくる薄めの本を毎週読む。3ヶ月ごとに理解度確認テストのようなものを送付する
②毎月ないしは隔月で会合に参加する
という通信教育を行なっているNPO法人です。入っている感覚として、新興宗教かと聞かれるとそうではないと思います。入ったところでそれ以上の勧誘はありませんし、教義を強制されることもありません。物品の購入で寄付することはできますが、それはカトリック教会などでも教会に売店があるのと同じですし、購入を強制されたと感じたことは一切ありません。感覚でいうと、啓蒙・自助団体にちかいです。
とはいえ、バラ十字会は良くも悪くもぶっとんだスピリチュアル団体だと感じました。人間にはソウルと呼ばれる輪廻を繰り返す主体が存在し、人生を通じてその本質を開花させていくという思想です.ソウルを薔薇で表現し、肉体を十字で表現し、その組み合わせがアイコンに使われている薔薇十字です。学者を含む著名人も入会しており、海外では比較的知られた国際団体でもあります。
(強制はされないものの薔薇十字会の立場でいうと)特徴的なところでいうと、
・身体と霊魂(ソウルと呼ぶ)が存在する
・生まれ変わりはあり、ソウルは人生を通じて開花している
・この世界を超えた世界が存在する
などの考えは一般にはかなり衝撃だと思います。また、(強制はされないものの)会合に出ると全面に押し出されるのでこれも他にはない特徴だと思います。まぁ結構私は好きですけどね、
ネットで検索すると薔薇十字団という昔の団体が出てくると思います。ただこれ自身は直接関係あるわけではないと思います。フリーメイソンとの違いみたいなのも聞かれるのですが、向こうのほうが有名です。本質的には変わらないと思いますが、もし人脈構築を目的とするならフリーメイソンの方がいいと思います。
日本ではマイナーなバラ十字会ですが、実はかなり大きな組織だと感じることがあります。
たとえば日本バラ十字会のHPには、オバマ大統領の祝電が掲載されています。いわく、バラ十字会自身は、古代エジプトの思想から生まれ、ギリシャなどの哲学を踏まえ、さらに先進的な科学的な知見を取り入れた教義を伝えるといっております。実態は上に述べたようなNPO法人で、4年経ってもまだ全体がつかめていないというのが正直な感想で、ときどき隔月で行われている会合で、日本にビジネスの出張できたのでついでに顔を出した、というフランス人がきたりしたこともありました。
HPに公開されている情報以上のことは言わないでくださいということなのですが、参加している人は会社員だったり学校関係者だったり主婦であったりです。私はNP-Systemsという個人事務所をやっています。精神的なものに惹かれているっていう点では皆同じだと思います。女性がやや多いです。
あらためてになりますが、バラ十字の思想としては
・身体と霊魂(ソウルと呼ぶ)が存在する
・生まれ変わりはあり、ソウルは人生を通じて開花している
・この世界を超えた世界が存在する
あたりは特徴的な思想です。古代エジプトから生まれ現代に続く知識を体系立てて伝えるとしています。シンボルはこん感じで、ソウルが身体を通じて開花していく様子を示しているとされています。
昔は秘密結社だったようです。いまは通信教育(!)です。一般には公開されておりません。(適切な準備をしてからじゃないとうまく教義を伝えられないからという理由です)フリーメイソンも似たイメージですが、フリーメイソンほどお金はかからないと思います。あと、フリーメイソンは紹介制なのですがバラ十字会は誰でも入会できます。フリーメイソンほど有名ではないので、興味本位で入る人が少ない分静かに過ごせるかなとは思います。
わたしは理系で、むかしは無神論者でした。科学しか信じないような性格でしたが、その目線であえて批判的な点をあげたいと思います
という2点です。
1点目については、例えば「前世があるか」「過去世があるか」「7という数字は神秘的か」「魂はいつ人体に宿るのか」といった事柄は、実際はわからないというのが真実だと思うのです。それを踏まえた上で、「でもわたしは個人的にはそうだと思います」というならわかりますが、バラ十字のスタンスは「あなたは知らないし信じないかもしれないけど、それが実は絶対的な真実なんです、強制はしないし思想は自由だと思うけど」というスタンスなのです。これを少し独善的だと感じる時があります。また、自分の意見をいうときに「科学的に正しい」「神秘学的に正しい」というのもやめた方がいいかと思います。性格には、合理的な判断によりこう考えている、ということだと思います。
2つ目については、まぁ高齢化の日本社会ではどうしようもないかな。。ちなみに男女比は男性3.5に女性6.5のイメージです。
わたしの意見だと、自らの本質であるソウルというものがあり、それが人生を通じて花開くことを目指すということに共感を感じられるか次第だと思います。無神論者で人間は肉体以上のものではないと思うなら難しいと思いますが、自分の本質は意識とは別のところにあるなにか高尚なものかもしれない、それに触れたい、近づきたいと思うなら、バラ十字会はベルトコンベアのような役割を果たすかもしれません。
また、個人的に会合で面白いと思ったことがあるます。
・幽霊の話、前世のはなし?ぜんぜんOK!
わたしの参加している地区を主導してくれている方はとてもいい女性ですが、お茶会のときに「どうぞここでは普段できない話を(笑)」と言ってくれたりすると和みます。たしかに前世、霊魂、秘密結社、話題はなんでもありです。
・会合ではエプロンのようなものをする。ふんどしに見えないこともないが、それを若い女性がしているのがちょっと面白い
強制はされませんが、薔薇十字会自身はかなりコアな思想をもっています。会合では瞑想のようなものを全員で最初の1時間程度おこなうのですが、建前上こう振舞ってくださいとか、これを着用してくださいとか言われます。別に思想を強要するわけではないですし、マナーのイメージなので問題ないと思いますが、ちょっとそういうところがどきどきしたりします。
・ときどき「こんな人が生活していたのか」と思うような人が参加していたりする。
以前、会合に初参加のひとが、古参の会員に「前世以来、ひさしぶり!」と挨拶していたのはびっくりした(笑)
会合は規模の大きさにしたがっていろんな名前がありますが、東京の大きなものだと入会してすぐに参加するのは難しいですが、3ヶ月くらいするとどの会合にも参加できるようになります。
東京では、板橋で毎月会合があります。
名古屋と奇数月に、金沢では偶数月に行なっています。
あとは札幌と大阪も定期的におこなっていますね。岡山もやっているようです。
実際に参加するとどういう人がいるのかわかりますし、迷っているなら参加するといいと思います。2回くらいきてやめてしまう人が多い印象ですが、それも問題ないとされている空気ですし。「フリーメイソンとか秘密結社に興味ある」「前世療法を仕事にしてて興味あって」みたいな人もいますし、いたって普通な人もいます。
まぁ精神的なことに興味があるならきてみてもいいんじゃないかと思います。
読んでくれてありがとう.これからもよろしくね
1
プラグインやライブラリをPython側に入れるかWordPres側に入れるかで2通りの方法があるよ
自動投稿する際,プラグインやライブラリをPython側に入れるかWordPres側に入れるかで2通りの方法があります.
RESTの方が汎用性は高い一方で、テーマによっては使えないことがあります。XML-rpcの場合は昔からあるので追加設定はいらず安定感はあります。Pythonを使ってxmlrpcでWordPressサイトを操作する場合、python-wordpress-xmlrpcをpipすれば使えるようになります。私はWordPressのプラグインを増やしたくなので後者の方を利用するようにしています。
動作環境はWindows10 64bitでPython3.6.5(Anaconda3.5.1-0)。 Mac Python3.8とXserverのターミナル(Python3.8)からもうまく動作しました。
pip install python-wordpress-xmlrpc
でライブラリを入れました。
(conda install ***だとファイルが見つからなかったので、 Anaconda環境であったがpipで入れました)
あとは下記のコードを実行するだけです。
# -*- coding: utf-8 -*-
import time
from datetime import datetime
from wordpress_xmlrpc import Client, WordPressPost
from wordpress_xmlrpc.methods.users import GetUserInfo
from wordpress_xmlrpc.methods.posts import GetPosts, NewPost
def main():
"""
変数を定義
"""
id="******"
password="******"
#idとpasswordはwordpressの管理画面に入るためのもの
url="https:***/xmlrpc.php"
#第3者が閲覧するURLの後ろに/xmlrpc.phpをつける。
#ワードプレスの管理画面の後ろにつけるとエラーになった
which="publish"
#which="draft"
#下書きに投稿するか本番で投稿するか選択
"""
クライアントの呼び出しなど
"""
wp = Client(url, id,password)
post = WordPressPost()
"""
実際に投稿する
"""
post.post_status = which
post.title = "タイトルをここに書く"
post.content = "本文をここに書く"
post.terms_names = {
"post_tag": ['希望するtag1', '希望するtag2'],
"category": ['希望するカテゴリー1', '希望するカテゴリー2'],
}
#過去に投稿した記事としたい場合、投稿日をここで指定。例として2018年1月1日10時5分10秒に投稿した例を示す。
post.date=datetime.strptime("2018/1/01 10:05:10","%Y/%m/%d %H:%M:%S")
wp.call(NewPost(post))
if __name__=="__main__":
main()
編集をする場合、編集したい記事のIDを取得したあと、その記事に対して操作します。
# -*- coding: utf-8 -*-
import time
from datetime import datetime
from wordpress_xmlrpc import Client, WordPressPost
from wordpress_xmlrpc.methods.users import GetUserInfo
from wordpress_xmlrpc.methods.posts import GetPost, GetPosts, NewPost, EditPost
def main():
id="******"
password="******"
#idとpasswordはwordpressの管理画面に入るためのもの
url="https:***/xmlrpc.php"
#第3者が閲覧するURLの後ろに/xmlrpc.phpをつける。
#ワードプレスの管理画面の後ろにつけるとエラーになった
"""
クライアントの呼び出しなど
"""
wp = Client(url, id, password)
post = WordPressPost()
posts = wp.call(GetPosts({'number': 5}))
for post in posts:
print(post.id, post.title,str(post.terms[0]))
if __name__=="__main__":
main()
もし編集したい記事が決まっている場合、その記事の編集画面にいくとURLにIDが表示されますのでそちらを利用することも可能です。
上記で記事IDを調べて、その記事に対して操作します。pidが編集したい記事のID(post_id)です。
# -*- coding: utf-8 -*-
import time
from datetime import datetime
from wordpress_xmlrpc import Client, WordPressPost
from wordpress_xmlrpc.methods.users import GetUserInfo
from wordpress_xmlrpc.methods.posts import GetPost, GetPosts, NewPost, EditPost
def main():
id="******"
password="******"
#idとpasswordはwordpressの管理画面に入るためのもの
url="https:***/xmlrpc.php"
#第3者が閲覧するURLの後ろに/xmlrpc.phpをつける。
#ワードプレスの管理画面の後ろにつけるとエラーになった
"""
クライアントの呼び出しなど
"""
wp = Client(url, id, password)
pid = 1030
post = wp.call(GetPost(pid))
post.post_status = "publish"
post.content = "content"
post.terms_names = {
"post_tag": ['tag1'],
"category": ['diary',],
}
ret = wp.call(EditPost(pid, post))
if __name__=="__main__":
main()
手元のPCはWIndowsでも Macでも動作確認しています。Xserverのターミナルからもうまく動作しました。しかし、以前Google Cloud PlatformのCloud functionsでデプロイした場合はできなかった記憶があります。AWS lamdbaなどでもエラーが起きる可能性があるのでローカルで動作させる事をお勧めします。
・siteGuardなどセキュリティ系のプラグインを入れると、デフォルトでxmlrpcをオフにしますので、解除が必要です
・Xserverなど一部のレンタルサーバでは意図的にデフォルト でアクセスをOFFにしていますので管理画面から設定変更が必要です
ダッシュ画面の左下からsiteguardを選択します。その中にXMMRPC防御という項目があるのでクリックします。
左上の部分でOFFを選択します。
xserverの場合、公式が丁寧に説明してくれているのでこちらを見れば大丈夫だと思います。
https://www.xserver.ne.jp/news_detail.php?view_id=6875
https://www.xserver.ne.jp/manual/man_server_wpsecurity.php#link-b02
読んでくれてありがとう.これからもよろしくね
1
ビックデータというのは10年くらい前から言われた言葉で、センサが安価になって多くのデータが得られるようになったり、Web上で多くのデータが得られるようになって言われた言葉です。データの量とマシンパワーで力づくでモデルを構築し、原因を分析したらモデル作成を行う方法です。特に深層学習のように人の判断を介在させず、データからのみで判断させるような解析は素晴らしいと思います。
しかし、今後、より注目されるのがスモールデータ分析だと思います。
ビックデータ解析ではもはやいかにデータを集められるかというのがポイントとなっています。ハードウェアの値段は下がっていますし、クラウドサービスで一時的にマシンパワーを借りることもできます。方法も公開されているものが多いので、既にビックデータ分析はレッドオーシャンという意見もあります。
それに対して、スモールデータは
のことでビックデータのようにブルートフォースな解析ができません。したがって、専門家の知見に基づく考察やデータのより繊細な前処理が必要となります。スモールデータでは、データからすべてを判断することができるほどのデータがありませんので固有技術的な考察を駆使してメカニズムを推定し、知見や仮説につなげることが重要です。
ビックデータと比べてスモールデータには下記のような特徴があります。
企業のドメスティックな環境で得られるデータというのはほとんどこれに相当すると思います。
そして、このスモールデータを解析するにあたって重要なのは
ということです。これはビックデータでも重要であることには違いありませんが、データ数が少ないと問題設定に応じたデータを選択的に取得する必要が出てきますのでよりその傾向は強くなると思います。
また、1番目の「目的に対して適切な問題設定を行う」という件についてはAIや機械学習になると途端に問題設定が曖昧になる傾向があると思います。しかし、何が目的なのか、そのためにどういう問題設定が適切なのかというのが人が行うべき業務なわけで解析でもこれが定まらないと成功するのは困難となります。例えば機械学習で株価を当てるということを考えたとき、目的は儲けるということですので、上がるか下がるかを予測するのが大事であって1円単位で予測することではないはずです。問題を適切に設定することで難易度は変わりますし、スモールデータだと今言った目的設定や課題設定がより重要になってきます。
今後スモールデータ分析が重要になる中で何を学べばいいかというと
だと思います。ビックデータだとライブラリに放り込んで比較的いい感じに分析してくれることがあってもスモールデータだと中身を理解していないと導く結論が大きく変わってしまうことがあります。またもう一つが専門的な知見です。固有技術的な考察を駆使してメカニズムを推定することでデータを効率的に活用することが求められますので、データサイエンスのみならず専門的な知見というのが大事になってくると思います。
データサイエンティストという職業がすっかり普及しましたが、今後はデータサイエンスに関する知識というのは専門家に求められる教養や素養という位置づけになり、各分野の専門家の役割というのが復活していくかもしれませんね。
AngularをはじめとするSPAでは、URLごとに実態のあるページが存在する一般的なサイトとは異なり、index.htmlをクライアント側で書き換えるため直接特定のアドレスにアクセスするとエラーがでます。
開発環境だと開発サーバ側でindex.htmlを読み込んでくれているので問題にならないのですが、デプロイ時には自分で設定することになります。設定内容はファイルが見つからない時はindex.htmlを参照してくれというものですので、Angularではなくサーバ側のapacheやnginxなどの設定ということになります。なのでデプロイ時に顕在化する問題となります。
.htaccessファイルに下記を指定します。サブドメインを使ってホスティングする場合、サブドメインのルート(サブドメインのindex.htmlのある場所)に下記を設置すればいいです。
<pre class="wp-block-syntaxhighlighter-code">RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html</pre>
こちらのページ(Front Controller Pattern Web Apps)に記載されているtry_filesを使って
index.html
に対して下記を設定します
try_files $uri $uri/ /index.html;
rootにある設定ファイル(確かfirebase.jsonだったと記憶)を下記のように直せばいいです
"rewrites": [ {
"source": "**",
"destination": "/index.html"
} ]
IISやRubyの場合は公式を見ていただくのが良いかと思います。
https://angular.io/guide/deployment#server-configuration
写真から文字情報を抽出して爆速でレポートや記事を作成するアプリを作成しています。無料なのでよかったらどうぞ。
iOS => https://apps.apple.com/app/id1497498494
Android => https://play.google.com/store/apps/details?id=com.rainbowsv2.ocr
上記の画像のようなサイドメニューとタブバーを備えたプロジェクトを作成します。
IonicのデフォルトテンプレートのひとつであるTabプロジェクトにサイドメニューを追加します。
https://petercoding.com/ionic/2019/05/05/side-menu-in-ionic4/
https://ionicframework.com/jp/docs/api/menu
下記のコマンドを打ってTabバーを備えたプロジェクトを生成します。
% ionic start sidemanu tabs --type=angular
さらにCapacitorを入れますか?(Integrate your new app with Capacitor to target native iOS and Android?) と聞かれたら、スマホアプリにすることを検討指定場合はYESにしておきます。
その後、作成したプロジェクトへ移動します。
$ cd sidemanu
プロジェクトへ移動したあと、下記コマンドで一度起動してみます。
ionic serve
このような画面が立ち上がればOKです。なお、デフォルトがIEなどのブラウザになっているとそもそも表示されないです。ChromeやEdgeでアクセスしてください。
なお、Tabバーのプロジェクト構成は下記となっています。
.
├── app-routing.module.ts
├── app.component.html
├── app.component.scss
├── app.component.spec.ts
├── app.component.ts
├── app.module.ts
├── explore-container
│ ├── explore-container.component.html
│ ├── explore-container.component.scss
│ ├── explore-container.component.spec.ts
│ ├── explore-container.component.ts
│ └── explore-container.module.ts
├── tab1
│ ├── tab1-routing.module.ts
│ ├── tab1.module.ts
│ ├── tab1.page.html
│ ├── tab1.page.scss
│ ├── tab1.page.spec.ts
│ └── tab1.page.ts
├── tab2
│ ├── tab2-routing.module.ts
│ ├── tab2.module.ts
│ ├── tab2.page.html
│ ├── tab2.page.scss
│ ├── tab2.page.spec.ts
│ └── tab2.page.ts
├── tab3
│ ├── tab3-routing.module.ts
│ ├── tab3.module.ts
│ ├── tab3.page.html
│ ├── tab3.page.scss
│ ├── tab3.page.spec.ts
│ └── tab3.page.ts
└── tabs
├── tabs-routing.module.ts
├── tabs.module.ts
├── tabs.page.html
├── tabs.page.scss
├── tabs.page.spec.ts
└── tabs.page.ts
これにサイドメニューを設置して行きます
事前にサイドメニューに設置するページを作成しておきます。新しいターミナルを立ち上げてプロジェクトフォルダまで移動したあと、下記コマンドでpageを2つ追加します。
ionic generate page side/mySide1
ionic generate page side/mySide2
プロジェクトは下記のようになります。
.
├── app-routing.module.ts
├── app.component.html
├── app.component.scss
├── app.component.spec.ts
├── app.component.ts
├── app.module.ts
├── explore-container
│ ├── explore-container.component.html
│ ├── explore-container.component.scss
│ ├── explore-container.component.spec.ts
│ ├── explore-container.component.ts
│ └── explore-container.module.ts
├── side
│ ├── my-side1
│ │ ├── my-side1-routing.module.ts
│ │ ├── my-side1.module.ts
│ │ ├── my-side1.page.html
│ │ ├── my-side1.page.scss
│ │ ├── my-side1.page.spec.ts
│ │ └── my-side1.page.ts
│ └── my-side2
│ ├── my-side2-routing.module.ts
│ ├── my-side2.module.ts
│ ├── my-side2.page.html
│ ├── my-side2.page.scss
│ ├── my-side2.page.spec.ts
│ └── my-side2.page.ts
├── tab1
│ ├── tab1-routing.module.ts
│ ├── tab1.module.ts
│ ├── tab1.page.html
│ ├── tab1.page.scss
│ ├── tab1.page.spec.ts
│ └── tab1.page.ts
├── tab2
│ ├── tab2-routing.module.ts
│ ├── tab2.module.ts
│ ├── tab2.page.html
│ ├── tab2.page.scss
│ ├── tab2.page.spec.ts
│ └── tab2.page.ts
├── tab3
│ ├── tab3-routing.module.ts
│ ├── tab3.module.ts
│ ├── tab3.page.html
│ ├── tab3.page.scss
│ ├── tab3.page.spec.ts
│ └── tab3.page.ts
└── tabs
├── tabs-routing.module.ts
├── tabs.module.ts
├── tabs.page.html
├── tabs.page.scss
├── tabs.page.spec.ts
└── tabs.page.ts
以上で準備は完了です。あとはこの2つのページへハンバーガメニューからアクセスできるようにします。
Ionicは、サイドメニューを簡単に作成するためにion-menuと呼ばれるコンポーネントを提供しています。app.coponent.htmlの中にion-menuタグを使ってサイドメニューを作っておいて、それを<ion-router-outlet>の中でidで紐付けます。ion-router-outletタグはコンポーネントを埋め込むために使用するものですので、これに登録しておくと作成したサイドメニューを他のページから簡単に読み込むことができるようになります。
最初はapp.component.htmlは下記のようになっています。ion-router-outletタグに何も登録がありません。
<ion-app>
<ion-router-outlet></ion-router-outlet>
</ion-app>
これを下記のようにします。
<ion-app>
<ion-menu side="start" menuId="first" contentId="my-content">
'''
'''
</ion-menu>
<ion-router-outdlet id="my-content"></ion-router-outlet>
</ion-app>
こうすることにより、ion-menuタグの中に設定した中身を他のページから読み込むことができるようになります。私の場合、下記のように設定しました。
<ion-app>
<ion-menu side="start" menuId="first" contentId="content1">
<ion-header>
<ion-toolbar>
<ion-title>Navigate</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list lines="none">
<ion-list-header>
一般情報
</ion-list-header>
<ion-menu-toggle autoHide="false">
<ion-item routerLink="/my-side1" routerLinkActive="active" routerDirection="root" detail="false">
<ion-icon slot="start" name="person"></ion-icon>
<ion-label>
Privacy Policy
</ion-label>
</ion-item>
</ion-menu-toggle>
<ion-menu-toggle autoHide="false">
<ion-item routerLink="/my-side2" routerLinkActive="active" routerDirection="root" detail="false">
<ion-icon slot="start" name="help"></ion-icon>
<ion-label>
Terms of use
</ion-label>
</ion-item>
</ion-menu-toggle>
</ion-list>
</ion-content>
</ion-menu>
<ion-router-outdlet id="content1"></ion-router-outlet>
</ion-app>
公式にも実装例が載っています。
https://ionicframework.com/docs/api/menu
以上でサイドメニューを設置できましたので、tab1ページから読み込んでみます。tab1.page.htmlはデフォルトではこのようになっていると思います。
<ion-header [translucent]="true">
<ion-toolbar>
<ion-title>
Tab 1
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">Tab 1</ion-title>
</ion-toolbar>
</ion-header>
<app-explore-container name="Tab 1 page"></app-explore-container>
</ion-content>
hdearの中で下記のタグで読み込めるようになりますので
<ion-buttons slot="start">
<ion-menu-button></ion-menu-button>
</ion-buttons>
tab1.page.htmlを丸ごとこのように変更します。
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-menu-button></ion-menu-button>
</ion-buttons>
<ion-title>
File selection
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">Tab 1</ion-title>
</ion-toolbar>
</ion-header>
<app-explore-container name="Tab 1 page"></app-explore-container>
</ion-content>
サイドメニューから飛んだ先で戻るボタンを設置できます。
最初はこのようになっていると思いますが、
<ion-header>
<ion-toolbar>
<ion-title>mySide2</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
</ion-content>
下記のようにion-back-buttonを設置します。
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button defaultHref="/"></ion-back-button>
</ion-buttons>
<ion-title>
Privacy policy
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
</ion-content>
そうするとこのように戻るボタンが設置できます。
Ionicでグラフを描写するライブラリにはいくつかあるようですが、安定していてよく使われているchart.jsを使いことにしました。意外に簡単でびっくりしました。
プロジェクトのルートフォルダに移動して、Terminalで下記コマンドを実行します。
npm install chart.js --save
すると下記のようなメッセージが出てchat.jsがインストールされます。
+ chart.js@2.9.3
added 4 packages from 7 contributors, removed 1 package and audited 1527 packages in 12.531s
node_modulesのなかに格納されるので、これを使いたいページのtsファイルから呼び出すだけで使用できるようになります。
このような棒グラフを書いてみます。
https://enappd.com/blog/charts-in-ionic-4-apps-and-pwa-part-1/52/
chart.jsはcanvas要素にグラフを描写するので、まずはグラフ要素をHTMLに記載します、
<ion-header>
</ion-header>
<ion-content>
=> <canvas #myChart></canvas>
</ion-content>
あとはtsファイルからライブラリをimportしたあとにグラフを描写するだけです。HTMLの要素を取得するので、ViewChildも呼び出します。
import { Component, ViewChild } from '@angular/core';
import { Chart } from 'chart.js';
@Component({
selector: 'app-admin',
templateUrl: './admin.page.html',
styleUrls: ['./admin.page.scss'],
})
export class AdminPage implements OnInit {
@ViewChild('myChart') myChart;
bars: any;
colorArray: any;
constructor() { }
ionViewDidEnter() {
this.createBarChart();
}
createBarChart() {
this.bars = new Chart(this.myChart.nativeElement, {
type: 'bar',
data: {
labels: ['Label1', 'Label2', 'Label3', 'Label4', 'Label5', 'Label6', 'Label7', 'Label8'],
datasets: [{
label: 'Viewers in millions',
data: [25, 30, 50, 60, 92, 75, 100, 67],
backgroundColor: 'rgb(50, 194, 129)', // array should have same number of elements as number of dataset
borderColor: 'rgb(50, 194, 129)',// array should have same number of elements as number of dataset
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
}
>>> lst = [i for i in range(10)]
>>> lst
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
こういうリストがあったときに全体に対して操作するならこれ
>>> lst2 = list(map(lambda e:e*2,lst))
>>> lst2
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
python3では、map関数が返すものはmap objectなのでlistへ変換する必要がある。
>>> lst2 = list(filter(lambda e:e%2==0,lst))
>>> lst2
[0, 2, 4, 6, 8]
1
Ionic:
Ionic CLI: 6.4.1 (/Users/myName/.nodebrew/node/v12.10.0/lib/node_modules/@ionic/cli)
Ionic Framework : @ionic/angular 5.1.1
@angular-devkit/build-angular : 0.901.6
@angular-devkit/schematics: 9.1.6
@angular/cli : 9.1.6
@ionic/angular-toolkit : 2.2.0
Utility:
cordova-res (update available: 0.14.0) : 0.9.0
native-run (update available: 1.0.0) : 0.2.9
System:
NodeJS : v12.10.0 (/Users/masaya/.nodebrew/node/v12.10.0/bin/node)
npm : 6.14.2
OS : macOS Mojave
公式ドキュメントはこちら
https://github.com/ngx-translate/core
npm install @ngx-translate/core @ngx-translate/http-loader --save
"dependencies": {
"@ngx-translate/core": "^12.1.2",
"@ngx-translate/http-loader": "^4.0.0",
app.module.tsにて、TranslateModuleをHttpClientModule, HttpClientと一緒にインポートします.
import {HttpClientModule, HttpClient} from '@angular/common/http';
import {TranslateModule} from '@ngx-translate/core';
・
imports: [
HttpClientModule,
TranslateModule.forRoot(),
],
使いたい場所のモジュールで
import {HttpClientModule, HttpClient} from '@angular/common/http';
import {TranslateModule, TranslateLoader} from '@ngx-translate/core';
import {TranslateHttpLoader} from '@ngx-translate/http-loader';
export function createTranslateLoader(http: HttpClient) {
return new TranslateHttpLoader(http, '../../assets/i18n/', '.json');
}
@NgModule({
imports: [
TranslateModule.forChild({
loader: {
provide: TranslateLoader,
useFactory: (createTranslateLoader),
deps: [HttpClient]
}
}),
],
import {TranslateService} from '@ngx-translate/core';
constructor(
private translate: TranslateService,
) {
this.translate.setDefaultLang('en');
this.translate.use('en');
}
あとHTMLに
<p>{{ 'HELLO' | translate }}</p>
とかく
最後に
/assets/i18n/
を作成して、jsonファイルをおけばいいです。
{
"HELLO": "こんにちはEnglish"
}
複数の場合はこのように書いてください
{
"Main": "メイン",
"File selection": "ファイルの選択",
"1. Choose a file": "1. ファイルの選択",
"Pick a file from your storage": "ストレージから選択",
"Or take a new picture": "新しく写真を撮る",
"2. Crop your image": "2. 写真の切り抜き",
"select the area you want to analyze from the photo": "解析したいエリアを選択してください",
"No ads 3 times if you watch a short video": "広告が3回表示されなくなります!",
"Preparing for the analysis. Since this app uses service that need to be payed(from not you but me), an ad will be shown to you.":"安全な方法でアップロードします。 このアプリは有料のAPIを使用しているため、広告が表示されます。",
"Analyzing.":"分析しています。"
}
最後のブロックの後にカンマを入れるとエラーになりますので注意.
app.module.tsを下記のようにします.
+import {HttpClientModule, HttpClient} from '@angular/common/http';
+import {TranslateModule, TranslateLoader} from '@ngx-translate/core';
+import {TranslateHttpLoader} from '@ngx-translate/http-loader';
+export function createTranslateLoader(http: HttpClient) {
+ return new TranslateHttpLoader(http, '../assets/i18n/', '.json');
+}
@NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [
+ TranslateModule.forRoot({
+ loader: {
+ provide: TranslateLoader,
+ useFactory: (createTranslateLoader),
+ deps: [HttpClient]
+ }
+ }),
],
providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
bootstrap: [AppComponent],
})
export class AppModule {}
app.component.ts
+import {TranslateService} from '@ngx-translate/core';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.scss'],
})
export class AppComponent {
constructor(
+ private translate: TranslateService,
) {
+ this.translate.setDefaultLang('en');
+ this.translate.use('en');
}
}
ライフイベント、ライフサイクルとは、ページを読み込み、表示し、その後ユーザーが離脱する一連の流れの中で特定のタイミングで発火するDOMイベントのことです。Ionicでは、Ionic独自のライフイベントに加えて、Angularのライフイベントも利用することができます。
これにより、ページが読み込まれたらこれをする、ページに変化があったらこれをするといったことを実装できます。
それまでまずはAngularのライフイベントからです。Ionicでは、Ionic独自のライフイベントに加えて、Angularのライフイベントも利用することができます。個人的にはAngularのイベントを使う頻度の方が高いです。
こちらの公式ドキュメントに細かく記載されておりますので、ここではよく使うライフイベントについて転載します。
https://angular.jp/guide/lifecycle-hooks
イベントフック(これを関数のように書いて呼び出します) | 概要 |
ngOnInit() | ページやコンポートネントが最初に完全に読み込んだら実行されるものと理解しています。イメージではJavaScriptのonDOMcontentLOaded()です。その後、 ディレクティブ/コンポーネントを初期化します。ページ読み込みの際に1度だけ呼び出されます。 最初 の nOnChanges() の後に 一度 呼び出されます |
ngOnChanges() | Angular がデータバインドされた入力プロパティを(再)設定するときに応答します。 このメソッドは、現在および以前のプロパティ値の SimpleChanges オブジェクトを受け取ります。ngOnInit() の前に呼び出され、データバインドされた入力プロパティが変更されるたびに呼び出されます。 |
ngOnDestroy() | Angularがディレクティブ/コンポーネントを破棄する直前に、クリーンアップします。 メモリリークを回避するためにObservableの購読を解除し、イベントハンドラをデタッチしましょう。 Angularがディレクティブ/コンポーネントを破棄する 直前 に呼び出されます。 |
Angular場合、ライフサイクルはコンポーネントの生成や破棄がトリガーになります。そのため、最初の1回しかイベントを実行したくないときなどに利用します。
なお、constructorとngInitを同じように考えがちですが、前者はライフイベントではありませんので、コンポーネントが表示されるまで待ってくれません。そのため、constructorを実行したのになにも反映されないということがあります。constructorではページ操作を行うような動作は入れない方が良いです。
次にIonicのライフイベントです。
イベントフック(これを関数のように書いて呼び出します) | 概要 |
ionViewWillEnter() | ページが表示されるアニメーションが始まるとき |
ionViewDidEnter() | ページが表示されるアニメーションが終了したとき |
ionViewWilLeave() | ページから離脱・遷移するアニメーションが始まるとき |
ionViewDidLeave() | 離脱するアニメーションが終了したとき |
Willのタイミングでデータの描画を行うのはよくないです。Will を使用する場合はデータの取得などの準備、Didを使用するのはデータを表示するなどのタイミングがよさそうです。
Angularの場合、先に述べたようにコンポーネントがトリガーとなっているのに対して、lonicのライフライクルトリガーはユーザーにとっての表示です。なのでページ遷移して戻ってきたときにも発生するなどでUIの改善などの観点では非常に使いやすくなっています。
Ionicの場合、ライフサイクルイベントを関数のように追記するだけですが、Angularのライフサイクルイベントは先に型を定義する必要があります。
IonicをAngularで使って、写真から文字情報を抽出して爆速でレポートや記事を作成するアプリを作成しています。無料なのでよかったらどうぞ。
iOS => https://apps.apple.com/app/id1497498494
Android => https://play.google.com/store/apps/details?id=com.rainbowsv2.ocr
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
・
・
constructor(
private client:HttpClient
) { }
・
・
devTestObservable(myStr):Observable<any> {
return new Observable(observer => {
setTimeout(() => {
observer.next(myStr+'myObservable');
}, 1000);
})
}
devTestPromise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('myPromise');
}, 1000)
})
}
devTestHttp():Observable<any> {
return new Observable(observer => {
this.client.get('/assets/data/test.json').subscribe(e =>{
observer.next(e);
})
})
}
import { DataService } from '../tabs/data.service';
import { HttpClient } from '@angular/common/http';
・
・
constructor(
private dataService:DataService,
private client:HttpClient,
) {
this.myStr = 'first ';
}
・
・
async onButtonClick(){
this.dataService.devTestHttp().subscribe(e =>{
console.log(e,'Hi');
this.myStr = e.authAdmin.linkLoginButton+'Hi';
})
this.dataService.devTestObservable().subscribe(e =>{
console.log(e);
})
this.dataService.devTestPromise().then(e =>{
console.log(e);
})
}
<ion-item lines=’full’><ion-label position=’floating’>らべる</ion-label><ion-input type=’text’></ion-input></ion-item>
inputには、最初にplaceholderが表示されていて、フォーカスをあてるとplaceholderのラベルが左上に移動するものが一番いいです。
こんな感じになります。
フォーカス前
フォーカス後
横いっぱいに広がったよく見るボタンが表示されます。クリック時の関数は(click)=で指定します。
<div><ion-button expand=’block’ (click)=”someFunc()”>Button</ion-button></div>
ionic g
とだけ入力すれば、下記の選択肢を表示してくれます。
以前はなにかサービスを作ろうと思うと、サーバを立てて運用するというのが常識でした。物理的なサーバを購入して自社や自宅に置くことはもちろんですが、そうでなくてもVPSで借りて運用するなどは常識だったと思います。WebならPHPでのバックエンドになりますし、アプリの開発ならRestAPIなどを設計したでしょうか。いずれにせよ、サーバを借りてプログラムを書くという点は常識でした。
しかしサーバの運用は大変なものです。プログラムを設置し、アクセスを適切に受けるようにして、セキュリティも考慮しなければなりません。OSの設定も大変ですし、物理的なサーバなら電源の冗長化や放熱なども考慮する必要があります。わたしも昨年、会社でDellのWindows Serverを購入しましたが、初期投資は150万円かかりましたし、場所を確保したり専用クーラを設置したり導入までに3ヶ月程度はかかりました。
こうした負担を軽減する方法はないのか?と考えた時にクラウドがあります。
クラウドはGoogleやAmazon、Microsoftなどがネット上に構築したサービス群で、OSをVPNのように提供する低レベルなものから(IaaS)、サービスだけを提供するSaaSレベルのものもあります。そして必要なものを選んで利用するほうが、自前でサーバを運用するより圧倒的に楽です。
従来と比べて大きく違うのは、まず初期コストはゼロというです。そして、サーバを運用し続ける負担がほぼなくなります。インフラの部分の担当を任せられるのですから非常にらくになります。これにより爆発的な導入がなさされておりますが、「セキュリティ」を理由に導入していないところも多くあると思いますが、官公庁ではAWSを使ったり、NetFlixのような非常に大規模サイトでも使用されています。
その他、個人的に感じるクラウドの強みは、開発者が納得いくまで何度でもやり直せる点です。先ほど述べたように、わたしは昨年DellのWindows Serverを購入しましたが、「とりあえず動くようにプログラム設置できたら、あとは怖いから放置」ということになってしまっています。実際、一念発起しても杞憂に終わらなかったですし。。一方、クラウドはサービスなので何度でも自分が納得するまで設定をして消去ということを繰り返すことができます。テスト環境を作って、なっとくするまで設定する、そしてうまくいったものだけで本番環境で再現できるとなれば、取り合えず動くようになったら放置というオンプレミス環境と比べて大きくプログラムへの理解が深まります。
サーバレスを実現するクラウドサービスはいろいろありますが、特に利用されるのがFirebaseです。現在はGoogle(Alphabet)の傘下ですが、スタートアップだったものをGoogleが買収したものです。
スマホアプリ開発におけるバックエンドを担うことがおおいようですが、JavaScript,JAVA,Swift,Objective-C、Swift、C++、Unity、Python、PHP、Goなどほとんどの環境からアクセスできます。
機能はこちらです
ユーザー認証 | 非常にいやらしい認証周りを簡素化するFirebaseの代表的なサービスです。IDとパスワードで実現するものに加えて、GoogleやTwitter、 Facebookなどのアカウントを利用したユーザー認証や匿名認証も可能です。 |
データベース | 「キー=バリュー型」の非SQLデータベース(Json形式)です。SQLの使えるRDBは連携しているGCPで利用できるのでFIrebaseにはNoSQLが搭載されています。ソケット通信で接続しておいて、変更があったらフロント側のデータを自動で更新してくれるので非常に便利です |
ストレージ | ファイルの保管機能。普通に画像などをストレージできます |
ホスティング | Webサイトをデプロイし、公開します |
クラウドファンクション | ネットワーク経由で特定の処理を呼び出し、実行します。Pythonで書くこともできます。このURLを叩いたらPythonプログラムを実行して解析した結果を返すといったことができます |
機械学習キット | 言語翻訳、写真からのテキスト認識、顔認証などです |
Google Analytics | Google Analyticsによるアクセス解析です |
メッセージング | スマホアプリへのプッシュ通信を実現します。Niftyなどでもできるようですが、FIrebaseがメジャーかと。。 |
実際はGCPと連携して使う場合もあり一概にはいえないですが、使い始めてすぐお金がかかるようにはなっていません。2種類の料金プランが用意されていて、まずは一ひとつめのSparkプラン(無料枠)から始めるようになっているためです。Sparkプランだけでもデータの保存に1GB/月、読み込みに10GB/月が設定され、認証は1 万/月可能なのでかなりでかいです。料枠を超えると利用量に応じた料金が自動的にかかる仕組みです。
公式によると下記の料金体系となっています。
プロダクト | 無料Spark プランGenerous limits to get started | 従量制Blaze プラン大規模なアプリの料金を計算checkSpark プランの無料使用量を含む* |
---|---|---|
A/B テスト | 無料 | |
Analytics | 無料 | |
App Distribution | 無料 | |
App Indexing | 無料 | |
認証電話認証 – 米国、カナダ、インド help電話認証 – 他のすべての国 help他の認証サービス | 1 万/月1 万/月check | $0.01/認証$0.06/認証check |
Cloud Firestore保存データ下りネットワークドキュメントの書き込みドキュメントの読み取りドキュメントの削除 | 合計 1 GiB10 GiB/月2 万/日5 万/日2 万/日 | $0.18/GiBGoogle Cloud pricing$0.18/10 万$0.06/10 万$0.02/10 万 |
Cloud Functionshelp呼び出しGB 秒CPU 秒アウトバウンド ネットワーキング | 12.5 万/月4 万/月4 万/月Google サービス専用 | $0.40/百万$0.0025/千$0.01/千$0.12/GB |
Cloud Messaging(FCM) | 無料 | |
Crashlytics | 無料 | |
Dynamic Links | 無料 | |
HostingGB 保存済みGB 転送済みカスタム ドメインと SSLプロジェクトごとに複数のサイト | 1 GB10 GB/月checkcheck | $0.026/GB$0.15/GBcheckcheck |
アプリ内メッセージング | 無料 | |
ML Kithelpデバイス用 APIカスタムモデルのホスティング / サービス提供AutoML Vision Edge データセットAutoML Vision Edge トレーニング Cloud Vision API | checkcheck画像 1,000 件/プロジェクト3 時間/プロジェクト close | checkcheckGoogle Cloud pricing15 時間/請求先アカウント、 $4.95/時間$1.50/1,000 (Cloud Vision の料金を参照) |
パフォーマンス監視 | 無料 | |
Predictions | 無料 | |
Realtime Database同時接続 helpGB 保存済みGB ダウンロード済みプロジェクトごとに複数のデータベース | 1001 GB10 GB/月close | 20 万/データベース$5/GB$1/GBcheck |
Remote Config | 無料 | |
ストレージhelpGB 保存済みGB ダウンロード済みオペレーションをアップロードダウンロード オペレーションプロジェクトごとに複数のバケット | 5 GB1 GB/日2 万/日5 万/日close | $0.026/GB$0.12/GB$0.05/1 万$0.004/1 万check |
Test Labhelp仮想デバイスでのテスト物理デバイスでのテスト | 10 件/日5 件/日 | $1/デバイス/時間$5/デバイス/時間 |
Google Cloud PlatformBigQuery およびその他の IaaS を使用 help | close | check |
プランを選択Looking for the Flame plan? | 無料Spark プランすぐに開始可能 | 従量制Blaze プランプランを選択 |
写真から文字情報を抽出して爆速でレポートや記事を作成するアプリを作成しています。無料なのでよかったらどうぞ。フロントエンドはAngularで開発し、バックエンドはGCPとFirebaseを使っています。
iOS => https://apps.apple.com/app/id1497498494
Android => https://play.google.com/store/apps/details?id=com.rainbowsv2.ocr
Twitterやってます.
メールで連絡いただければ迅速に対応いたします