• “两数之和(Two Sum)”问题的 Python3 解答

    “两数之和(Two Sum)”问题的 Python3 解答

    题目描述

    给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。

    示例

    给定 nums = [2, 7, 11, 15], target = 9
    因为 nums[0] + nums[1] = 2 + 7 = 9
    所以返回 [0, 1]

    解题思路

    要求的结果是两个索引组成的 List:[aIndex, bIndex],这两个索引对应的值记为 a, b。

    遍历列表,假设列表中第1项的值 a 是结果 List 中的一个索引的值,那么用 target 减去 a 后得到的结果 b 就是就是要找的另一个索引的值,列表除掉 a 后的子列表里面,如果 b 存在,问题已解——答案是 a 的索引和 b 的索引组成的列表 [aIndex, bIndex]。

    如果不存在,将列表的第二项赋值给 a,继续寻找 b,直到找到为止。

    解答

    class Solution:
        def twoSum(self, nums, target):
            """
            :type nums: List[int]
            :type target: int
            :rtype: List[int]
            """
    
            i = 0
    
            for num in nums:
                nextNum = target - num
                j = i + 1
                if nextNum in nums[j:]:
                    return [i, nums[j:].index(nextNum) + i + 1]
                i += 1
    
    

    中文官网的题目地址:两数之和

  • “两数相加(Add Two Numbers)”问题的 Python3 解答

    “两数相加(Add Two Numbers)”问题的 Python3 解答

    题目描述

    给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。

    你可以假设除了数字 0 之外,这两个数字都不会以零开头

    示例

    输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
    输出:7 -> 0 -> 8
    原因:342 + 465 = 807

    测试用例

    [2,4,3]
    [5,6,4]
    
    [1]
    [9,9]
    
    [5]
    [5]
    
    [0]
    [7,3]
    
    [9,9]
    [9]
    

    解题思路

    遍历链表,按节点两两相加,有进位将进位加到下一个节点。

    解题思路很简单,此题被标记为中等难度,是因为:

    1. 数据结构是链表;
    2. 两个链表长度不一定相等,尤其是有进位情况下的处理需考虑。

    解答

    # Definition for singly-linked list.
    # class ListNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.next = None
    
    class Solution:
        def addTwoNumbers(self, l1, l2):
            """
            :type l1: ListNode
            :type l2: ListNode
            :rtype: ListNode
            """
            l3 = l1
    
            while l1 != None or l2 != None:
                sum = l1.val + l2.val
                l1.val = sum % 10
    
                if sum >= 10:
                    if l1.next != None:
                        l1.next.val = l1.next.val + 1
    
                        if l1.next.val >= 10 and l2.next == None:
                            l2.next = ListNode(0)
                    else:
                        l1.next = ListNode(1)
    
                else:
                    if l1.next == None and l2.next != None:
                        l1.next = ListNode(0)
    
                if l2.next == None:
                    break
    
                l1 = l1.next
                l2 = l2.next
    
            return l3
    

    算法分析

    上述算法通过一次遍历完成,没有用单独的变量存储 carry 值。两个链表同节点相加的结果最大为 9 + 9 + 1 = 19,所以结果链表中对应节点的值永远可以用(l1[index] + l2[index] + carry) % 10来得到。

    上述算法将进位 carry 计入到了下一位中。具体解题过程为

    1. 用新变量 l3 保留对 l1 的引用
    2. l1 和 l2 对应节点做加法
    3. 有进位且 l1 有下一节点的情况下,将进位加入到 l1 的下一个节点;l1 没有下一个节点就给 l1 添加一个值为 1 的节点;没有进位执行步骤4
    4. l1 没有下一个节点了,但是 l2 还有下一个节点,就给 l1 添加一个值为 0 的节点
    5. 3 或 4 步骤执行完毕,如果 l2 没值了,就跳出循环,返回 l3,原题得解;否则将 l1 和 l2 移动一个节点,执行步骤2

    中文官网的题目地址:两数相加

  • 读李娟的《冬牧场》——读书读生活

    读李娟的《冬牧场》——读书读生活

    原本是打算写写《围城》的,遗忘的太多了。回头看的时候顺便看了下别人的书评,有些感受确定在读书的时候同样有过,但现在感觉没那么强烈了。留着重读之后再看看能不能写点什么。

    去年读的书里面,《冬牧场》是最能重拾小时候读书乐趣的作品。

    小时候读书,杂志、期刊类的“书”比较多,《读者》、《青年文摘》等的,这些都是从哥哥姐姐那里得来的。记得初中每次开学总会带几本《读者》等杂志去读,以应付刚开学那几天无所事事的时光。特别记得小学时候,每个学期会发一些课外读物,大概有两三种不同类型的读物,每人仅一本,同桌两个人是不同类型的,大家交换着看,另外还有一些作文类的报纸。我们班还建立了“图书角” ,也就是在教室黑板旁边角落放了一张书桌,班主任鼓励大家把自己的书放到“图书角”,登记在册,供全班同学借阅。除此之外,我很少能读到其他的书。在图书资源相对匮乏的年代,到手的书总是如饥似渴地读。记得从同学手里借到一本《简爱》,喜爱至极,没日没夜读了两天,读完了。对书中人物的遭遇感同身受,身临其境般,这种读书的奇妙感觉至今犹在,回味无穷。在图书资源相对匮乏的年代,对读物也是不挑食的,饿极了什么都吃,《故事会》、《小说界》等一些可能不适合小学生读的期刊、杂志,也读过一些。严格来说,《读者》、《青年文摘》我可能也是在不该读的年龄段里开始读的,最不该读的可能还有一些五行八卦类的地摊书……见到什么读什么而已。

    高中时期的读书应该比较符合自己的年龄了,那正是韩寒、郭敬明、安妮宝贝等流行于校园的时候。这段时间的读书得益于我有了一部手机,每天晚上熄灯后,查房的老师们走了后,我就着火柴盒大小的手机屏幕读了三年。有段时间痴迷于《福尔摩斯探案集》,每天晚上读一篇,读完了全集,我记得电子书资源有几十 M 之多,后来在书店翻看才知道那些文字印成书,得有几十公分厚了。此外,那个时候读的最多的应该是安妮宝贝的作品,安妮是那时我最喜欢的一个作家,我喜欢她优美、精炼、清澈凛冽的文字,不过也都是就着火柴盒大小的手机屏幕读的。大学放暑假回家,在火车站旁边的新华书店买过一本《春宴》,那是买的安妮宝贝的第一本书,装帧也喜欢,文字也喜欢,慢慢读,度过了一个美好的暑假。郭敬明的《悲伤逆流成河》是高一入学前的那个暑假读的,那年中考,考场就设在后来读高中的那所学校。一好友从校园附近的书店买了《悲伤逆流成河》和《乱世佳人》,他读完后,我借来读。《乱世佳人》下册他没读完,我只借到上册。我有个哥哥酷爱读书,我们两个都上学的时候,没到暑假,我们一起玩,他就捧一本书,坐在河边看。我记得我们讨论过郭敬明的《幻城》和韩寒,我都不甚了了。直到看到《悲伤逆流成河》才知道郭敬明文笔的厉害!高中读他的《最小说》,班里有几个他的书迷,其中有个漂亮的女同学每月都会买《最小说》,我们就轮流借着读。此外还读了他公司旗下许多作家的作品,记得有落落、安东尼等,那也是一段快乐的时光。

    读书得到的乐趣,除了对未知的渴求之外,可能还有想要一种“那样的生活”、“那样的爱情”……的满足。当然,这肯定不是读书乐趣的全部。读《冬牧场》感受到的快乐,应该就是这样的吧。

    读李娟的第一本书是《我的阿勒泰》,通过“多看” APP 读的电子版。爱上了那个在北疆生活的女子,爱上了她亲切坦诚而又清澈优美的文字。读的过程中一直在想象作者的模样——优雅、倔强,一个真正的活着,活得明媚的女子。从读《我的阿勒泰》到读《冬牧场》,过去了有三四年,不知道这两本书的写作顺序,在我这里,李娟的生活就在这两本书、三四年间延续着。读到《冬牧场》,第一感觉就是,对了!是那个女子!她现在的生活是什么样的呢?

    后来我知道李娟可能是一个遇到了也不会多看两眼的普通女子,身上并没有我印象中作家那种不食人间烟火的气质。她真的真实,放下笔杆子就是一活生生的人,拿起笔杆子就能把生活活生生地展现在你面前。一个牧民家庭,跟随季节迁徙,尤其在冬天,几个人,一群牲口,去到一望无际的戈壁滩放牧生活,除了无聊、寒冷,有什么可写的呢?拿起《冬牧场》,却感觉不到可能的乏味、无趣,反而让我开始思考,我正在经历的是生活吗?在城市里,上班下班重复着可能并无太多意义的工作,天空灰蒙蒙一片,好像李娟笔下的荒凉的戈壁滩倒挂起来了。这样自然的天色,却闻不到自然的味道。似一场梦,偶尔醒过来,只想逃离。

    我看到的人们呢?人们自私、虚伪、势力、奸诈,人们孤独,无助,无趣、可怜。人们努力建设着的社会秩序里,只有一小部分人在生活,剩下的都是为了生存而不情愿地建筑着那小部分人的生活。也许,这就是这个世界的画面。也许,喜欢李娟是因为她给了我没想到过的生活的另一幅画面。也许,童年的农村生活决定了我更需要一种接近于自然的生活方式。也许,长久以来的不断向上生活目前到尽头了,而这个尽头又是我不能坦然接受的。

    这或许也是一个二十多岁的青年的尴尬。生活看似给了人们无穷的选择权力,但具体到某一个人,未必可以做到“选择”。未必能选择一个最爱的人共度一生;未必能选择结婚不结婚,生不生孩子;甚至未必能选择做你真正喜欢的工作。大多时候的所谓“选择”,只不过是去争取一下,然后等待着“被选择”,这道理是从《向往的生活》黄磊老师那里学到的。到底很少有人能过上自己向往的生活。可还是有些人在二十多岁的时候对自己的生活有了选择,选择逃离目前所拥有的一切,去到一个自己想去的地方,开始一种生活,而且不显得矫揉造作。什么是苦日子?李娟和她笔下的人们风餐露宿的生活是苦日子吗?我不觉得是,没有自由与灵魂的生命才是苦的。

    我甚至在接近成年的时候还不太懂世界观、人生观、价值观有什么意义,虽然从小就被教育要树立正确的三观,被教育什么才是正确的三观。到了二十多岁,我开始怀疑这一切。这个世界和小时候眼中的世界不太一样,人生也不只有一种可能性,小时候被建立的“价值观”似乎与我现在所追求的也没多大关系。读到过一句话:当一个人为你服务,你却不能给他足够的报酬的时候,你就教育他,让他树立正确的三观。……嗯,重构自己的思想,这个过程是很痛苦的,甚至会毁了一切,但是一旦完成了,能坦然地从头再来一次,应该也是很痛快的吧。

  • 从浏览器页面呈现原理来讨论站点优化

    从浏览器页面呈现原理来讨论站点优化

    当前的浏览器现状

    当前主流浏览器使用的内核包括 Webkit(Safari、Chrome、Opera等),Trident(IE),Gecko(Firefox)等,其中最值得了解的当然是 Webkit。

    Webkit 是由苹果公司开发的,供自家浏览器 Safari 使用的内核。Safari 于2003年1月7日首次发行测试版。2010年4月,苹果公司宣布了其浏览器引擎的最新项目 Webkit2。Webkit 内核实际上包含 WebCore 渲染引擎和 JavaScriptCore javascript 引擎。

    Chrome 浏览器自2008年发行起,一直使用 Webkit 作为其内核原型。在13年发布的 Chrome 28.0.1469.0 版本中,又改为使用 Blink 内核。

    前面说过,Webkit 内核包含 WebCore 渲染引擎和 JavaScriptCore javascript 引擎。Chrome 中使用的 javascript 引擎实际上是自家开发的大名鼎鼎的 V8 引擎,V8 主要用在 Chromium 和 Chrome 浏览器中。因此,Chrome 中的 Webkit 和 Safari 中的 Webkit 并不等价,而从 Blink 内核开始,其差别越来越大。

    Chromium 和 Chrome 使用同样的内核,Chromium 是开源的,Chrome 是闭源的,许多功能会在 Chromium 浏览器上应用,稳定后才会在 Chrome 上推出。大多国产浏览器实际上是基于 Chromium 而不是 Webkit 开发的,因此会称 Chromium 为内核。

    移动设备上,Android 4.4 之前的浏览器默认使用 Webkit 内核,Android 4.4 以及之后使用 Chromium 内核。

    鉴于上述,本文技术方面的介绍,是在 Chromium 层面的。

    从资源加载过程来优化站点

    网页是如何展现在我们面前的

    从输入 URL 开始,到网页展现在我们面前,浏览器主要做了以下几件事件:

    1. 从网页的 URL 加载资源
    2. 构建 DOM 树
    3. 从 DOM 树构建 Webkit 的绘图上下文
    4. 从绘图上下文生成最终的图像

    当然,每一步都进行了复杂的处理。而且,浏览器一般会同时做这些事情。下面从网页开发者角度说明每一步中值得关注的点。

    从网页 URL 到加载资源的过程

    通过 URL 打开一个网站,无论这个网站是静态的还是动态的,浏览器通过这个 URL 识别到的都应该是一个 html 文档资源。然后浏览器通过解析这个 html 文档,通过标签识别文档中的其他资源,进一步加载其他资源。

    资源加载和缓存

    Chromium 使用多进程的资源加载和缓存机制。其中 Renderer 进程并没有请求资源的权限,当浏览器需要请求资源的时候,会交给 Browser 进程处理,Browser 进程处理完毕后再交给 Renderer 进程渲染页面。Browser 进程和 Renderer 进程通过进程间通信的方式传递数据。

    如果每次请求资源都从远程服务器请求,将会非常耗时和浪费资源,Chromium 采用了高效的缓存机制。需要请求资源的时候,会先去缓存查找资源是否已经存在,不存在时才会去请求网络资源。

    DNS 预取和 TCP 预连接

    在请求网络资源的时候,会经过域名解析和 TCP 连接过程,Chromium 针对这两个过程,分别做了优化。当我们在浏览网页的时候,Chromium 会提取网页中的超链接,利用系统的 DNS 机制预解析,并将解析结果保存下来,当我们点击链接的时候,就不需要进行 DNS 解析了。开发者可以显式声明哪些域名需要提前解析,做法如下:

    当我们在浏览器地址栏输入网址的时候,如果输入的网址和候选项匹配,那么 Chromium 也会预解析该域名。DNS 预取机制大概可以节省 60ms – 120ms 或者更长的时间。

    更进一步,Chromium 甚至会在 DNS 解析之后,用户点击链接之前提前建立 TCP 连接。这里,Chromium 会使用追踪技术预测我们可能点击的链接,在有很大把握的时候才会做这些事情。

    对于网页开发者的启示:

    • 减少网页的重定向,以更好地应用浏览器的 DNS 预取技术
    • 适当地合并资源,减少浏览器建立连接的次数
    • 压缩资源,节省数据量和数据传输时间

    在 Chromium 或者 Chrome 浏览器中,我们可以通过chrome://net-internals/#dns来查看 DNS 缓存情况,并可以通过 Clear cache 和 Flush sockets 工具来及时清除 DNS 缓存数据。在开发过程中,在切换域名 host 之后,用此工具可以使网页立即解析到新的地址,而不用重启浏览器。

    net-internals -w600

    net-internals 工具中的 DNS 面板截图

    从 html 文档构建 DOM 树的过程优化站点

    构建 DOM 树与资源加载

    上面介绍了浏览器加载资源的过程,在这个过程中,浏览器还会同时进行 DOM 树的构建工作,甚至下文要介绍的构建 Webkit 绘图上下文的工作也是同步进行的,要不然页面呈现在我们面前就太慢了。

    对于图片、CSS、视频等文件,浏览器从 HTML 代码解析到他们的 URL 的时候,会通过相关的资源管理器异步加载,这不会阻碍浏览器构建 DOM 树,但是 JavaScript 代码除外。当浏览器解析到 JavaScript 代码节点或者 JavaScript 资源的 URL,会停下 DOM 树的构建,去加载 JavaScript 文件,执行 JavaScript 代码,然后再继续构建 DOM 树。所以,我们要特别注意,当用 JavaScript 去操作 DOM 的时候,DOM 树很可能还没有构建完成,此时 JavaScript 是获取不到 DOM 节点的。总结 JavaScript 代码出现在文档中时会出现的具体问题:

    1\. 中止 DOM 树的构建;
    2\. 不会并发下载接下来文档中可能存在的 src 资源,比如图片;
    3\. JavaScript 代码如果涉及到对 DOM 的读写,可能会失败;
    4\. JavaScript 代码的执行耗费时间,延长文档的加载完成时间。
    
    

    针对上述问题,关注两个 JavaScript 事件:onload 和 DOMContentLoaded。顺便说明,支持 onload 事件的 JavaScript 对象有 image, layer, window,经常谈到的是window.onloadwindow.onload事件是在包括图像等资源在内的,整个页面全部加载完成之后才会触发,DOMContentLoaded事件在网页文档加载并解析完毕(DOM 树构建完成)之后就会触发。所以,对 DOM 的操作放在DOMContentLoaded事件触发之后最好。将 JavaScript 代码放在文档的最后(一般是置于 body 元素里面紧贴 body 闭合标签)也是一种方案。

    当然,确实有一些 JavaScript 代码是与 DOM 无关的。这种情况下,可以为 script 元素添加async属性,告诉浏览器这是可以异步执行的 JavaScript 代码。

    HTML 网页和它的 DOM 表示

    Webkit 实际上具有预扫描和预加载机制,在文档中解析到 JavaScript 代码的时候,会继续解析后面的文档查看有没有资源需要下载,有的话就下载,但在实际测试中,浏览器确实去下载资源了,但是由于 JavaScript 代码执行时的阻塞,资源并没有加载。而且其他的浏览器中不一定有此机制。因此,还是推荐使用前面的处理策略。

  • 冷漠

    冷漠

    周末网上看到两件事情。

    一件事发生在北京街头,一孩子骑自行车碰倒了一位阿姨,那孩子只扭头看了一眼,就走了。路过的一位摩托车骑手看到了之后,首先去把阿姨扶了起来,然后让那孩子过来向阿姨道歉。那孩子态度非常不好,摩托车手把他训斥了一顿。他跟那孩子说就是过来道个歉,什么事都没有。孩子的父亲自始至终一直在,但是什么也没说,什么也没做。骑手坚持,那孩子最终道了歉。骑手后来接受采访,说他这不是管闲事,这也不是闲事,他不希望这个世界这么冷漠。

    DSCF3035副本.jpg
    晚上的南艺艺术创客空间

    另外是一则广告,父母亲给自己的孩子买平板电脑,店员询问孩子多大了,父亲说孩子今年 5 岁,店员让父亲 7 年后再来给他买。父亲不解,店员说孩子还小,在他变得冷漠之前应该和家人在一起,享受家的温暖。

    DSCF1144副本.jpg
    白天的南艺艺术创客空间

    第三件事是我这周末又去了南艺。去年去的时候正值开学,校园里的创意街区,人来人往,沿街点缀设计精良的小店,极富感染力与艺术气息。这次去,南艺还在暑假中。夜色中,校园里只有晚饭后散步的三两人。走在创意街区,几只小猫在路灯下吃路人撒的猫粮,秋叶落下,只有凄凉。

    DSCF3039副本.jpg
    路灯下的猫

    真正有价值的是人,是正在活着的人。刨去了人的行为、感情,时间也会黯然失色。

    Image
    南艺下午茶
  • 傍晚雨中雨后的南京建邺

    傍晚雨中雨后的南京建邺

    二零一七年七月二日,南京,雨

    这天雨下得并不大,湿气倒很重

    从走廊向外望去,白茫茫一片

    是南方的那种烟雨楼台

    如果在白墙黑瓦的秦淮河畔

    大概是另一幅诗意的景象

    DSCF2845.jpg
    雨中

    雨过天晴后的建邺

    天际线还不错

    空气清澈而舒爽

    DSCF2895.jpg
    雨后
  • Laravel 使用 Laravel Mix 打包前端静态资源,引入 Vue

    Laravel 使用 Laravel Mix 打包前端静态资源,引入 Vue

    Laravel 的静态资源处理方式不断更新,5.4 版本从 基于 gulp 的 laravel-elixir 完全升级到构建于 webpack 之上的 laravel-mix。

    项目原来的打包策略

    1445238527elixir-1024x549.jpg

    本站基于 Laravel 开发,更新到 Laravel 5.4 之前的静态资源打包混合使用laravel-elixir(gulp)webpack,由于要实现静态资源(主要是 js)跟随版本的模块化加载,以便下一步实现静态资源分离,使用 CDN 加速(本站使用七牛),其时的gulpfile.js打包脚本如下:

    /* ...省略了一些变量定义代码... */
    
    elixir(function (mix) {
        /* bootstrap 字库 */
        mix.copy(AWESOME_FONT_PATH, `${DIST_PATH}/fonts`);
    
        /* 复制图片 */
        mix.copy('resources/assets/img', `${DIST_PATH}/img`);
    
        /* CSS 处理 */
        mix.sass('lib.scss', `${DIST_PATH_WITH_VERSION}/css/lib.css`);
        mix.sass('app.scss', `${DIST_PATH_WITH_VERSION}/css/app.css`);
        mix.sass('control.scss', `${DIST_PATH_WITH_VERSION}/css/control.css`);
    
        /* JS 处理 */
        mix.webpack([], `${DIST_PATH_WITH_VERSION}/js`);
    });
    

    webpack.config.js文件中的处理脚本如下:

    /* ...省略了一些变量定义代码... */
    
    // webpack 入口
    let entry = {
        vendor: ['jquery', 'bootstrap-sass']
    };
    
    /**
     * 生成文件入口
     */
    _.forEach(JS_MODULES, module => {
        if (module !== 'helpers') {
            entry[module] = path.resolve(JS_PATH, module, 'index.js');
        }
    });
    
    //noinspection JSUnresolvedVariable
    module.exports = {
        entry: entry,
        output: {
            filename: '[name].bundle.js'
        },
        resolve: {
            alias: {
                'jquery': path.join(__dirname, 'node_modules/jquery/src/jquery')
            }
        },
        plugins: [
            new webpack.optimize.CommonsChunkPlugin({
                names: ['vendor', 'manifest'],
            }),
        ],
    };
    

    更新到 Laravel 5.4 之后项目的打包策略

    1-LthzZzfbaat9WPg6hQRCNg.png

    更新到 Laravel 5.4 之后,全部使用 webpack 来打包静态资源,迁移步骤如下:

    1. 参考 Laravel 5.4 更新 package.json 文件;
    2. 添加webpack.mix.js文件;
    3. 复制一份webpack.config.js文件到项目的根目录(备份好原有的配置文件):cp node_modules/laravel-mix/setup/webpack.config.js webpack.config.js 删除package.json文件scripts字段中如下参数配置,以加载使用复制的配置文件--config=node_modules/laravel-mix/setup/webpack.config.js 使用复制的 webpack 配置文件的原因是要支持模块化跟随版本的打包方式,实际上仅仅修改了原有配置中的输出路径。
    4. 迁移原有的配置,webpack.mix.js文件更新如下:const { mix } = require('laravel-mix'); /* ...省略了一些变量定义代码... */ /* CSS 处理 */ mix.sass('resources/assets/sass/lib.scss', `${DIST_PATH_WITH_VERSION}/css/lib.css`) .sass('resources/assets/sass/app.scss', `${DIST_PATH_WITH_VERSION}/css/app.css`) .sass('resources/assets/sass/control.scss', `${DIST_PATH_WITH_VERSION}/css/control.css`); /* JS 处理 */ _.forEach(JS_MODULES, module => { if (module !== 'helpers') { mix.js(`${JS_PATH}/${module}/index.js`, `${DIST_PATH_WITH_VERSION}/js/${module}.bundle.js`); } }); /* Vue 处理 */ mix.js('resources/vue/index.js', `${DIST_PATH_WITH_VERSION}/js/vue.bundle.js`); /* 公共库 */ mix.extract(['jQuery', 'vue'], `${DIST_PATH_WITH_VERSION}/js/vendor.bundle.js`); 可以看到,添加了 Vue 处理路径配置,具体的处理脚本,原作者已经在webpack.config.js中写好了!

    无论是原有的打包方式,还是新的打包方式,,我们要做的也就是根据项目规划,配置一下打包文件入口和输出而已,其他的处理,Laravel 已经配置好了。

  • 树莓派(Raspberry Pi)入门实战记录之 SSH 局域网无线连接

    树莓派(Raspberry Pi)入门实战记录之 SSH 局域网无线连接

    树莓派作为一台完整的微型电脑,可玩性很高。树莓派使用 microSD Card 作为存储介质,安装系统就是把系统镜像写入 microSD Card 中。将写好系统的 microSD Card 放入树莓派的 microSD Card 插槽中,通电,就完成了树莓派启动。我手中的树莓派是 Raspberry Pi 3 Model B 型,集成了蓝牙和 WIFI 模块。

    在 Mac 下用 ApplePi-Baker 安装树莓派系统非常方便,ApplePi-Baker 的界面如下图所示:

    WechatIMG1.jpeg
    1. 左侧选择要写入树莓派系统的 microSD Card;
    2. 右侧上方小窗口 IMG file 选择下载好的树莓派系统镜像(我一般使用树莓派官方制作的 RASPBIAN 镜像,可以从树莓派官网下载到);
    3. 然后点击右侧上方小窗口中的 Restore Backup 按钮,等进度条跑满就完成了树莓派系统的制作。

    接下来的操作就是将写好系统的 microSD Card 装进树莓派,开机。

    如果有一台显示器,可以选择相应树莓派操作系统的图形界面版本,将显示器、鼠标、键盘接入树莓派来实现普通桌面电脑的操作体验。我拿到树莓派的时候手边并没有可用的显示器,也并不打算通过外接键盘、鼠标的方式实现对树莓派的控制,所以下面介绍通过 SSH 方式连接树莓派。如果通过 SSH 方式连接树莓派,在写好系统后要新建一个名为 SSH 的文件放入 microSD Card 的根目录,以打开树莓派的 SSH 功能。然后进行如下操作:

    1. 将树莓派通过网线连接路由器;
    2. 通过路由器的管理界面查看树莓派目前使用的 IP 地址,记下这个地址(我的是:192.168.0.15);
    3. 树莓派的默认用户是 pi,密码是 raspberry ,通过以下命令可以连接到树莓派:ssh pi@192.168.0.15 WX20170415-215417@2x.png

    经过上面三步已经通过 SSH 方式连接到了树莓派,接下来我们可以让树莓派通过无线连接方式连接到路由器(当然得是无线路由器)。我使用的是树莓派官方制作的 RASPBIAN 系统,选择其他系统可能操作不同。

    1. 查看可用的网路,必须使用 sudo (这步非必须,如果知道无线路由器的 ESSID 的话): sudo iwlist wlan0 scan 记下要连接的无线路由器的 ESSID:WX20170415-220916@2x.png
    2. 编辑 /etc/wpa_supplicant/wpa_supplicant.conf,添加无线网络配置: network={ ssid="Targaryen-Cloud" psk="your-password" }
    3. 重启系统,拔掉网线,通过路由器管理界面可以看到树莓派已经通过新的无线方式连接到路由器了。

    这一步结束后路由器可能会为树莓派分配新的 IP 地址,所以 SSH 连接树莓派时注意切换新的 IP 地址!

  • 在树莓派上安装 Docker 记录

    在树莓派上安装 Docker 记录

    树莓派默认源中的 Docker 版本太老了,一些 Docker 的新特性无法尝试,这里尝试在树莓派上安装新版本的 Docker。安装方法主要参考了开源中国的一篇文章 《Raspberry-jessie Docker 安装记》。如果去看原文并且也只是想安装 Docker 的话 ,建议从原文的第 5 步开始看起,前面是作者的试错过程。这里将可以成功在树莓派上安装新版本 Docker 的关键步骤整理如下:

    1. 添加源到系统,这里使用的是阿里的源,将 debhttp://mirrors.aliyun.com/docker-engine/apt/reporaspbian-jessie main 加入到系统 /etc/apt/sources.list 文件中。
    2. 将 key F76221572C52609D (这 key 是在添加源后执行 sudo apt-get update 的警告信息中获得的)添加到系统 apt-key 列表:gpg -a --export F76221572C52609D | sudo apt-key add -
    3. 安装 Dockersudo apt-get update sudo apt-get install docker-engine

    至此,完成了在树莓派上安装新版本 Docker 的全部过程!

    nature-2129493_1920.jpg
  • 苏州印象

    苏州印象

    去苏州也算得上是一次说走就走的旅行了

    ……

    2016-12-31

    ……

    2017-01-01

    据说苏州火车站也是很有苏式味道的,行程安排忽略了,只能按照已有计划匆匆前往旅程第一站。游览完最后一站,由于旅途疲惫,到了苏州站准备改签车票尽早返程。虽然排了长队,但改签的速度还是远超预期,所以,在苏州站广场长久逗留,得以感受一番苏州站的美。如果是初到苏州直奔车站广场,定会被其震撼。

    DSCF2253.JPG
    苏州城的正确打开方式——苏州站广场

    然而我打开苏州城的方式是整站的绿皮火车,隐约感受到的中式屋顶,融合了充满现代感的简约线面设计,也是极具特色的苏州味道,不过一些店铺招牌略显扎眼,为何不换个素雅些的,以与其相融合?

    绿皮火车
    苏州火车站内景
    DSCF1979.JPG
    苏州火车站内景

    苏东坡说过,“到苏州不游虎丘者,乃憾事也”,于是这第一站选择了虎丘,过了“吴中第一山”牌坊,大概是虎丘公园吧,此时并未进入景区内部,公园石板整洁,应是新修。

    吴中第一山.jpg
    吴中第一山

    进入景区,一阵古风扑面而来。虎丘山下是一条碧波荡漾的河,经查名叫“山塘河”,是大诗人白居易为便利苏州水陆交通开凿,河中停泊客船,一下就让人想起“夜半钟声到客船”的诗句。

    虎丘环溪.jpg
    虎丘山下的“山塘河”



    沿河行走,会有各式石拱桥,虽然应也是新修的,搭配两岸白或黄墙、黑瓦,依然可以让人感受一下“小桥流水人家”的闲适意境。

    Image
    小桥流水人家
    Image
    古道夕阳帅马
    Image
    飞檐走壁
    DSCF2088.JPG
    荷言旗袍
    DSCF2145.JPG
    水乡亦或水城
    DSCF2160.JPG
    三眼拱桥,平静的水面
    DSCF2163.JPG
    人潮
    DSCF2170.JPG
    苏州城的生活气息
    DSCF2189.JPG
    绿树掩映中的苏式庭院
    Image
    采风