Fengxiaoping's bubble

  • (30 gadget day 4) 那边有把吉他,所以 - MYO (2)

    2月 23rd, 2015

    今天我终于把MYO搞好了。之前无论如何都Update不动,搜了下发现可以用“直连线”强制升级。Anyway,让我们开始想想这玩意儿能玩啥吧!

    又到了这个点儿,家里又只剩下YubiKey等超弱智设备陪着我。就只能打打擦边球了,用手机来充当Gadget吧…

    看了一圈MYO的market,发现基本之前想的一些场景都有人实现了。比如用手势来操作chrome,操作鼠标,地图,游戏,甚至trello。

    好,吧,惆怅了,写个啥呢…

    有把吉他

    图片描述

    抬望眼,看到有把吉他在远处蓬头垢面的看着我。再看我…再看我就拿你开Live!

    嗯,万事具备,只差我不会弹,and没有粉丝了…

    好,吧,那写个粉丝呗。请想象一下…“爷弹了个和弦,观众就掌声雷动!” O.O >..<||

    图片描述

  • 校园API化

    2月 23rd, 2015

    图片描述

    以前应人邀请写的个东西,结果人家说看不懂哈,那就发在这里啦。

    在我心目中,理想的校园应该是个大实验室,学生和老师在其中学习了解各种知识,实践尝试各种创新的想法。而在这个人人都在喊“大数据,物联网”的时代里,校园更应该是最活跃的实验场。

    当我们讨论iWatch,iBeacon,Oculus这类新型的可穿戴,物联网技术的时候,可能都隐约意识到其中所蕴含的变化的内涵,在这些人与环境,人与人,人与自身感官之间交互方式的转变背后,其实是人类社会自身数字化的过程。在这里我只想就这种数字化的构想做一些想象,设想一些在校园内可能的数字化实验的场景。

    API的力量

    API是应用程序接口(Application Programming Interface)的简称,一般用来指代系统的不同模块之间通信的约定。Wiki中解释API设计的目的:“程序设计的实践中,编程接口的设计首先要使软件系统的职责得到合理划分。良好的接口设计可以降低系统各部分的相互依赖,提高组成单元的内聚性,降低组成单元间的耦合程度,从而提高系统的维护性和扩展性。”。由于现代系统的复杂度非常高,人们不得不将系统划分为大量基本模块,这就使得合理的模块间通信设计变的十分重要。

    对于工程师来说,提到API,多数会想到那些可以弹出个对话框,把一些字符串拼到一起这类软件开发工具(SDK)。但对于许多新公司而言,API代表的是更高级,更抽象的服务,而这些或多或少的已经成为了公司核心的一部分。

    如果我们现在创业做一款产品,所需要的大部分技术工作都可以寻找到对应的API。底层的如提供服务器托管的阿里云,直接服务应用开发者的的LeanCloud;应用层的如用语用户反馈的Uservoice,可以完成大量复杂数据分析的Mixpanel;再到直接提供机器学习算法服务的algorithms.io,专门提供图像内容识别服务的Rekognition。可以说,开发者需要的基本工具,都能以很低廉的价格,以服务的方式获取到。而这些服务,就是新一代的API。

    新一代的API不局限具有更广的“光谱”:小至算法(algorithms.io),大至企业帐目核算(Mint.com),银行资金托管(bancbox.com)。这些服务现在都在或多或少的以一种“可编程”的形式出现。这就使得原来需要人力去“粘合”才能保证企业运转的工作,比如员工招聘,会计,行政的工作,都可以被程序更高效的替代。

    我相信,能够善用这些新API(也就是擅长Mashup),将是未来工程师的重要技能。所以,我模仿了国外的一个博客系列,Learning 30 technologies in 30 days,也开始了自己的30天30项技术的30hackdays系列,可以在segmentfault的博客看到。

    未来的人工智能是网状的。前面提到了algorithms.io这样的产品,可以给那些完全没有机器学习算法经验的团队提供复杂的算法服务。而近些年,类似的产品(服务)也出现暴增的趋势,如出门问问,Tuling123,虫洞助手这样的智能助手产品等。这意味着,原来被视为大公司才能拥有的人工智能服务正在被一个个细小的产品分食。这些微型智能服务从许多小需求点切入,并且尽量大程度的开放API给其他开发者。一方面提高了自己产品的生存能力,另一方面也为以后形成微型智能服务之上的中型智能服务奠定了基础。

    假设某个开发者想实现一个检测橱窗里海报被关注度的产品,他完全可以购买一款可以通过API访问当前视频流的摄像头放在海报版前面,将数据流分别导入一个提供OpenCV的服务和一个如Amazon EMR的大数据存储平台中,在获得当前板子前的同学的轮廓以及朝向后,将这个数据分留给如chartbeat这样的实时数据分析平台,以及提供用户行为预测服务的Framed Data类平台。最后将得到的分析结果输出给Mixpanel这样的数据可视化平台。这样就借助许多第三方服务完成了一个看起来每个点都需要很大工作量的系统。

    释放巨龙的力量

    算法已经被充分互联网化,甚至服务化。但现实世界在这方面就落后的多。物联网算是离人们最近的数字化技术,但人们目前可以接触到普及了的相关技术也就是NFC和短期内可能兴起的iBeacon技术。机器人算是填补这个沟壑的重要手段。通过大量的传感器和具有实际干预能力的机械装置,机器人可以实现充分释放“淤积”在互联网中算法的巨大力量。

    除了最近火到黑的Jibo家庭机器人,比较低技术含量的家用机器人也已经崭露头角。如添加了各种传感器的联网扫地机器人,微型飞行器,联网的空气质量监测器,这些设备的根本目的都是将人们周围的环境量化,将数据传入云中,利用算法的力量来尝试解决实际问题。为什么叫尝试解决呢?第一,这里的问题可能在拿到一定数量的数据之前都是未知的,只有到了“大数据”的量级,问题才会浮出水面。第二,除了那些明显通过改进算法可以解决的确定性问题之外,发现那些原来并不存在因果关系的,只是概率上存在关联的问题会成为算法的重要责任。这也就是为什么在中型规模的智能服务没有兴起前,所谓的智能家居也只是“App上的开关”的原因。

    校园,变革的前线

    生活在校园中,我们肯定经常遇到到某些不便,去自习室看书却不知道哪间教室人少;去操场打球却要花很长时间招呼朋友;去图书馆借书却又找不到XY书架在哪。这些问题的本质都是信息的不对称。过去人们通过发明电话,地图等方式来辅助人们减少这种不对称。而大数据时代的做法则是,API化一切,利用算法的力量解决物理世界的问题。

    正如前面提到的,API化包含两方面含义:对物理世界的数据化,以及数据的物理化。前者指的就是通过各种各样的传感器,将物理世界的各种表相转换为可以被算法处理的数据信息,比如各种监控摄像头所存储的校园内的影像信息。后者指的是将以上数据处理以后的结果转换为实际的物理行为,比如荷兰设计师设计的可以跟随人的椅子,Take a seat。

    在学校中,我们可以做些什么API化的尝试呢?

    安全。相比社会,学校一般还是更安全的地方,但一旦出现事故在社会上的影响也是更严重。所以如果学校能够将学生的位置,比较实时的获取到,在保证学生隐私的前提下,检测每个学生的安全程度。一旦发生事件,学生可以很容易的报告学校保安部门,也许就可以及时阻止可能的危险行为。这在技术上并没有难度,每个学生几乎都有智能设备。通过在室内增加一些诸如iBeacon的设备也可以更精准的定位学生的位置。但正如前面所说,学生对于隐私的疑虑也许会高于对自身安全的担心。

    社交。基于如上的安全产品,学校的学生位置就已经被API化了。除了Dota,撸啊撸以外,学生关心的应该就是社交了。做校园社交的产品很多,但由于各家都不会开放自己的数据,所以在使用不同产品的时候都需要重复填写很多信息。这个问题对于职场人来说没有多大问题,因为大家都在几个大的社交平台活动,如linkedin,facebook等。但学生会具有更多细化的筛选需求,比如某个院系专业的,正在选修某些课程的。课程格子在这方面做了很多有趣的尝试。

    开放。学校应该建设自己的数据开放平台,为学生提供实现上述类型想法的最基础设施。比如在教学楼内部署温度湿度红外传感器,并将这些数据同步到网络中供大家访问。这个时代的开放校园,除了开放的课程以外,学校的公开信息,甚至一草一木的数据都应该被开放出来供大家访问。

    双刃

    另一方面,美剧《Person of interests》讲了一个大数据的另一面,一个令人很恐慌的黑暗面。政府建造了一个监控所有数据的机器,由此发展出了智能,反过头来干预现实人们的生活。就目前的技术发展来看,很有可能片中的情况已经发生,只是我们被机器“照顾”的很“正常”,并没有意识到另一个“大意识”的存在。

    算法的力量已经开始渗入普通人的现实世界。《互联网思维与我们的未来》一书中的海妖服务器即将成为未来的游戏规则。尽量接近“核心算法”,找到自己的位置,至关重要。

  • (30 gadget day 3) 绝对的小个子-littlebits cloudbit

    2月 22nd, 2015

    做技术启蒙教育的可能都听说过littlebits,一堆小小的工作单元,通过磁力轻松的连接起来,就可以实现一些简单的电路逻辑。比如,把电源-按键-LED串在一起,就能实现一个“按键让灯亮”的小电路,也不用担心电路接错了会烧坏元件啥的。

    图片描述

    逗我玩么…

    当然,爷会只玩这么白痴的东西么…如果有孩子了的话还是有可能的…转个推

    @Tomy 偶然发现一个程序猿的各种 SNS 帐号都在2012年之后停止了更新,博客、微博、Twitter、V2EX 都没有了音讯,就连 Github 2013年后都没再提交代码了!!怀着恐慌的心情 Google 了下 ID,发现了他在2014年海淘了几袋奶粉的晒单……心情的跌宕起伏,是为记

    好吧,我承认这是混字数。你走开!我之所以买了一套littlebits呢,就是看中了新推出的cloudbits——一个可以联网控制的元件。

    图片描述
    图片描述

    Cloudbit

    玩IFTTT的同学应该都注意到有一些菜谱里面出现了这个小笑脸,这玩意儿就是cloudbits。

    图片描述

    简单的说,Cloudbits就是一个可以联网控制的littlebits组件,而就是这么简单的设计,给littlebits带来了无限的可能性。littlebits官网首页的展示视频里有一个小情景:猫猫按了一下littlebits的按钮,主人手机就蹦出来一个“feed me”,主人点一下feed,猫粮就掉下来了,这个情景的实现就完全倚赖cloudbits的推出。

    Cloudbit get started

    setup的过程如下:

    1. 登陆Cloudbit控制后台
    2. 按指示连接到Cloudbit的wifi
    3. 帮助Cloudbit登陆本地wifi
    4. 切换回本地wifi,等待cloudbit的灯从绿色闪烁变为绿色持续(这个过程我搞了好几次,可以试试拔掉Cloudbit再插上,TroubleShotting里也有一些有用的东西)

    p.s.
    悲剧的是我发现我这个单元的reset按键坏了,基本可以判断总是按接通状态。于是…就总是处于reset,reset的循环中…最后就只能把那reset键给拆了…

    图片描述

    反正最终的结果就是这样

    图片描述

    这个大按钮的作用呢,就是让这个Cloudbit想外发送数据(其实就是提供电压,还可以调节输出电压的数值,当然是从0到100这样的方式)。

    Develop with Cloudbit

    具体的玩法就不说啦,里面核心的就是如何将Cloudbit的输入输出与网络服务结合起来。先看API文档吧,没想到API已经到v2版本了。

    Auth

    littleBits的API支持标准的OAuth2,DeviceID和Token从后台就能看到。用这两个值就可以完成认证。

    图片描述

    Endpoints

    [code lang=text]
    —Responds—
    OAuth HTTP
    path Scope Code Payload ◆ Make LB Cloud…
    —- —– —- ——— —————-
    /devices
    GET read 200 [<devices>] return a list of the user’s devices

    /{device_id}
    GET read 200 <device> return device model
    PUT admin 200 <device> update device model
    POST admin 201 <device> activate device, is then associated to the user
    DELETE admin 200 <device> deactivate device, is then associated to no body

    /output
    POST write 200 output some voltage on the given device

    /subscriptions
    GET read 200 [<subs>] return device's subscriptions
    POST read 201 publish given device events to given endpoint
    DELETE read 200 stop publishing given device events to a given endpoint
    [/code]

    赞这个“文档”,极简又足够清楚。先拿一下这设备的信息。

    curl -i -XGET -H "Authorization: Bearer e352c8d9f7a9103c59xxxxxxxcdb6c5b28fbd6c2c438936xxx" -H "Accept: application/vnd.littlebits.v2+json" https://api-http.littlebitscloud.cc/devices/00exxxxxxx39
    

    response

    {"label":"office","id":"00exxxxxxx39","user_id":35515,"is_connected":true,"ap":{"ssid":"senz_xiaomi","mac":"8C:BE:BE:28:15:6B","strength":"100","server_id":"7yY9Dniw","socket_id":"7JeMsZ2w"},"subscriptions":[],"subscribers":[],"input_interval_ms":750}
    

    看起来没啥用呢…再回来看Doc,output的部分看起来容易用哈。

    curl -i -XPOST -H "Authorization: Bearer e352c8xxxxxxfbd6c2c438936e0b97cebb8b7" -H "Accept: application/vnd.littlebits.v2+json" https://api-http.littlebitscloud.cc/devices/00exxxx39/output -d percent=50 -d duration_ms=1000
    

    结果呢,就是灯亮了1秒钟!宏大吧!>.<

  • (30 gadget day 2) 最简单也最复杂的Gadget - YubiKey

    2月 21st, 2015

    晚上翻出myo准备继续写的时候,被提示需要升级,于是就update呗。于是…就update了一个小时,现在还在转…

    图片描述

    其他设备都在办公室,于是智能在家里翻箱倒柜…先是翻出了Chromecast,拿在手里很开心的开始看Cast文档。看了一会迫不及待的拿出来试。于是…

    图片描述

    找了一圈基本确认Cast决定今天不见我以后,继续寻觅下一个下手的目标。于是找到了这只TI的“智能手表”。好吧,谁还认识它?

    图片描述
    图片描述

    这次我谨慎审视了下,自然的决定了放弃。因为很显然我基本12个小时内找不到它的专用充电器…好~吧~于是最后翻到了它:YubiKey。

    图片描述

    YubiKey呢,是个99.999%的人都不会有兴趣的Gadget,而且剩下的0.001%里顶多按过两三次以后就扔那了(><)

    一次一密(OTP)

    一次一密是一种简单粗暴有效的加密方式。基本的概念就是,每次加密用的钥匙都来个新的,跟上次用的没啥关系的。这样基本只能用遍历破解。

    YubiKey OTP

    YubiKey的使用很简单,插在电脑上,它就会亮。按一下那个唯一的按键,它就会往你光标在的位置“吐”一串密码。当然要登录的服务器得支持YubiKey的认证方式(所以基本没几个服务可以用,但是有LastPass)。

    图片描述

    YubiKey的OTP实现如下。顶上紫色的是最终产生的一个字符串。其中前面一部分是用户ID,用来对应用户的公钥。后面部分是一个由counter何session key组合产生的密码。由于每次按键都会使得内部的counter自增,所以同一个密码是不能被拿来验证两次的。另外,由于这玩意儿里面的firmware是写死的,所以也基本不用担心算法被篡改的问题。

    otp_details.png

    YubiCloud

    刚才说到服务器要支持YubiKey的认证方式,YubiCloud就是Yubico给出的解决方案。流程很简单如下图。

    图片描述

    只要在验证的步骤中增加一步跟YubiCloud交互的过程就ok了。一般这种应用会要求三个凭证来作为用户身份验证:用户名,密码,YubiKey产生的OTP。先验证密码的好处是,可以不至于每次输错密码都要重新产生一个OTP。

    YubiCloud提供了几个写好的Server-YubiCloud的SDK,同时也给出了兼容这个协议的独立认证服务器实现参考,还有个第三方的go写的哟。

    U2F

    前段时间Gmail宣布支持U2F,因为有软件的Authenticator,硬件版本的U2F对于大部分二次验证用户来说…没啥用…但…对于在笔记本上使用二次验证的用户来说,买一个他家出的U2F SECURITY KEY,可能还是可以应对“手机没电”,“清空了Authenticator数据”,“手机丢了”等情况的。况且,日子还要过,逼还要装,怎能跟那些厮一样,打开个App看密码…

    好吧,我承认今天的blog过于水了…就请看在之前找题材痛苦的份儿上…

    晚安~

  • (30 gadget day 1) MYO get started

    2月 20th, 2015

    MYO

    MYO是一款类似Leap motion的新型人机交互HCI设备。它被戴在人的前臂,从而可以感知人的肌肉电流,进而识别出人的各种手势动作,比如向左向右挥手。

    图片描述

    官方给出的MYO的几个用途是

    • 做展示。挥挥手就能换页,或者将Prezi的控制变成它应有的样子。
    • 控制手机。比如跑步的时候挥挥手就能切换歌曲,玩1024之类的。
    • 智能家居。打个响指就能让电视开机之类的。
    • 控制那些会跑的。现在支持了Sphero和Parrot Drone。

    另一个我觉得很酷的例子是Armin Van Buuren在一次演出里使用MYO来辅助增强现场表演效果。特别有未来实时大规模交互演出的感觉。那些具体的表演视频就大家自己去搜吧。

    avb-myo-home.jpg

    我买了两个MYO腕带,下面三天我们就来想想能用它来玩点什么~(那上面的标志是在亮的,真的挺酷)

    图片描述

    MYO的结构

    myo-overview.png

    整个MYO中间靠近皮肤的部分都布满了各种金属触点,所以戴起来的时候完全不在乎什么角度。充电用的是标准的Micro USB。

    图片描述

    开发者视角

    跟Leap motion类似,MYO提供两类输入数据:空间数据(Spatial data),手势数据(Gestural data)和唯一一种反馈接口,震动(vibration command)。

    空间数据包括两个维度:方向(orientation),三维的加速度向量(acceleration vector)。
    手势数据包括几种特定的手势,比如握拳等。

    iOS sample

    当然,MYO提供了基本所有平台的SDK(当然Windows phone除外)。开发起来最方便的还是Mac啦,windows要装一堆驱动啥的。如果只是开发应用的话,基本之用跟Android/iOS的SDK打交道就好啦。如果需要底层数据,MYO也提供C lib API。另外,还有一种用Lua写的Myo Scripts。

    sdk-stack.png

    跟各种Sensor的使用类似,MYO的数据是以回调传递事件的方式来提供。MYO提供三类事件,如前面所说所空间事件,手势事件,以及一些辅助类的事件(如连接,断开设备等)。

    开发MYO应用的最好方式就是先运行sample程序。iOS的SDK里面包括一个Doc和叫HelloMyo的Sample程序。打开Sample,运行,玩玩就好了。(MYO SDK开发速度很快,所以如果发现Sample程序告知版本太低,则需要连上USB和蓝牙发射器进行一次升级)。

    看看代码吧。

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        // Data notifications are received through NSNotificationCenter.
        // Posted whenever a TLMMyo connects
        [[NSNotificationCenter defaultCenter] addObserver:self
                                              selector:@selector(didConnectDevice:)
                                              name:TLMHubDidConnectDeviceNotification
                                              object:nil];
        // Posted whenever a TLMMyo disconnects.
        [[NSNotificationCenter defaultCenter] addObserver:self
                                              selector:@selector(didDisconnectDevice:)
                                              name:TLMHubDidDisconnectDeviceNotification
                                              object:nil];
    ...
        // Posted when a new pose is available from a TLMMyo.
        [[NSNotificationCenter defaultCenter] addObserver:self
                                              selector:@selector(didReceivePoseChange:)
                                              name:TLMMyoDidReceivePoseChangedNotification
                                              object:nil];
    
    }
    

    首先是注册各种事件,包括连接断开连接,这里有个Sync Gesture,指的是一种比较奇怪的动作(不大好描述)。应该是MYO用来给手臂肌肉电流做一个基本的base line吧。

    最有用的可能就是TLMMyoDidReceivePoseChangedNotification了。一旦有新的姿势检测到,这个函数就能收到一次callback。来看这个Callback的内容。

    - (void)didReceivePoseChange:(NSNotification *)notification {
        // Retrieve the pose from the NSNotification's userInfo with the kTLMKeyPose key.
        TLMPose *pose = notification.userInfo[kTLMKeyPose];
        self.currentPose = pose;
    
        // Handle the cases of the TLMPoseType enumeration, and change the color of helloLabel based on the pose we receive.
        switch (pose.type) {
            case TLMPoseTypeUnknown:
            case TLMPoseTypeRest:
            case TLMPoseTypeDoubleTap:
                // Changes helloLabel's font to Helvetica Neue when the user is in a rest or unknown pose.
                self.helloLabel.text = @"Hello Myo";
                self.helloLabel.font = [UIFont fontWithName:@"Helvetica Neue" size:50];
                self.helloLabel.textColor = [UIColor blackColor];
                break;
            case TLMPoseTypeFist:
                // Changes helloLabel's font to Noteworthy when the user is in a fist pose.
                self.helloLabel.text = @"Fist";
                self.helloLabel.font = [UIFont fontWithName:@"Noteworthy" size:50];
                self.helloLabel.textColor = [UIColor greenColor];
                break;
            case TLMPoseTypeWaveIn:
                // Changes helloLabel's font to Courier New when the user is in a wave in pose.
                self.helloLabel.text = @"Wave In";
                self.helloLabel.font = [UIFont fontWithName:@"Courier New" size:50];
                self.helloLabel.textColor = [UIColor greenColor];
                break;
            case TLMPoseTypeWaveOut:
                // Changes helloLabel's font to Snell Roundhand when the user is in a wave out pose.
                self.helloLabel.text = @"Wave Out";
                self.helloLabel.font = [UIFont fontWithName:@"Snell Roundhand" size:50];
                self.helloLabel.textColor = [UIColor greenColor];
                break;
            case TLMPoseTypeFingersSpread:
                // Changes helloLabel's font to Chalkduster when the user is in a fingers spread pose.
                self.helloLabel.text = @"Fingers Spread";
                self.helloLabel.font = [UIFont fontWithName:@"Chalkduster" size:50];
                self.helloLabel.textColor = [UIColor greenColor];
                break;
        }
    
        // Unlock the Myo whenever we receive a pose
        if (pose.type == TLMPoseTypeUnknown || pose.type == TLMPoseTypeRest) {
            // Causes the Myo to lock after a short period.
            [pose.myo unlockWithType:TLMUnlockTypeTimed];
        } else {
            // Keeps the Myo unlocked until specified.
            // This is required to keep Myo unlocked while holding a pose, but if a pose is not being held, use
            // TLMUnlockTypeTimed to restart the timer.
            [pose.myo unlockWithType:TLMUnlockTypeHold];
            // Indicates that a user action has been performed.
            [pose.myo indicateUserAction];
        }
    }
    

    内置的手势有这些:

    TLMPoseTypeDoubleTap(拇指和中指连续点击两次)
    TLMPoseTypeFist(握拳)
    TLMPoseTypeWaveIn(向内挥手,戴在右手就是往左挥手)
    TLMPoseTypeWaveOut(向外挥手)
    TLMPoseTypeFingersSpread(按理来说是类似cross finger的意思,但似乎我没咋触发过这个pose)

    基本就这么点儿代码。明天我们尝试把这个跟其他功能联系起来哈。

  • (30 hackdays ) 30个gadget day

    2月 20th, 2015

    Gadget days

    30hackday帮助我验证了快速学习的可能性和方法。下面这30hackday我想集中在硬件Gadget的开发上,看能不能积累出一套适用于Gadget App开发的经验。

    2015年2月20日开始,每天我会写一篇比较正式的博客文章(文章质量参考原作者,第二天早上2点前发出算数),内容都是关于这些硬件Gadget的应用开发。

    非常希望借此机会认识对Gadget开发感兴趣的伙伴们。所以,如果在文章里发现了任何错误,请帮忙指出,我都很乐意请你喝咖啡(限北京…)~ contact: fxp007@gmail.com

    开发设备如下,过程中可能略有变化,排名不分先后。MYO,Kinect for windows 2,SmartScopes,Estimote iBeacon,LittleBits,Tobii eyeX,Sphero,Philips hue,Mindstorm,ARDrone

    进度

    • (30 gadget day 1) MYO get started

    图片描述

  • Httpsify – 国内视频https托管方法

    12月 8th, 2014

    问题

    一些浏览器会禁止http内容展现在https页面中。比如我们在squarespace里插入一个Youku的视频(Youku嵌入的视频不支持https),就会无法播放

    解决方案

    我们需要找一个免费的支持https的serve视频的地方。第一个选择就是七牛云,搞了半天发现qiniu的ssl证书是invalid的…
    于是又想起了“可怜的”LeanCloud。下载云代码,把要托管的文件放到public下,avoscloud deploy avoscloud publish就好啦,在setting里设置一下web主机的二级域名。就能直接访问了。

    squarespace

    squarespace比较特别的是它要求embed video,比如youtube之类的用iframe的玩意儿。但国内的那些视频网站基本都不支持https的iframe。好吧,这个也用LeanCloud解决吧。那就写个HTML来解决它。这个HTML要能处理各种Video的请求的话就得读到url里的query。

    <div id="content"></div>
    
      function getParameterByName(name) {
        name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
        var regex = new RegExp("[\\?&amp;]" + name + "=([^&amp;#]*)"),
          results = regex.exec(location.search);
        return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
      }
      var videoUrl = getParameterByName('video');
      if (typeof videoUrl != 'undefined') {
        var node = document.createElement("video");
        node.width = window.innerWidth;
        node.height = window.innerHeight;
        node.autoplay = true
        var controlAttr = document.createAttribute('controls');
        var srcAttr = document.createAttribute('src');
        srcAttr.value = videoUrl;
        node.setAttributeNode(srcAttr);
        node.setAttributeNode(controlAttr);
        document.getElementById('content').appendChild(node);
      }
    

    没做任何优化,只处理了video这种query,大概意思就是这样。

  • CNUtils

    11月 29th, 2014

    因为众所周知的原因,很多网站因为用了font.googleapis.com而变的打开很慢很慢很慢。其实也就是那么一个文件打开慢而已。360出了个CDN造福了一大堆程序员。

    于是我想,如果能做个小js库,让这些网站通过它来选择性加载不同源的数据该多好~于是就做了个cnutils

    代码很简单,一个demo而已,里面用到了ip-api.com的api来判断ip国籍。欢迎友人有兴趣能做下去哈。

    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open("GET", 'http://ip-api.com/json', false);
    xmlHttp.send(null);
    var result = JSON.parse(xmlHttp.responseText)
    var fontSrc = (('China' === result.country) ?
            'http://fonts.useso.com' :
            'https://fonts.googleapis.com') +
        '/css?family=Open+Sans:300italic,400italic,600italic,400,300,600|Merriweather:700'
    var linkElement = document.createElement('link');
    linkElement.rel = 'stylesheet';
    linkElement.href = fontSrc;
    console.log(fontSrc)
    document.head.appendChild(linkElement);
    
  • (30 hackdays day 30) StrongLoop – Javascript全栈框架

    11月 8th, 2014

    SL_Logo_Stacked_RGB.png

    StrongLoop是一个基于Nodejs的强大框架,几乎包含了移动开发全栈所需要的所有功能。2013年成立,很少的员工,一个技术驱动,执行力强大的团队。也是在13年我开始接触StrongLoop,当时是为了做nodejs方面的技术选型,看了许多框架,LoopBack是我觉得最酷的一个。我还记得当时是觉得LoopBack的文档太差(主要是跟在线的版本不一样),不知道能活多久所以才放弃了它。时隔一年回来看到这个绿油油的框架,这一年可真是突飞猛进呢。

    LoopBackarch7162014-3.png.pagespeed.ce.tUGpVTVgYP.png

    全栈框架StrongLoop

    StrongLoop基本提供了制作一个移动产品所有的框架和工具,从标准的Backend server,Devops,应用监控,。要想介绍完全StrongLoop的所有产品得写一个长篇连载了,这里只简单的浏览一遍。

    • LoopBack
      一个功能很强大的WebServer框架,隐约看到Spring的影子…

      • SDK
        这是当时我觉得StrongLoop最好用的一点:根据后端Model自动生成对应的前端SDK。
      • RESTful API
        MEAN stack推动了所有新框架默认支持RESTful API,比如Nodejs里的Node-restify,Sailjs之类的天生就是为了serve API的。StrongLoop还提供了一个用来设计API的工具(beta状态),当然跟RAML比还是差不少的。
      • Data model
        很容易创建数据模型,自动产生对应的RESTful API。
      • Connectors
        当然可以对接各种数据库。
    • StrongLoop Controller
      Debug, Package Management, Build, Deploy, Cluster, Log等等一堆Devops工具。
    • Application Monitor
      一堆监控服务器的模块。
    • mBaaS
      使用StrongLoop,你也可以创建自己的LeanCloud啦,包括Push,地理位置计算(Geopoint),Social Login,User management,各种Replication,Offline sync(离线同步是个好东西),对接各种Stroage云(AWS,Rackspace之类内置了的)。当然,其实这些都是LoopBack里提供的功能,意思是用StrongLoop得永生。

    开始

    安装StrongLoop sudo npm install -g strongloop
    创建一个应用 slc loopback(找个空白的目录哦) 它只会问你项目叫啥。
    创建一个Model slc loopback:model (是不是想起了Yo generator~),然后它就会问一堆乱七八糟的问题了。

    图片描述

    plural指的是RESTful API的route名,一个Model对应的route默认情况下会被plural(复数化),比如Post的路径是Posts。

    猜一下,像LeanCloud里类似,这时候应该去访问一个类似127.0.0.1:3000/xxx的地方看到他的后台吧~嗯 xxx=explorer http://127.0.0.1:3000/explorer 就能看到一个用Swagger做的API dashboard。

    图片描述

    看一下项目的结构,像Meteor一样,LoopBack将JS代码分成服务端(server),前端(client),以及共用部分(common,个人认为这种纯schema的方法比Meteor分割的更清晰)。

    略过后面的API Explorer,如何连Database,直接看如何在前端使用刚刚创建出来的API。LoopBack的做法是帮助你创建你当前API的各端SDK,目前只支持Android/iOS/Angularjs。如果你用别的Web框架可能就只能自力更生了。

    创建自己的SDK lb-ng server/server.js client/lb-services.js 看看client/lb-services.js,不错吧~

    嗯,你的前端工程师需要个文档?执行 lb-ng-doc client/lb-services.js 有时候需要在前面添加sudo(不知道为啥),然后访问 http://localhost:3030/ 就能看到文档啦~这个功能是基于Docular做的。另外,如果你点LoopBack Services进去没东西,别担心,刷新一下。

    看看是不是很像早期Angular的文档~

    图片描述

    API Designer

    相信很多程序员喜欢Parsejs或者LeanCloud的原因都是那个图形化界面的Model设计(或者叫API设计)后台。如果前面用的那个”Yo generator”的API creator看起来还不够贴心,你可以试试StrongLoop新推出的StrongLoop Studio beta。

    • 在工程根目录下sudo npm install -g http://get-studio.strongloop.com/strong-studio.tgz 安装Studio。
    • 启动Studio strong-studio,自动打开浏览器
    • 去StrongLoop官网右上角注册个账号(文档里居然写了On the bottom right is a link to go to the registration page on strongloop.com,你们不知道页面很容易改版么…)
    • 用注册的用户名登录进去看到API Composer和Profiler。
    • Bingo!各种玩耍吧!

    图片描述

    p.s.如果这时候你遇到了类似SyntaxError: Cannot parse package.json: Unexpected token e这样的问题,检查一下你工程根下的package.json里是不是被jslint搞乱了(I dont’t know why…)
    好吧好吧,我告诉你这个beta还真是特别beta…尽量不要在之前写过代码的项目里用…

    懒人们

    如果你缺个可以玩耍的Mongodb:Mongolab
    如果你想要个可以协作开发的IDE:Koding
    如果你想要个便宜好用的VPS:Digital Ocean
    如果你觉得他们家不够便宜:Serverbear
    如果你连VPS都不想要,只想部署个Node项目:Nodejitsu
    如果你想设计个API尽快给客户端同学,又不想搭Node,找地方部署:Apiary
    如果你想做(抄)个APP,又不想花钱雇一堆人:Appdupe

    30天结束

    这是最后一篇30hackdays啦,终于熬出来了(吁…)。Anyway,这三十天我学到了很多,如何寻找自己想要的服务,如何快速实现原型,如何比较开发者产品的竞品…

    回头看,文章的内容肯定没有Shekhar的那篇Learning 30 Technologies in 30 Days: A Developer Challenge写的详尽(确实也没人家投入那么多时间精力),但我选择的技术更广泛(或者叫更乱七八糟),对我也是一种扩展视野的过程。

    希望我的这个系列能给大家一些启发。技术并不都是那么深奥难懂,拥抱它也许不能立刻涨工资,但至少在寒冷的日子里,没有wifi,孤独寂寞冷的时候,还可以打开浏览器的console,输入个while,来暖暖手。

    下面

    嗯,不是你想的那个,也不是用来吃的。之后我会继续时不时写一些发现的好玩的开发者服务;另外,我会写一个StrongLoop的系列文章来介绍这个框架更多的特性,希望大家能够尝试这个迅猛发展的产品。

    再做个小广告:最近在做一个小班(免费),专门教高中生技术,直到达成可以自行参加Hackathon的程度。如果身边有高中生对技术感兴趣,欢迎联系我~ fxp007@gmail.com

    ok,那些输了的情自行来约~

    ec0a6159252dd42af84c70ce003b5bb5c9eab82a.jpg

  • (30 hackdays day 29) Google TTL – 让Google讲小说

    11月 7th, 2014

    最近一直在喜马拉雅听有声小说《轮转长生》。每天会更新两集。但由于我记忆力差,所以如果等着每天的小说更新,就会由于记不住之前的情节而感觉很迷茫。所以我去搜了下,发现了这个小说的文本。于是就想如果能用Text To Speech把文字变成语音的话,不就能一直听下去,而不用等播音了嘛。

    于是我就去搜各种TTS API Chinese。发现了iSpeech, tts-api,voicerss之类的服务。确实,TTS技术发展了这么多年,肯定有巨多的服务提供商。但翻了一圈发现中文的效果都很差。郁闷的时候想起Google Translate的TTS,就是那个整天被人当B-Box玩的东西。

    图片描述

    Google-TTS

    这是一个非官方的Google TTS库,但是文档里说到Playbackwill only work when running the script locally as Google's server only returns audio if you can prevent the browser from sending the Referrer HTTP Header to their server,看来是Google对referrer做了检查。不过这点后面看起来似乎没那么严格。

    我们先用个简单的页面测试一下播音(注意科学上网),播放一小段中文听起来还不错。

        var tts = new GoogleTTS('zh-CN');
        tts.play('你好呀呀呀呀', 'zh-CN', function (err) {
            console.log('complete');
        });
    

    拿小说

    这就用到了之前介绍的技术Import.io。安装桌面应用,Create API from URL 2.0,找一个详情页,比如第一百五十三章 照片上的三口之家,选择文章内容的div改column名为text。就可以create啦。
    看一下文章的url是连续的,好,那就用node写个循环,然后用AVOS把文章内容保存下来。

    // ...省略初始化
    var Chapter = AV.Object.extend('Chapter');
    
    _.each(_.map(_.range(27888, 27996), function (num) {
        return 'http://book.guidaye.com/daomu/85/' + num + '.html';
    }), function (url) {
        var q = new AV.Query(Chapter);
        q.equalTo('url', url);
        q.first()
            .then(function (chapter) {
                if (chapter) {
                    console.log('exists,%s',url);
                } else {
                    unirest.get('https://api.import.io/store/data/c2f29086-18a8-4c7b-9d5d-6ea1d54a9bc5/_query')
                        .query({
                            'input/webpage/url': url,
                            '_user': '[UER]',
                            '_apikey': '[API KEY]'
                        })
                        .end(function (response) {
                            new Chapter({
                                url: response.body.pageUrl,
                                text: response.body.results[0].text
                            }).save().then(function () {
                                    console.log('done,%s', response.body.pageUrl);
                                }, function (err) {
                                    console.log(err);
                                })
                        })
                }
            })
    
    })
    

    跑一遍基本就ok啦,如果有发生错误的就再执行一遍验证下。

    读小说

    好,我们要一个前端页面来读小说。

    <div id='playing'></div>
    
    
        AV.initialize("[APPID]", "[APPKEY]");
    
        function speakChapter(chapterNum) {
            var url = 'http://book.guidaye.com/daomu/85/' + chapterNum + '.html';
            var Chapter = AV.Object.extend('Chapter');
            var query = new AV.Query(Chapter);
            query.equalTo('url', url);
            query.first()
                    .then(function (chapter) {
                        document.getElementById('playing').text = "playing:" + url;
                        console.log('playing,%s', chapter.get('url'));
                        var tts = new GoogleTTS('zh-CN');
                        tts.play(chapter.get('text'), "zh-CN", function (err) {
                            console.log('complete,%s', chapter.url);
                        });
                    }, function (err) {
                        console.log(err);
                    })
        }
        //speakChapter(27889);
    

    我们在console里实验一下speakChapter(27889);,终于开始读啦!听起来感觉还好,但还是TTS的最大普遍问题:语气不对。每个人说的,旁白说的都是一个味道…另一个问题是,读文章的时候一段以后会需要几秒钟的加载时间去加载下一段。而这个gap很有可能是一句话的中间。这就让人听起来很诡异了…“雷英…(上个厕所)…雄笑了笑”…

    最后说一下浏览器问题。我发现safari打开这个页面就能正常播放,所以,也还算可忍~

    好啦,按这个思路我们可以把自己喜欢的小说播放出来~如果你想把声音保存成mp3的话,可以用node-google-text-to-speech来把数据pipe到文件里,再用pushbullet类的产品把数据同步到移动端去。

    29天啦,坐等吃串!

←上一页
1 2 3 4 … 9
下一页→

Blog at WordPress.com.

 

正在加载评论...