flexbox その2
flexboxを改めてやる。以下のサイトの記事を読んだ。
flexアイテムとflexコンテナ
flexコンテナは多数のflexアイテムを内包する。flexコンテナにしたい要素に display: flex;を設定する。
すると子要素は自動的にflexアイテムになる。
並べる方向
flex-direction: row; で横方向に並べる。 row-reverseなら右から左になる。columnで上から下。column-reverseで下から上。
まとめて設定
flex-flow: row nowrap;
右づめで表示したい。
justify-content: flex-end; でdirectionがrowなら右づめになる。flex-startなら左づめ、centerなら中央、space-betweenなら等間隔に間をあけて表示される。space-aroundなら端っこにも空間があいた等間隔。
横にならべておいてアイテムの高さはコンテナいっぱいにひろげたい。
横に並べている(row)のときの縦をクロス軸と呼ぶ。
align-items: stretch; を設定すれば良い。
縦方向は上詰めにしたい場合はalign-items: flex-start;。下詰めにしたいときはflex-end。縦方向に中央に配置したい場合はcenter。baselaineに沿わせるならbaseline。
横にならべておいて、複数行の行間を調整したい。
align-content: stretch; コンテナの高さに基づいて均等配置。flex-startなら上からつまる。flex-endなら下からつまる。centerは中央。上端から下端で等間隔ならspace-between。上端と下端で端っこにも空間があいた等間隔ならspace-around。
アイテムの並び順
アイテムに対して order: 2; 等と設定。
アイテムを指定して並べ方を指定
align-self
URLヘルパ
URLを作る。
$this->Url->build(['action' => 'home', $article->id])
で
/kagero3/articles/view/1
ができる。
エレメントとHTMLヘルパ等と組み合わせて次のようなものが作れた。
<?= $this->Html->tag( "a", $this->Element( "agora_card", [ "title" => $article->title, "body" => $article->body ] ) , ["href" => $this->Url->build(['action' => 'home', $article->id]) ] ) ?>
<a url="/kagero3/articles/view/1"><div style="width:200px; height:200px; background-color:white;"> <div> <p> タイトル </p> </div> <div> <p> 内容 </p> </div> </div></a>
ちょっと面白くなってきた。
HTMLヘルパー その2
以下を参考に色々さわっている。
qiita.com
CakePHP 1.3 - Htmlヘルパー
画像リンク
<?= $this->Html->image( 'cake.power.gif', ["alt" => "cake.power", "url" => [ "controller" => "Articles", "action" => "home", "1"] ] ); ?>
<a href="/kagero3/articles/home/1"><img src="/kagero3/img/cake.power.gif" alt="cake.power"/></a>
urlを指定しないと単純にimageタグができる。
<?= $this->Html->image( 'cake.power.gif', ["alt" => "cake.power"] ); ?>
<img src="/kagero3/img/cake.power.gif" alt="cake.power"/>
タグ
タグ自体を指定して生成することもできる。
<?= $this->Html->tag( 'div', 'hello', ['class' => 'classA'] ); ?>
<div class="classA">hello</div>
よって、タグの入れ子も表現できる。
<?= $this->Html->tag('div',$this->Html->tag( 'p','hello'),['class' => 'classA']); ?>
<div class="classA"><p>hello</p></div>
HTMLヘルパー
単純にリンク
<?= $this->Html->link("hello","http://rodhos.info/") ?>
は次のように変換される。
<a href="http://rodhos.info/">hello</a>
つまり、第1引数が表示する文字で、第2引数がURL。
第2引数は以下のように連想配列で指定することもできる。
<?= $this->Html->link(__('View'), ['action' => 'view', $article->id]) ?>
<a href="/kagero3/articles/view/1">View</a>
もう一つ例として
<?= $this->Html->link("hello",[ "controller" => "Articles", "action" => "home", "1"]) ?>
は次のように変換される。
<a href="/kagero3/articles/home/1">hello</a>
第3引数
第3引数を指定するとaタグに属性をつけられる。
<?= $this->Html->link( "hello", "http://rodhos.info/", ["class" => "button"]) ?>
は次のようになる。
<a href="http://rodhos.info/" class="button">hello</a>
テーブルのところ
CakePHPのbakeで作られたテーブル
<table cellpadding="0" cellspacing="0"> <thead> <tr> <th scope="col"><?= $this->Paginator->sort('id') ?></th> <th scope="col"><?= $this->Paginator->sort('title') ?></th> <th scope="col"><?= $this->Paginator->sort('category_id') ?></th> <th scope="col"><?= $this->Paginator->sort('avatar_id') ?></th> <th scope="col"><?= $this->Paginator->sort('created') ?></th> <th scope="col"><?= $this->Paginator->sort('modified') ?></th> <th scope="col" class="actions"><?= __('Actions') ?></th> </tr> </thead> <tbody> <?php foreach ($articles as $article): ?> <tr> <td><?= $this->Number->format($article->id) ?></td> <td><?= h($article->title) ?></td> <td><?= $article->has('category') ? $this->Html->link($article->category->name, ['controller' => 'Categories', 'action' => 'view', $article->category->id]) : '' ?></td> <td><?= $article->has('avatar') ? $this->Html->link($article->avatar->name, ['controller' => 'Avatars', 'action' => 'view', $article->avatar->id]) : '' ?></td> <td><?= h($article->created) ?></td> <td><?= h($article->modified) ?></td> <td class="actions"> <?= $this->Html->link(__('View'), ['action' => 'view', $article->id]) ?> <?= $this->Html->link(__('Edit'), ['action' => 'edit', $article->id]) ?> <?= $this->Form->postLink(__('Delete'), ['action' => 'delete', $article->id], ['confirm' => __('Are you sure you want to delete # {0}?', $article->id)]) ?> </td> </tr> <?php endforeach; ?> </tbody> </table>
Objective-C++でクラス
JSONを使った受け渡しを想定して書いてみた。非効率かも。
#import <Foundation/Foundation.h> @class Engine; typedef NSDictionary JSON; @protocol EngineProtocol <NSObject> - (void)engine:(nonnull Engine *)engine message:(nonnull JSON *)message; @end @interface Engine : NSObject + (nonnull instancetype)engine:(nonnull id <EngineProtocol>)delegate; - (void)tellMessage:(nonnull JSON *)message; @end #include <stdio.h> #include <iostream> class EngineCpp; class EngineCpp { public: EngineCpp(); ~EngineCpp(); void hello(); typedef std::shared_ptr<EngineCpp> Ptr; std::string message; std::string proc(std::string src); }; EngineCpp::EngineCpp() { std::cout << "EngineCpp new" << std::endl; } EngineCpp::~EngineCpp() { std::cout << "EngineCpp delete" << std::endl; } void EngineCpp::hello() { std::cout << "EngineCpp hello" << std::endl; } std::string EngineCpp::proc(std::string src) { return "{\"Hello\":" + src + "}"; } @interface NSJSONSerialization(String) + (NSString *)jsonString:(NSDictionary *)dic; + (NSDictionary *)jsonString_r:(std::string &)str; @end @implementation NSJSONSerialization(String) + (NSString *)jsonString:(NSDictionary *)dic { NSData *d = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil]; NSString *sd = [[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding]; return sd; } + (NSDictionary *)jsonString_r:(std::string &)str { NSData *data = [NSData dataWithBytes:str.c_str() length:str.length()]; NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; return dic; } @end @interface Engine() @property (nonatomic) id <EngineProtocol> delegate; @property (nonatomic, assign) EngineCpp::Ptr engineCpp; @end @implementation Engine { } - (void)dealloc { NSLog(@"Engine dealloc"); } + (instancetype)engine:(id<EngineProtocol>)delegate { Engine *engine = [Engine new]; engine.delegate = delegate; engine.engineCpp = std::make_shared<EngineCpp>(); return engine; } - (void)tellMessage:(JSON *)message { std::string str = [NSJSONSerialization jsonString:message].UTF8String; std::string result = self.engineCpp->proc(str); NSDictionary *dic = [NSJSONSerialization jsonString_r:result]; [self.delegate engine:self message:dic]; } @end
リーダー選出アルゴリズム
リーダー選出のアルゴリズム
後続(successor)がダウンしている場合、飛ばして次のプロセスにElectionメッセージを送信する。
このメッセージには自分のプロセス番号をつける。
後続者は次々と自分の後続者にElectionメッセージを自分のプロセス番号を追加してまわしていく。
一周してElectionメッセージがもどってきたら(メッセージに自分のプロセスIDが入っているかどうかで判断する)、メッセージのタイプをCoordinatorに変更、これを回覧する。
すべてのプロセス番号がそろっているのでCoordinatorが誰かがわかる。
結果、2周する。
EventManager
登録方法は2種類。
EventListenerInterfaceを実装してonで自身を登録するか、onでキーとともに無名関数を登録しておくか。
Eventを作ってdispatchすることも可能。
登録したものの削除はoffでできる。
使いすぎて密結合に注意。
一文字づつ区切る
NSStringEnumerationByComposedCharacterSequencesを用いる。
NSString *string= @"ハローワールド🗾"; NSMutableArray *list = [NSMutableArray array]; [string enumerateSubstringsInRange:NSMakeRange(0,string.length) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) { [list addObject:substring]; }]; for (NSString *sub in list) { NSLog(@"%@", sub); for (int i=0;i<sub.length;i++) { NSLog(@"%04x", [sub characterAtIndex:i]); } }
Unicode block
Basic Latin
UTF8では1バイトで表現される。
Basic Latin (Unicode block) - Wikipedia
Latin-1 Supplement
U+0080–U+00FF
Halfwidth and fullwidth forms
Halfwidth and fullwidth forms - Wikipedia
U+FF00–FFEF
- U+FF01–FF5EはASCIIの全角
- U+FF65–FFDCはカタカナ、ハングルの半角
Hello World 4回目
アプリ作る。cakephp 3.5
composer create-project --prefer-dist cakephp/app MyApp2017
中に入る
cd MyApp2017/
sqlite3のdb作成
sqlite3 MyApp2017.db
sqlite> .tables sqlite> .q
コンフィグでデータベースをsqlite3に。atomは好きなエディタで。
atom ./config/app.php
'Datasources' => [ 'default' => [ 'className' => 'Cake\Database\Connection', 'driver' => 'Cake\Database\Driver\Sqlite', 'persistent' => false, 'database' => 'MyApp2017.db', 'encoding' => 'utf8', 'timezone' => 'UTC', 'flags' => [], 'cacheMetadata' => true, 'log' => false,
ここでサーバを立ち上げて確認する。
./bin/cake server
http://localhost:8765/にアクセス。databaseにつながっていることを確認。
ここでDBのテーブルを考える。
ログインしたユーザが書き込める掲示板という発想。
ユーザーテーブルを作ってみる。
./bin/cake bake migration CreateUsers name:string description:text created modified
/config/Migrationsフォルダに20170911144034_CreateUsers.phpファイルができる。
public function change() { $table = $this->table('users'); $table->addColumn('name', 'string', [ 'default' => null, 'limit' => 255, 'null' => false, ]); $table->addColumn('description', 'text', [ 'default' => null, 'null' => false, ]); $table->addColumn('created', 'datetime', [ 'default' => null, 'null' => false, ]); $table->addColumn('modified', 'datetime', [ 'default' => null, 'null' => false, ]); $table->create(); }
実際に作るには
./bin/cake migrations migrate
確認する。
sqlite3 MyApp2017.db .tables .schema
たしかにusersができている。idというautoincrementな主キーは自動で追加されるようだ。
次にUsersのモデル(テーブルとエンティティ)を作る。
./bin/cake bake model Users
これで
src/Model/Table/UsersTable.php
src/Model/Entity/User.php
ができた。
class UsersTable extends Table { /** * Initialize method * * @param array $config The configuration for the Table. * @return void */ public function initialize(array $config) { parent::initialize($config); $this->setTable('users'); $this->setDisplayField('name'); $this->setPrimaryKey('id'); $this->addBehavior('Timestamp'); } /** * Default validation rules. * * @param \Cake\Validation\Validator $validator Validator instance. * @return \Cake\Validation\Validator */ public function validationDefault(Validator $validator) { $validator ->integer('id') ->allowEmpty('id', 'create'); $validator ->scalar('name') ->allowEmpty('name'); $validator ->scalar('description') ->allowEmpty('description'); return $validator; } }
class User extends Entity { /** * Fields that can be mass assigned using newEntity() or patchEntity(). * * Note that when '*' is set to true, this allows all unspecified fields to * be mass assigned. For security purposes, it is advised to set '*' to false * (or remove it), and explicitly make individual fields accessible as needed. * * @var array */ protected $_accessible = [ '*' => true, 'id' => false ]; }
調子に乗ってユーザーコントローラを作る。
./bin/cake bake controller Users
これで
/src/Controller/UsersController.php ができた。
<?php namespace App\Controller; use App\Controller\AppController; /** * Users Controller * * @property \App\Model\Table\UsersTable $Users * * @method \App\Model\Entity\User[] paginate($object = null, array $settings = []) */ class UsersController extends AppController { /** * Index method * * @return \Cake\Http\Response|void */ public function index() { $users = $this->paginate($this->Users); $this->set(compact('users')); $this->set('_serialize', ['users']); } /** * View method * * @param string|null $id User id. * @return \Cake\Http\Response|void * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ public function view($id = null) { $user = $this->Users->get($id, [ 'contain' => [] ]); $this->set('user', $user); $this->set('_serialize', ['user']); } /** * Add method * * @return \Cake\Http\Response|null Redirects on successful add, renders view otherwise. */ public function add() { $user = $this->Users->newEntity(); if ($this->request->is('post')) { $user = $this->Users->patchEntity($user, $this->request->getData()); if ($this->Users->save($user)) { $this->Flash->success(__('The user has been saved.')); return $this->redirect(['action' => 'index']); } $this->Flash->error(__('The user could not be saved. Please, try again.')); } $this->set(compact('user')); $this->set('_serialize', ['user']); } /** * Edit method * * @param string|null $id User id. * @return \Cake\Http\Response|null Redirects on successful edit, renders view otherwise. * @throws \Cake\Network\Exception\NotFoundException When record not found. */ public function edit($id = null) { $user = $this->Users->get($id, [ 'contain' => [] ]); if ($this->request->is(['patch', 'post', 'put'])) { $user = $this->Users->patchEntity($user, $this->request->getData()); if ($this->Users->save($user)) { $this->Flash->success(__('The user has been saved.')); return $this->redirect(['action' => 'index']); } $this->Flash->error(__('The user could not be saved. Please, try again.')); } $this->set(compact('user')); $this->set('_serialize', ['user']); } /** * Delete method * * @param string|null $id User id. * @return \Cake\Http\Response|null Redirects to index. * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. */ public function delete($id = null) { $this->request->allowMethod(['post', 'delete']); $user = $this->Users->get($id); if ($this->Users->delete($user)) { $this->Flash->success(__('The user has been deleted.')); } else { $this->Flash->error(__('The user could not be deleted. Please, try again.')); } return $this->redirect(['action' => 'index']); } }
最後にtemplateをbakeする。
./bin/cake bake template Users
src/Template/Users/index.ctp
src/Template/Users/view.ctp
src/Template/Users/add.ctp
src/Template/Users/edit.ctp
が生成された。
このあたりでもう一度サーバーを立ち上げみてみる。
http://localhost:8765/users にアクセスするとユーザー一覧が出てくる。
続く。