CoreML
iOS 11推出的新framework - CoreML, ML即Machine Learning.
官方给出的架构如下图:
如图可见, 该框的几个实现包括Vision, 还有NLP.
NLP (Natural Language Processing)
常有功能:
- Language Identification
- Named Entity Recognition
架构:
这么一来, 封装后使用变得简单.
iOS 11推出的新framework - CoreML, ML即Machine Learning.
官方给出的架构如下图:
如图可见, 该框的几个实现包括Vision, 还有NLP.
常有功能:
架构:
这么一来, 封装后使用变得简单.
还在Kotei的时候, 跟着一个Tuts+教程, 花了4天熟悉Vim.
从此入了Vim阵营, 感叹它在啥环境下都有.
那时也留下了学习emacs的念想.
这么多年过去, 是时候付诸实践啦~
会持续在此更新相关笔记.
C
代表Ctrl
键
M
代表Meta
键(Alt
键)
终止emacs会话C-x C-c
退出正在键入的命令C-g
下一屏C-v
, 上一屏M-v
光标所在字符的 居中/居上/居下C-l
前一行C-p
(Previous line)
退一格C-b
(Backward)
进一格C-f
(Forward)
下一行C-n
(Next line)
进一词M-f
(Forward)
退一词M-b
(Backward)
行头C-a
行尾C-e
句头M-a
句尾M-e
篇头M-<
篇尾M->
<>
键都处于上键位置, 所以输入时是需要按住Shift
键.
位移命令可接受数字参数, 使用C-u
录入数字, 然后会被重复作用到后续的位移命令上.
按住M
输入数字也等同于此操作.
例如C-u 8 C-f
会前进8个字符.
Luo Yu
Friday, September 8, 2017
官网注册一下bluemix的账号, 如果之前注册过IBM的账号的话, 可以直接拿来登录并激活该功能.
(有部分Script似乎在墙外, 最好翻一下操作).
首次登入, 会被告知试用天数, 和简单的收费介绍, 大概就是超出免费使用额的时候进行收费.
然后呢, 会有一个指引, 来创建"组织名称">"空间名称". 这里也会选择服务器物理位置. 自动给我匹配了一个“悉尼”, 看似最近的也只有这个了.
选一个服务吧. 各类应用容器...(这样算, 一个服务一份钱?).
因为要部署的是Hubot, 一个NodeJS做的程序, 所以这里就直接选个CloudFoundry的Node.js应用类型就行啦.
同样, 创建好名称, 比如我这里就叫“nodejshubot”.
创建完后, 系统会自动为你启动该服务.
bluemix环境已有, 接下来就是获取hubot并部署到该服务中.
那这个环境是一个CloudFoundry环境, 就需要它的交互工具.
在macOS中, 还是老一套, 用Homebrew来安装吧:
brew install cloudfoundry/tap/cf-cli
使用cf
命令测试了一下,
$ cf
cf version 6.30.0+decf883fc.2017-09-01, Cloud Foundry command line tool
Usage: cf [global options] command [arguments...] [command options]
挺正常的.
然后还需要git和node环境, 如果你还没有的话.
下载安装过Xcode的, 都会由Command Line Tools附带安装了git.
node环境, 也是可以直接brew install
的.
$ git clone git@github.com:hubotio/hubot.git
Cloning into 'hubot'...
remote: Counting objects: 8746, done.
remote: Total 8746 (delta 0), reused 0 (delta 0), pack-reused 8746
Receiving objects: 100% (8746/8746), 1.91 MiB | 117.00 KiB/s, done.
Resolving deltas: 100% (4926/4926), done.
官方解释到:
如果要部署到 Bluemix,设置 manifest.yml 文件会很有用。manifest.yml 包含有关应用程序的基本信息,例如名称、要为每个实例分配的内存量以及路径。
那我们就在这个项目里创建一个manifest.yml文件, name呢就是我们的应用程序名称.
---
applications:
- name: nodejshubot
command: ./bin/hubot --adapter slack
instances: 1
memory: 256M
到了用Cloud Foundry CLI的地方啦.
cf api <API-endpoint>
API-endpoint呢 则是前面选好的区域, 比如我选的悉尼.
API 端点 | 区域 |
---|---|
https://api.ng.bluemix.net | 美国南部 |
https://api.eu-gb.bluemix.net | 英国 |
https://api.au-syd.bluemix.net | 悉尼 |
实际使用:
$ cf api https://api.au-syd.bluemix.net
Setting api endpoint to https://api.au-syd.bluemix.net...
OK
api endpoint: https://api.au-syd.bluemix.net
api version: 2.75.0
Not logged in. Use 'cf login' to log in.
那么就是OK的了, 都提示好让我直接login:
$ cf login
API endpoint: https://api.au-syd.bluemix.net
Email> blodely@gmail.com
Password>
Authenticating...
OK
Targeted org blodelyAtSyd
Targeted space dev
API endpoint: https://api.au-syd.bluemix.net (API version: 2.75.0)
User: blodely@gmail.com
Org: blodelyAtSyd
Space: dev
这就可以从程序目录push应用程序到bluemix了(感觉这个架构很重):
$ cf push
Using manifest file /Users/blodely/Desktop/bluemixhubot/hubot/manifest.yml
Updating app nodejshubot in org blodelyAtSyd / space dev as blodely@gmail.com...
OK
Uploading nodejshubot...
Uploading app files from: /Users/blodely/Desktop/bluemixhubot/hubot
Uploading 85K, 64 files
Done uploading
OK
Stopping app nodejshubot in org blodelyAtSyd / space dev as blodely@gmail.com...
OK
Starting app nodejshubot in org blodelyAtSyd / space dev as blodely@gmail.com...
Downloading liberty-for-java_v3_11-20170710-0312...
# 省略省略大段的远端环境自动下载配置的信息...
Staging complete
Uploading droplet, build artifacts cache...
Uploading build artifacts cache...
Uploading droplet...
Uploaded build artifacts cache (1.2M)
Uploaded droplet (18.8M)
Uploading complete
Destroying container
Successfully destroyed container
0 of 1 instances running, 1 starting
1 of 1 instances running
App started
OK
App nodejshubot was started using this command `npm start`
Showing health and status for app nodejshubot in org blodelyAtSyd / space dev as blodely@gmail.com...
OK
requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: nodejshubot.au-syd.mybluemix.net
last uploaded: Sat Sep 2 04:10:43 UTC 2017
stack: cflinuxfs2
buildpack: SDK for Node.js(TM) (ibm-node.js-6.11.1, buildpack-v3.13-20170725-1347)
state since cpu memory disk details
#0 running 2017-09-02 12:12:13 PM 0.2% 48.7M of 256M 75.4M of 1G
这就push成功,应用也启动了.
状态也列举出来在最后面, manifest中写到的一样, 指派了256M内存的使用(???).
骆昱, September 2, 2017
indie.luo@gmail.com
不用多介绍了,Kitura差不多是一岁了. 来自IBM的Swift框架(on server-side).
自Swift开源以来,大家都在进行各个平台的尝试.
相关较成熟的解决方案有Perfect框架, Kitura则相对来说较为轻量级.
现在的优势是该Swift框架在IBM的Bluemix上已有应用服务了,当然Swift容器也有的.
照例使用Swift Package Manager创建:
swift package init --type executable
修改Package.swift,添加Kitura框架的依赖:
import PackageDescription
let package = Package(
name: "myFirstProject",
dependencies: [
.Package(url: "https://github.com/IBM-Swift/Kitura.git", majorVersion: 1, minor: 7)
])
Build一下:
swift build
首次Build就会看到一个个依赖包被克隆下来啦.
修改Main.swift文件,添加服务入口:
import Kitura
// Create a new router
let router = Router()
// Handle HTTP GET requests to /
router.get("/") {
request, response, next in
response.send("Hello, World!")
next()
}
// Add an HTTP server and connect it to the router
Kitura.addHTTPServer(onPort: 8080, with: router)
// Start the Kitura runloop (this call never returns)
Kitura.run()
然后就可以跑起程序试试了:
swift build
.build/debug/myFirstProject
这里有个比较坑的地方, 追根溯源, 还是来自Apple的. 目前Swift给出的包都是为了Ubuntu环境准备的, 有14.04LTS, 有16.04LTS的. 其他环境得自己编译.
这里呢, 我偷懒点, 使用最爱的docker来部署.
ibmcom/swift-ubuntu
是一个Swift Ready的Ubuntu14环境,可以直接拿来用.
骆昱/Luo Yu, indie.luo@gmai.com
Saturday, September 2, 2017
假定项目/公司既有代码规范, coder遵从or不遵从规范都是显而易见的.
故不评审代码样式/风格/规范.
找寻的目标, 应该是潜在bug和有性能问题的代码.
代码层面的基础问题:
代码组织设计上的问题:
其他的控件:
为不同尺寸的设备配置UI控件:
基本上,这也是个场景(Scene).
使用自定义的布局, 包含一些基础的UI元素, 例如一个“Start开始”按钮.
一张背景图(TextureFrame).
和一个使用custom font自定义字体的Label, 显示copyright信息.
现今操作系统的字体通常都是矢量图形, 适合不同尺寸的展示, 格式通常为TTF(TrueType)或OTF(OpenType).
渲染此类字体成位图资源是一个复杂的过程. 通常由CPU完成. 而游戏引擎使用GPU渲染, 3D相关APIs并不能高效支持此类渲染, 所以需要在之前将字体转换成一个更友好的格式.
基本上呢, 和使用Unity类似, 有指定字体大小情况下的bitmap生成图, 再交由引擎使用, 是一个好方法.
劣势也是一样的: 字体尺寸问题、中文字符集问题等.
Godot里的动画. Godot的动画系统是极其强大而灵活的.
增加AnimationPlayer节点(node).
选中时, 会出现Animation Editor面板.
(颈椎背痛,休息了四天...)
Godot里, 引擎绝大多数的行为与功能都是有nodes实现而来, 与Nodes一样非常重要的另一种数据类型是resource.
Nodes关注与behaviors(行为), 例如绘制一个sprite, 绘制3D模型, 物理引擎, GUI控件等等.
Resources则纯粹是数据容器(data containers). 意思是它们不会有任何action也不会处理任何信息.
Resources只包含数据.
如: Texture, Script, Mesh, Animation, Sample, AudioStream, Font, Translation等等.
当Godot从磁盘存储或载入一个scene(.scn/.xml), 一张图片(.png/.jpg), 一段脚本(.gd)或几乎任何东西, 被操作的那个文件就是一个resource.
当资源(resource)从磁盘载入, 它将只会被载入一次. 这意味着,资源会被载入到内存(memory). 尝试再次载入只会返回该资源.
通常而言, Godot里的每个对象(Node, Resource or anything else)都能输出属性.
属性可以是很多类型, 如string, integer, Vector2等, 有些类型可以是个resource.
这意味着nodes和resources都可以包含resources型的属性. 如图:
资源属性可以以两种方式关联资源: external(on disk)或是built-in.
代码的两种载入方式:
# 1
func _ready():
var res = load("res://robi.png") # resource is loaded when line is executed
get_node("sprite").set_texture(res)
# 2
func _ready():
var res = preload("res://robi.png") # resource is loaded at compile time
get_node("sprite").set_texture(res)
自打去年在搜索引擎上看到这个开源的游戏引擎来,足足一年时间过去了,却没有真正开始学习/尝试使用这个引擎.
今起,可以利用业余时间开始一步步学习这个引擎,目前看来,作为移动平台小游戏的基础,它应该是满足条件的.
MIT的许可证,也比较适合我们来使用.
将会在博客每天持续更新学习记录.
内容会是以官方文档为基础的学习, 暂不会参考其他网上教程(其实好像也还没有). 时间尽量定在1~2周.
第一天,就来了解一些关于Godot引擎的基础好了.
基本上,介绍页解释的是Godot里元素的基础是node
, 暂且翻译为“节点”. 一个节点(node)有名称、有可编辑的属性、能接受回调、能被扩展、能被挂到其他节点下作为子节点.
也强调了子节点的组织方式, 称非常重要, 以这种方式组织时,这些nodes形成了tree(树)
. (感觉...非常...寻常的方式...- -!)
另外,就是Scene(场景). 起特征是:
一个Scene有且只有一个根节点(root node)、Scene可以被保存到磁盘也能被载入、可以被实例化、运行一款游戏意味着运行一个Scene、一个工程里可有多个Scene.
(基本上和其他引擎定义一致)
Godot editor其实就是个Scene editor.
+
新增node(Create New Node), Node|CanvasItem|LabelInspector
中编辑label的内容, 比如“hello, world”main scene
, 运行即可看到效果基本原理
Godot里,Scene的特征上面已描述过:
对于一个正在编辑的Scene来说,其他Scene的示例也可以加到其下:
上面图里展示的是Scene B以一个instance加到Scene A中.
官方的demo示例中,在Scene面板中点按“链接形状”按钮选择一个Scene创建instance.
Design language
When making games with Godot,
the recommended approach is to leave aside other design patterns
such as MVC or Entity-Relationship diagrams
and start thinking about games in a more natural way.
Start by imagining the visible elements in a game,
the ones that can be named not just by a programmer but by anyone.
举例一个简单的射击游戏的思路:
记下想到的元素, 并用箭头表示其ownership.
使用的脚本语言称作GDScript. 其设计时有两个目标:
任意情况下, 若有性能需求, 可以用C++编写核心块然后交给脚本调用.
右击node, add script
, 意味着extend该node, 故会自动填上Inherit
该node.
默认脚本里, 会有一个_ready()
函数. 它会在该node(和它所有的children)进入活动scene时被调用. Constructor函数是_init()
.
# 获取元素
Node.get_node()
# 默认树结构 是 从该脚本控制的node的直接子node开始
# 例如Panel->Label->Button的结构的话, 就是get_node("Label/Button")
# 连接signal信号与响应
Object.connect()
# get_node("Button").connect("pressed",self,"_on_button_pressed")
有些情况下, 需要脚本处理每一帧. 有两类processing: idle processing
和fixed processing
.
Idle processing由Node.set_process()函数激活. 一旦其激活, Node._process()回调将会被每一帧调用. 示例:
func _ready():
set_process(true)
func _process(delta):
# do something...
# delta参数描述了时间间隔, 单位秒, float类型, 间隔自上一次调用_process().
Nodes可以被添加到groups(想加多少加多少).
Node
面板下的Groups
按钮.add_to_group("enemies")
在此情况下, SceneTree.call_group()可通知一个group下的所有node.
# if the player is discovered sneaking into the secret base
# all enemies can be notified about the alarm sounding
# by using SceneTree.call_group()
func _on_discovered():
get_tree().call_group(0, "guards", "player_was_discovered")
当然, 也可通过group获取其所有nodes的列表: SceneTree.get_nodes_in_group()
var guards = get_tree().get_nodes_in_group("guards")
Godot系统包含一个通知系统.
添加Object._notification()
函数即可使用:
func _notification(what):
if (what == NOTIFICATION_READY):
print("this is the same as overriding _ready()...")
elif (what == NOTIFICATION_PROCESS):
var delta = get_process_time()
print("this is the same as overriding _process()...")
func _enter_tree():
# When the node enters the _Scene Tree_, it becomes active
# and this function is called. Children nodes have not entered
# the active scene yet. In general, it's better to use _ready()
# for most cases.
pass
func _ready():
# This function is called after _enter_tree, but it ensures
# that all children nodes have also entered the _Scene Tree_,
# and became active.
pass
func _exit_tree():
# When the node exits the _Scene Tree_, this function is called.
# Children nodes have all exited the _Scene Tree_ at this point
# and all became inactive.
pass
func _process(delta):
# When set_process() is enabled, this function is called every frame.
pass
func _fixed_process(delta):
# When set_fixed_process() is enabled, this is called every physics
# frame.
pass
func _paused():
# Called when game is paused. After this call, the node will not receive
# any more process callbacks.
pass
func _unpaused():
# Called when game is unpaused.
pass
代码创建node. 调用.new()
方法. 例如:
# 代码创建node. 调用`.new()`方法
var s
func _ready():
s = Sprite.new() # create a new sprite
add_child(s) # add it as a child of this node
# 删除node
func _someaction():
s.free() # immediately removes the node from the scene and frees it
# 释放一个node, 它的子nodes也会跟着被释放.
删除一个正处于“blocked”状态的node将会导致crashing, 因为它正在发出信号(emitting a signal)/调用方法(calling a function).
最为安全的删除node的办法是Node.queue_free(). 它将在idle状态下删除安全的删除node.
代码里instancing一个scene分两步:
var scene = load("res://myscene.scn")
, 或是var scene = preload("res://myscene.scn")
PackedScene.instance()
.var node = scene.instance()
add_child(node)
二步初始化的优势是, packed的scene可以一直被保持着, 用来快速初始化多个instances. 例如创建多个enemies, bullets等等.
需注意的是,最新的Jenkins需要Java8的环境。
直接brew安装:
yul@MAC-LUOYU > brew install jenkins
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 1 tap (caskroom/cask).
No changes to formulae.
==> Using the sandbox
==> Downloading http://mirrors.jenkins-ci.org/war/2.70/jenkins.war
==> Downloading from http://mirrors.tuna.tsinghua.edu.cn/jenkins/war/2.70/jenkins.war
######################################################################## 100.0%
==> jar xvf jenkins.war
==> Caveats
Note: When using launchctl the port will be 8080.
To have launchd start jenkins now and restart at login:
brew services start jenkins
Or, if you don't want/need a background service you can just run:
jenkins
==> Summary
? /usr/local/Cellar/jenkins/2.70: 7 files, 72.2MB, built in 1 minute 48 seconds
快速又便捷,并给出使用的提示,
如果想启动Jenkins并且让它重启登录时自启动,使用命令:
brew services start jenkins
或如果你不想让它作为后台服务运行,可以直接使用命令:
jenkins
按照上面的提示开启Homebrew服务,并设置Jenkins随系统启动的服务:
yul@MAC-LUOYU > brew services start jenkins
==> Tapping homebrew/services
Cloning into '/usr/local/Homebrew/Library/Taps/homebrew/homebrew-services'...
remote: Counting objects: 12, done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 12 (delta 0), reused 7 (delta 0), pack-reused 0
Unpacking objects: 100% (12/12), done.
Tapped 0 formulae (40 files, 53.8KB)
==> Successfully started `jenkins` (label: homebrew.mxcl.jenkins)
Jenkins启动后,默认端口号是8080,
可以直接访问例如本机http://localhost:8080
会显示首次登录的Unlock Jenkins页面
这里会要求一个初始的管理员密码验证,并告知了该密码在服务器上的位置,
所以可以:
cat ~/.jenkins/secrets/initialAdminPassword
安装的过程也很简介,有推荐的插件可以直接开启Jenkins,也可以手选自己需要的插件。
等待各个插件的安装完成..
最后会提示创建一个admin管理员账号:
*.swift
文件
在Xcode弹出提示时,选择创建一个Objective-C Bridging Header
文件
如果未选择创建,可以手动创建该头文件,并在Build Settings
里增加配置Objective-C Bridging Header -> $(SRCROOT)/projectname-Bridging-Header.h
实现Swift类
类使用@objc
注解
Build Settings的参数检查
#import "projectname-Swift.h"
Friday, July 7, 2017