learn windows powershell in a month of lunches/Windows PowerShell实战指南(第2版)

Windows PowerShell实战指南(第2版)

Windows PowerShell实战指南(第2版)

说回来这本书还是1块钱从kindle活动淘到的。最初接触windows powershell 是因为要卸载win10自带的一些重复应用,
例如appx版本的无用的在中国的网络环境中永远无法完成同步的ms onenote. 而其office pc端的onenote则表现得好的多。

虽然我自己已经订阅了office 365但是还是提醒一下大家ms onenote早已免费,而且非常好用,同步在中国区勉强可用。

后开始尝试使用powershell代替cmd操作一些功能,当时主要是win python和git.
再之后就是win10刚好发布了WSL, 开始使用powershell启动bash, 联动调试flask.
某些应用比较tricky, 尤其是virtualenv和python lib的关联一直都不是很清白,似乎还不能完全支持虚拟环境。
也趁此机会了解学习一下powershell的用法。

key points

  • powershell的诞生是为了替代cmd和vbscript进行计算机管理,脚本化批量操作
  • powershell的命令行集中在单行指令中执行,像句子中的主谓宾区分一样有专门的’行动’命令和’对象’命令
  • 自带的ISE功能强大,辅助脚本编写

archive

  • 2014年左右轻度使用过win server, 因此也不具备服务器端管理和批处理的经验。快速浏览完留下印象为以后应用的时候做好回溯准备。
  • 用的最多的还是flush dns类似的功能,在powershell里使用help 查询dns关键字即可调出相关命令。暂时也还没有深度使用和批处理的需求。
分享到 评论

The autobiography of Benjamin Franklin/富兰克林自传

富兰克林自传

富兰克林自传

这本也是Kindle做活动的时候1块收的。印在$100上的有故事的男人,及其附有魅力的美国国父,在科学上的成就可以比肩活在光电帝国里的三个电学祖师爷。
因为观察树叶的脉络发明钞票印刷防伪技术而把自己的头像留在了钞票上。

生于1月17日,墓志铭是费城的一个印刷匠,100多年前出版的穷理查历书甚至到现在都还频频出现在当代成功学的关键字里。
书里是个有志的青年,不甘于平凡的商人,对未知事物有包容心的科学家,心怀中产阶级的政治舵手。
当然私生活也是一团乱的奇怪的人。

从书中我看到的不是在独立宣言上签字的那个美国国父,也不是印在美刀上的侧脸,而是个不甘于平凡的人的一生。

从经济独立到学术成就,从皇家科学院的讲台步入社会金字塔的顶端,辗转政治的领域。后在工商、科研和政治领域都留下了深深的烙印。

抱着对美好未来的坚定信心和对中产阶级人民最大的信任,将自己的信念在出版物上传播。
起初出任外交官员长驻英国为殖民地最大化地争取权益,后随为了联邦政府的独立辗转法国求援。
再到废奴意识的觉醒和推广,贯穿南北战争。

虽然已经在历史的车轮上已经留下了足够的印记,但是我看到的仍是一个内生矛盾的人的挣扎。
坚信以实用主义博取商业和政绩的成就,先独善其身而后则兼济天下,不甘于平凡的人生。

在长途跋涉的航运旅程中也不忘检测洋流温度,开拓了海洋学研究的领域。
简直让我不禁怀疑是我们生错了时代还是那个时代伟人扎堆现世。

读书可以以数小时的代价获取到其他人一生的体验,读书的代入感让我窥见了历史的一隅。在这历史的洪流中,随波逐流。

分享到 评论

http权威指南

HTTP权威指南

HTTP权威指南

同为亚马逊kindle活动时候1毛买书,屯着看。2013年的日版kpw2也马上要陪我走过第四个年头。
陪我从上海到深圳,又回到上海,陪我从传统能源行业到新能源行业甚至到写代码开博客,拓展出更多的可能。

该书在2014年初识python的时候就听闻大名,去年Q4用flask写网站调试也遇到了相关问题,正好补充这块的知识。
本书也非本专业内的书,因此就过的快一些,待到用时再回看。但是电子书不方便回溯也是算是缺点之一吧。

key points

  • http版本众多,某些版本不向下兼容
  • http头文件内含重要信息
  • 重要的方法,GET POST DELETE等
  • 服务器回执码,有很多预留位,但是总的来说2XX是成功,3XX是含警告,4XX是未找到等各种问题,5XX是服务器内部发生错误
  • 404是常见错误,未找到
  • 500也是服务器内部代理错误
  • 除了url还有uri来标识网络地址
  • https开始普及,443端口,ssl安全连接

archive

  • 书是好书可能是我看太快了没有太顾及的到细节,本书中提到了DOM但是也没有细讲,之前写网站的过程中文本信息的前后端传递这块确实发生了困扰。
  • 提到了DNS解析和反向代理相关的内容,回顾起来也突然没了很明显的印象,最近在同步看TCP/IP相关的书,也有可能是错觉
  • 考虑要不要收一本纸质书
分享到 评论

roof detection by opencv

背景简介


可再生能源是世界的未来,光伏发电是可再生能源里不可或缺的一个版块。
本人有幸自14年从传统石化能源行业转行到新能源行业,并且一直在与分布式光伏项目打交道。

对于分布式项目国内外也有不同,北美的分布式项目多指容量较小的项目,也包含部分直接对电网ppa的项目。
而我国的分布式项目主要是指屋顶分布式项目,虽然走量大的是全额上网项目,但是个人还是坚持自发自用项目才是真正的分布式项目,
也是最符合业务逻辑(高风险高回报)的项目。

那么好的屋顶(面积要大,承重要够)和好的企业(讲信用,按时付电费,存续时间长)是我们主要搜索的目标。

因此有足够的动机通过卫星图挖掘好的屋顶资源,抢占先机。虽说拿下屋顶主要靠人脉资源,
但是发掘优质资源勉强算是一种需求。

该应用主要用于实现下列事项:

  1. 下载选定区域卫星图
  2. 识别图中的屋顶
  3. 获取屋顶的业主企业信息

可用的免费卫星图源也不多,就google, 百度,高德,其他付费图源包括HERE, Openstreet map以及其他国内付费卫星图源。
就时效性和可用性(API配额、便捷和技术支持)而言就只剩google了。唯一麻烦的是需要翻墙,在自己电脑上使用shadowsocks
全局下载很不稳定,1600张600x650 z16的图断断续续地下了将近一周。

识别程序主要参考了 Roof detection in aerial images of Uganda, 该文献google暂时查不到,scholar里也没有,比较奇怪。
该文献内容虽然比较粗糙,但是讲的方法是最直白最实用的了。

Roof detection in aerial images of Uganda,
Angela Santin Ceballos, Master of Science,
Artificial Intelligence School of Informatics,
University of Edinburgh, 2015

文献中功能实现的代码详见github. 其pipeline详见下文:

1
2
3
4
5
6
opencv cascading training -> cascade models : fast propose rect roof candidates, output the coords of the roofs in satellite image
python machine learning pkg Theano -> convolutional neural network model : recognite whether it's a roof including rotated scenario in candidates, output the possibility
raw image ->> opencv viola jones detection with cascede models -> cNN detection -> Non-maxima suppression ->> detected image
Non-maxima suppression used to delete the roof parts and save the most overfeat one

获取企业信息主要使用map api服务商的reverse geocoding功能,即逆地理信息查询,通过经纬度查询point of interest(poi).
poi的结果严重依赖地图服务商的数据库。这方面就是国内地图服务商的强项了,google显然离开中国市场太久导致无人上报,水土不服。
后经过斟酌选用高德API来进行reGeo,主要原因是配额和技术支持以及地点的可靠性。高德个人开发者每天只有2000配额,
升级为企业开发者后拥有每天400万配额,每分钟6万上限。缺点是识别出来的图片的坐标系统为WSG89,且国内有偏移,
需要用高德的坐标准换API转换后才能减小偏移误差,提升poi匹配精度。即使这样也无法完全消除坐标偏移影响。

由于该项目初期对ap要求不高,因此只实现了前面opencv cascading detection部分,后续cNN未实施。
初步计划在本地执行python脚本,
但是在实际过程中发现脚本的运算时间过长(dell xps13 9350, ubuntu 16 LTS 平均识别时间约20s),效率太低。
后换闲置的dell vostro 3800挂机运行,仅执行识别脚本,每天最多只能输出~9000 poi, ~1200 km2硬是跑了5天多,效率依旧很低。

后使用aws ec2 t2.micro配置的服务器进行图像下载和识别,大概每小时可以处理约100 km2区域,涵盖约3000 poi.

代码分析


卫星图像获取部分代码详见下文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
lat_list = np.arange(start_lat, end_lat, step)
lon_list = np.arange(start_lon, end_lon, step)
total_num = len(lat_list) * len(lon_list)
a = np.array([[0, 0]], dtype=float)
for lat in np.arange(start_lat, end_lat, step):
for lon in np.arange(start_lon, end_lon, step):
b = np.array([[lat, lon]], dtype=float)
a = np.concatenate((a, b))
flag = 2
i = flag
for v in a[flag:]:
lat = v[0]
lon = v[1]
urlparams = urllib.urlencode({'center': '{0},{1}'.format(lat, lon),
'zoom': 16,
'size': '600x625',
'maptype': 'satellite',
'key': GOGL_WEB_KEY})
url = 'https://maps.googleapis.com/maps/api/staticmap?' + urlparams
print 'now saving... {0}/{1} ...'.format(i, total_num)
urllib.urlretrieve(url, "image_cache/sate_c_{0}_{1}_z_16.png".format(lat, lon))
with open('scan_coords.csv', 'ab') as f:
writer = csv.writer(f, delimiter=';')
writer.writerow([i, "image_cache/sate_c_{0}_{1}_z_16.png".format(lat, lon), lat, lon])
i += 1
t = random.randint(1, 3)
time.sleep(t)
print '*** mission complete ***'

其中的难点主要在于经纬度入参,需要根据方块边界的经纬度每张图片的经纬度中心点,
下载像素范围(与zoom有关)以及步长。经纬度包含小数点后6位,需要进行float除法,并且组成数组遍历。
但是list只支持int, 因此需要使用numpy中的array来完成按步长计算和遍历。

1
2
3
4
5
6
7
8
input_xml = 'parameter/cascade.xml'
roof_cascade = cv2.CascadeClassifier(input_xml)
img = cv2.imread(input_image)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
roofs = roof_cascade.detectMultiScale(gray, 1.05, 3)

其中Input xml即为训练完成的model,识别代码也非常简单,roofs为输出的obj, 内含像素坐标集合。

cascading训练相关资料

在初次训练的时候花费了近2天的时间手工截取了1200多个正样本,训练效果一般。这种做法比较不可取,但是也局限于没法找到免费的训练样本集。
上文中的作者直接pitch了在Uganda大学做相关研究的教授,直接获取了训练样本,节省了大量的时间。

object detection case及相关资料

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def regeo(lat, lon):
urlparams = urllib.urlencode({'key': AMAP_WEB_KEY,
'location': '{0},{1}'.format(lon, lat),
'poitype': '公司',
'radius': 300,
'extensions': 'all',
'batch': 'false',
'roadlevel': 1})
url = 'http://restapi.amap.com/v3/geocode/regeo?' + urlparams
urlhandler = urllib.urlopen(url)
mdata = json.loads(urlhandler.read())
addr = mdata['regeocode']['formatted_address']
company = list()
company.append(addr)
note = 'there does not exist any companies near 300m of this coords'
for poi in mdata['regeocode']['pois']:
if u'公司' in poi['type']:
company.append(poi['name'])
if company:
return company
else:
return note
print note

这里只是调用高德的reGeo API, 并没有什么特别要注意的难点,内里也只有一些简单的string manipulate.

trouble shooting


图像识别中处理旋转的图像和识别准确率的提升

后续程序的优化在于使用cNN方法进行图像识别,opencv的VJ方法的有点是速度快,可以快速推送candidates,
后跟进cNN进行屋顶的是非概率判断也是非常关键的。当然在VJ方法中也可以选装图形进行训练或者识别,
毕竟屋顶的朝向多数为正南,东南或者西南,特征也非常显著。总之存在很多方法提升ap.

也是自己挖的坑还需要再填补。瓶颈在于训练样本的获取。

识别效率

现阶段看来使用aws ec2的服务可以完全满足需求,商用价格也相对合适,自用的话第一次使用有1年的免费t2.micro的使用期。
付费的可以选择light sail服务,$10月租与t2.micro同配置的服务器也算合适。

国内的BAT三家也都提供相应的云服务,由于使用阿里旗下的高德地图API, 因此尝试过使用阿里云的计算资源,后由于没有免费的试用资源放弃。
aws中国是单独代理运营的公司,且不提供试用,要备案,约束较多,不建议使用。腾讯的云服务有争议,百度的就不推荐使用了。

分享到 评论

practice of raspberry pi 2

背景简介


2014年还在深圳的时候想尝试一下智能家居相关的业务和具体的玩法,入了raspberry pi2的板卡、亚克力外壳、2A的适配器和一个腾达的无线网卡。

rp2使用低功耗的arm处理器,装载debian系统,主板采用最简化配置和有限的接口,整个面积只有公交卡大小。用hdmi线连接显示器,接好键盘,插入存着
预安装程序的sd卡即可开始安装。设置为固定ip之后就可以使用ssh或者vnc远程登录。

raspberry pi有强大的GPIO接口,方便连接其他控制元件,例如电气控制中最常用的继电保护装置。
当时主要跟随以下三本书的内容推进。

爱上Raspberry Pi

Linux+树莓派玩转智能家居(第2版)

Raspberry Pi:Python编程入门

也间接增加了搬家时候的负担和痛苦。

言归正传,也是从rp2开始接触Linux系统,顺便在14年在edx跟完了两门很重要的课程: Introduction to Computing with java, Indroduction to Linux.
也趁此机会复习了一下模拟电路里的知识和电子器件。

借着在深圳的地利也买了块面包板和一堆杜邦线,传感器件。最后半途而废,搬家的时候还随身带着这些东西,警示着自己的怠惰。

少了一份填坑的坚持。不知道是不是因为随着年龄的增长越要想在行动前看到利益,更加世俗了。

回溯起来,从15年1月开始之后的第7周,知道了办公室即将于4月底解散。忙于下一份旅途的不确定性,耽误了下来。最终绕了一圈,又回到了上海。

代码分析


基于debian, 并且很方便利用python程序调用GPIO接口,但是最后没有试验成功。
所以这块暂时就没有代码可以展示。

trouble shooting


再次摘录一些归档的笔记和荒废在csdn blog里的一些东西。


GPIO

端子25电压为3.3V, 和arduino的电压不同,不能混用,切记。

GPIO python pkg可以找到相关脚本python支持包。


Raspberry pi 2 适配器型号

为了稳定运行,请使用5V 2A适配器。


公网IP和远程登入

当时想通过微信远程遥控,因此遇到了公网IP的问题。电信用户一般都是有公网IP的,但是不是固定IP, 每隔一段时间会有变动。
使用花生壳可以进行内网穿透,但是当时没有找到完美的解决方案,在debian系统内安装成功,但是没有调试成功。

电信一般是封锁80端口,因此需要通过其他途径绕开。一般使用vps部署NGINX反向代理解决。

Yeelink也提供一些内网穿透的解决方案,但是个人最终没有调试成功。

当时也希望用pi架设一个blog, 由于公网IP的问题最终也作罢。不过2年之后在github上实现了久远的愿望,也不错。


LCD1602

参考接线完成后成功点亮LCD,由于没有电位器所以不能调节LCD亮度。

连接液晶屏:
LCD1602液晶屏提供了16列x2行的ASCII字符显示能力,工作电压5V,
提供4位数据与8位数据两种工作模式,Raspberry Pi的GPIO口数量很有限,所以我们使用4位数据模式。

LCD1602液晶屏模块提供了16个引脚,我们只需接其中的12个即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1. VSS,接地,RPi PIN 6
2. VDD,接5V电源,PRi PIN 2
3. VO,液晶对比度调节,接电位器中间的引脚
4. RS,寄存器选择,接GPIO 14,RPi PIN 8
5. RW,读写选择,接地,表示写模式,PRi PIN 6
6. EN,使能信号,接GPIO 15,RPi PIN 10
7. D0,数据位0,4位工作模式下不用,不接
8. D1,数据位1,4位工作模式下不用,不接
9. D2,数据位2,4位工作模式下不用,不接
10. D3,数据位3,4位工作模式下不用,不接
11. D4,数据位4,接GPIO 17,RPi PIN 11
12. D5,数据位5,接GPIO 18,RPi PIN 12
13. D6,数据位6,接GPIO 27,RPi PIN 13
14. D7,数据位7,接GPIO 22,RPi PIN 15
15. A,液晶屏背光+,接5V,RPi PIN 2
16. K,液晶屏背光-,接地,RPi PIN 6

分享到 评论

best pracetice of GIS coding in front end with AMAP api

背景简介


综合前篇是为了做一个光伏应用的网站,展示一些屋顶信息。计划以卫星地图为底图背景,
同时方便交互。

考虑到地图更新频率、区域屏蔽以及国内GIS坐标偏移等问题,优先方案是google map api.
但是在实施过程中实际的问题是前端代码在客户浏览器执行,因此google map在国内就根本加载
不出来。再次我编程调试使用的电脑也没有完全翻墙,当时也还没有选定在国内还是国外部署。
考虑到以上各种不确定性,最后采用风险较低,地图质量较好的高德地图。

PS: 早先有编程进行过批量的逆地理编码查询,google, baidu, 高德三家的map api均有涉猎。
就服务的质量判断,google最好。国内的高德好于百度,无论是web, js api, 测绘地图质量,技术文档还是
人工服务。

坐标漂移一直存在,从经纬度(WSG89)换算到国内的经纬度仍然会有0~500 m的随机偏移无法避免
因此该案例中使用google坐标系(WSG89)识别的物体换算国内经纬度一定会存在漂移。
即使用AMAP自家的经纬度转换API进行处理。

代码分析


其中部分代码详见下文,在第三行的YOUR_API_KEY中对应的是开发者自己申请的API KEY.
各家的js api key都是无配额限制,但是无法理解的一点是无法隐藏该API KEY,
即无法在script src字段内使用变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
<script src="http://cache.amap.com/lbs/static/es5.min.js"></script>
<script type="text/javascript" src="http://cache.amap.com/lbs/static/addToolbar.js"></script>
<script type="text/javascript" src="http://webapi.amap.com/maps?v=1.3&key=YOUR_API_KEY&plugin=AMap.MouseTool"></script>
<script type="text/javascript">
// set up map canvas.
var map = new AMap.Map('container', {
resizeEnable: true,
center: [121.405034,31.164609],
zoom: 16
});
map.setDefaultCursor("crosshair");
// set up marker.
var marker = new AMap.Marker({
position: [121.405034,31.164609]
});
marker.setMap(map);
// click event to open marker.
marker.on('click',function(e){
infowindow.open(map,e.target.getPosition());
})
// advanced marker, more info.
AMap.plugin('AMap.AdvancedInfoWindow',function(){
infowindow = new AMap.AdvancedInfoWindow({
content: '<div class="info-title">XXX</div><div class="info-content">'+
'<img src="http://webapi.amap.com/images/amap.jpg">'+
'XXX!<br/>'+
'<a class="glyphicon glyphicon-envelope" href = "mailto:info@XXXcn.com">moreinfo</a></div>',
offset: new AMap.Pixel(0, -30)
});
infowindow.open(map,[121.405034,31.164609]);
})
// enable tool kits.
AMap.plugin(['AMap.ToolBar','AMap.Scale','AMap.OverView','AMap.MapType'],
function(){
map.addControl(new AMap.ToolBar());
map.addControl(new AMap.Scale());
map.addControl(new AMap.OverView({isOpen:true})); //遮挡button-group
map.addControl(new AMap.MapType({defaultType:1}));
});
// right button functions.
var mouseTool = new AMap.MouseTool(map);
AMap.event.addDomListener(document.getElementById('areaMeasure'), 'click', function() {
//鼠标工具插件添加draw事件监听
AMap.event.addListener(mouseTool, "draw", function callback(e) {
var eObject = e.obj; //obj属性就是鼠标事件完成所绘制的覆盖物对象。
});
mouseTool.measureArea(); //调用鼠标工具的面积量测功能
map.on('dblclick', function() {
mouseTool.close('True');
});
}, false);
AMap.event.addDomListener(document.getElementById('eargleEye'), 'click', function() {
var drawRectangle = mouseTool.rectangle(); //用鼠标工具画矩形
AMap.event.addListener( mouseTool,'draw',function(e){ //添加事件
var rect = e.obj;
var data = {"minLng" : rect.getBounds().getSouthWest( ).getLng(),
"maxLng" : rect.getBounds().getNorthEast( ).getLng(),
"minLat" : rect.getBounds().getSouthWest( ).getLat(),
"maxLat" : rect.getBounds().getNorthEast( ).getLat(),
"cLng" : rect.getBounds().getCenter( ).getLng(),
"cLat" : rect.getBounds().getCenter( ).getLat()
};
if(confirm("are you sure to submit?"))
{
$.post({
url : "{{ url_for('main.NEWPAGE2', username = current_user.username) }}",
data: JSON.stringify(data),
contentType: 'application/json;charset=UTF-8',
success: function(data) {
top.location.href = "{{ url_for('main.NEWPAGE2', username = current_user.username) }}";
},
async:false
});
}
else
{
mouseTool.close(true);
}
});
}, false);
</script>
  • 实现的功能详见代码内注释的文档,其他明细可详询官方文档
  • 官方的实例中心内有详实的案例供参考引用
  • 其中带数字的红蓝图钉只到10, blue mark,red mark
  • 该案例使用的是flask-bootstrap模板,因此模板文件完全支持bootstrap,
    地图嵌入使用容器embeded-responsive.
  • NEWPAGE2中需要达到分栏的效果,使用的是row, col-lg-xx 两个组件进行分区,
    其中一个嵌套地图容器

trouble shooting


无法在src中隐匿API_KEY

一般而言像API_KEY这样的私密信息是写入系统环境变量,在代码中直接读取而非明文写入代码。
即使是jinja2的模板用 的方法也无法将变量传到src=’’中。
所以这点暂时无解,只能在API设置里标记好白名单以规避滥用风险。

但是stack overflow里有一说是和域名关联,也无法滥用

KEY或者其他私密信息例如email和密码都强烈建议使用环境变量

在python中读取系统环境变量:

1
2
import os
os.environ.get('ENV_VAR_NAME')

一般建议将系统环境变量写入到虚拟环境中,即virtualenv中。系统环境变量设置方法:

Linux:

1
$ export ENV_VAR_NAME='YOUR_API_KEY'

windows cmd/powershell:

1
>set ENV_VAR_NAME='YOUR_API_KEY'

AMAP前端说明

虽然高德已经是阿里旗下的产品但是个人读说明文档还是不够顺畅,无法直接找到
解决问题的方法。

社区活跃度也是一般,稍微比百度的强一些。该案例中很多时间都花费在了调试上。

分享到 评论

best pracetice of flask development

背景简介


填坑,记录分享在2016年12月使用flask进行web开发遇到的一些问题。

本人只有入门级的python经验,之前只写过一些爬api数据的工具,
入门级Linux经验 —— MOOC edx和Rasp pi 2进行少量实践,
入门级Java coding经验 —— MOOC edx,
入门级Javascript经验 —— codeacadamy, w3cschool,
入门级Machine learning经验 —— MOOC coursera by Octave,
未做过web开发相关的事。

本次事件的背景是要上线一个可以识别屋顶的web应用,
使用场景主要在新能源行业,具体作用是辅助分布式光伏项目开发。
本次web开发主要基于web development of flask
这本书。

局限于个人经历,经过简单咨询,起步时决定使用flask作为后端,也方便对接现有的机器学习包。
由于有传参的需求,因此前端使用AngularJS进行相关数据绑定和传输。
GIS api原计划使用Google map api, 但是由于资金没有到位,暂时无法获取可靠的服务器资源,改用国内使用环境较友善的AMAP(高德地图) api.
初步的项目是在线执行识别程序脚本(python脚本),
但是在项目实际过程中发现脚本的运算时间过长(dell xps13 9350, ubuntu 16 LTS 平均识别时间约20s),
因此决定把识别和渲染分离。识别结果单独进sqlite数据库,web app只进行查询,缩短页面响应时间,改善用户体验。

PS: 后改用aws ec2 t2.micro服务器处理图像识别任务,效率大大提升,每小时可处理大约100 km2区域,涵盖3000+ poi.

开发环境为WSL - windows subsystem linux, dst. Ubuntu 14 LTS
只有一台电脑,之前是把Ubuntu装在另一个外置固态硬盘里,启动不太方便,
而且Ubuntu的中文输入法调制,shadowsocks配置均以失败告终,为了更顺畅地用
google和stack overflow折中于此。

现阶段发现WSL唯二的不好用的地方是:

  1. python virtualenv部署不成功,可以venv active但是实际lib路径仍为系统路径
  2. 网络层没有开发完全,ifconfig及相关usr/network/interface等设置暂时均无法实现。
    WSL currently does not support NETLINK sockets

代码分析


文件目录,典型的flask文件配置:

1
2
3
4
5
6
7
frontiersolar/
├── app
├── migrations
├── requirements
├── tempfiles
├── tests
└── venv

基于上文中提到的教程,
其中主要变更的内容在app/models.py, app/main/views.py和app/templates/newpages.html

在数据库中新增了一个表,并注入数据。
如果不习惯命令行操作,推荐使用SQLiteStudio, 其GUI操作界面非常友善好用。

在views.py和templates中新增了两个html页面以增补额外的功能。

views.py的部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@main.route('/NEWPAGE1/<username>', methods=['GET', 'POST'])
@login_required
def eagleeye(username):
user = User.query.filter_by(username=username).first_or_404()
return render_template('NEWPAGE1.html', user=user)
@main.route('/NEWPAGE2/<username>', methods=['POST', 'GET'])
@login_required
def roofresult(username):
user = User.query.filter_by(username=username).first_or_404()
if request.method == 'POST':
global coords, clist, coord_list, center_coord
coords = request.get_json(force=True)
clist = [coords['minLat'], coords['minLng'], coords['maxLat'], coords['maxLng'], coords['cLng'], coords['cLat']]
coord_list = Roof.query.filter(Roof.lat.between(clist[0], clist[2]), Roof.lon.between(clist[1], clist[3])).order_by(
"area desc").all()
for roof in coord_list:
db.session.expunge(roof)
center_coord = [clist[4], clist[5]]
return render_template('NEWPAGE2.html', coord_list=coord_list, user=user, center_coord=center_coord)

NEWPAGE.html中的部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
AMap.event.addDomListener(document.getElementById('eargleEye'), 'click', function() {
var drawRectangle = mouseTool.rectangle(); //用鼠标工具画矩形
AMap.event.addListener( mouseTool,'draw',function(e){ //添加事件
var rect = e.obj;
var data = {"minLng" : rect.getBounds().getSouthWest( ).getLng(),
"maxLng" : rect.getBounds().getNorthEast( ).getLng(),
"minLat" : rect.getBounds().getSouthWest( ).getLat(),
"maxLat" : rect.getBounds().getNorthEast( ).getLat(),
"cLng" : rect.getBounds().getCenter( ).getLng(),
"cLat" : rect.getBounds().getCenter( ).getLat()
};
if(confirm("are you sure to submit?"))
{
$.post({
url : "{{ url_for('main.NEWPAGE2', username = current_user.username) }}",
data: JSON.stringify(data),
contentType: 'application/json;charset=UTF-8',
success: function(data) {
top.location.href = "{{ url_for('main.NEWPAGE2', username = current_user.username) }}";
},
async:false
});
}
else
{
mouseTool.close(true);
}
});
}, false);

  • 其中第二个页面为了达成传参的目的,使用了全局变量。
  • 个人使用中感受到的flask的局限,除了form等常规的前后端传参方法外,使用POST方法
    传递json或者xml data相对复杂。
  • 前端由于使用jinja2模板,html文件中除了静态模板文件还包含了大量的js代码,
    个人理解这样把视图和功能混放,不便于后期维护,其二也把功能部分的数据放在了前端,
    可以轻易获取,保密性较差。

trouble shooting


传参

在NEWPAGE1.html中使用ajax的POST方法传参给后端的NEWPAGE2,
NEWPAGE2后端处理完这些参数后把从数据库查询的object返回到NEWPAGE2.html渲染。

初始处理的时候发现NEWPAGE2后端程序会先响应一次POST方法接收数据,再响应一次GET方法发送渲染数据。
且只有在POST方法时才能获取前端传入数据。

POST方法获取json数据并存储计算,GET方法时只要进行到解析json数据的指令就会立即报错终止。
因此必须要写if表达式并且return语句要在if外侧,否则无法完成前端模板渲染。

之前也尝试过把需要传递的参数放入url中传递,天然形成api,但是实际操作过程中需要传递的
参数过多,远超url长度限制,后放弃。

考虑到数据读取的便利性还是希望传入obj进行操作,因此最后选择全局变量的方法处理。
由于现在处于demo阶段,无论是数据库的数据量还是网站访问的人员都不多,
该方法的问题还没有充分暴露,稳定性暂时无法判断。

部署

在测试阶段一般直接使用manage.py对flask app进行管理、运行操作,但是在生产环境中不建议
直接使用flask的内置http接口监听处理访问流量。

因此部署的时候还是建议使用gunicorn启动flask app, 并且使用NGINX对内部服务器进行反向代理。

参考文档:Explore flask

注意原生flask对代理支持不足,需要使用Werkzeug ProxyFix修复代理,详见上文档中ProxyFix section.

前端数据操作

这块暂时也没看到很好的解决方案,最近在学习vuejs, 仿MVVC框架进行进一步的拆分,
由于WSL的支持问题无法使用webpack, 因此也无法体验MEAN框架下完整的功能。

看了一些github上vue + flask的blog方案,但是暂时没有深入探索。

MVVC是否可以做到进一步解耦仍有待实际操作研究。

分享到 评论

Web全栈工程师的自我修养

Web全栈工程师的自我修养

Web全栈工程师的自我修养

中亚kindle电子书活动淘的闲书,趁过年回家坐车的时间看完。读起来的感觉更像是作者的找工作回忆录+工作5年以后的流水账。
整个读下来感觉像是一篇参杂着回忆录的综述。从前端讲到后端,作者很推崇js的理念,实际也多用js做前端工作。

kindle的排版看起来很乱,尤其是引用的部分里的引用书籍封面贴图大小不一,位置各异。

key points

  • 全栈的核心是解决问题,是撸起袖子快速迭代,而不是空想
  • 推荐Linode VPS, 并且强烈推荐自己弄个VPS练手,一方面是熟悉Linux环境,另一方面是熟悉部署调参
  • 校招的时候作品比简历更有价值
  • 设计的基本概念,亲密、对齐、重复、对比
  • DRY原则,3次以上的复用直接解耦为单独的功能,否则为WET. (don’t repeart yourself vs. write everything twice)
  • ​ssh不使用root账号,登陆时尽量用key而不是输入明文密码
  • 早期经典web构架,LAMP - Linux Apache MySQL PHP
  • 要锻炼管理能力,亲力亲为重要并紧急的事情,安排好重要但不紧急的事情的日程,把紧急但不重要的事情分给别人,尽量少花时间在既不重要又不紧急的事情上
  • 锻炼身体,拒绝加班

archive

  • 现在有个试用期的AWS ec2 VPS用着练手,Ubuntu 16 LTS, 已经可以正常使用Linux相关功能
  • 后续读两本书:写给大家看的设计禅与摩托车维修艺术
  • 已经折腾了一个flask + gunicorn, 后续可以折腾的还有很多
分享到 评论

追尾危险,保持车距

如同标题所说,我由于没有保持好车距追尾了,全责。在回家的高速路上的车祸几乎把我所有的计划都打乱,汽车的两面性不得不让我对购车的必要性再次进行评估。

原因回溯

  • 疲劳驾驶
    这次计划凌晨4点出发,中午之前驶出高速拥堵路段尽快地道目的地。结果前一天为了处理项目一直忙到晚上10点回家,后来处理杂事至1点开始睡觉。
    只睡了两个多小时就匆匆上路,再加之夜间行车非常消耗注意力,最终导致反应力迟钝。

  • 跟车距离不足
    之前上过防御性驾驶的课程,充分知晓4秒距离的必要性,这次盲目相信本车的制动能力,再加之赶时间急于赶路,故意无视了该原则,导致制动距离不足。
    踩死了刹车仍然碰撞前车至对方后保险杠变形,后门变形,自己的车机盖变形,前进气格栅变形,内部支撑结构变形。
    时速超过100 km/h的时候至少要保持3秒车距以留足制动距离。

  • 定速巡航
    距离收费站已经比较近的时候还在使用定速巡航功能且设置巡航速度超过100 km/h, 导致反应时间不足。

  • 其他驾驶习惯
    收费站前拥堵是常态,靠近收费站时没有及时减速。没有拉手刹辅助制动,切记拉手刹时要握紧方向盘。

事故处理流程

  1. 高速车道上停车是非常危险的行为,打双闪,拍照/录像,如果车子已经不能动了,人去应急车道外站着,如果还能动沟通好之后赶紧开到最近的检查点
    或者服务区,如果两者都较远,停应急车道,摆好反光三角,人站到护栏外。

  2. 打12122联络高速交警出警,同时给自己的保险公司打电话上报事故。

  3. 等交警来现场出事故认定书

  4. 由于保险公司的车不上高架,如果还能开就跟事故相关车协调下高速联络当地的保险公司服务人员去高速出口现场交涉,确定报案号和定损方案。

  5. 一般是后续各自开到维修的4s店或者保险公司认可的维修店进行维修的时候联络保险公司,一般有驻店的相关保险公司现场处理人员协同进行定损。

  6. 按维修点的流程检查签字,等修好。

  7. 如果2车发生事故且自己是全责的状况下,对方的定损维修费用需要这边出,后拼发票到自己保险公司报销。

  8. 预计明年会涨保费…

总结

这次由于没办法年前修车,计划全乱,处理完事件该路段高速向我们目的地方向的入口由于事故过多直接封闭了。
最后到达目的地的时间已经比预计的晚太多,还不如上午多休息一会。
为了善后还要租车把东西和人都搬回家,春节期间不仅租车费用高,更有可能根本没车可租。

不幸发生了这件事,有幸人都没事,车还能坚持住把我们带回家。

切勿疲劳驾驶,切勿疲劳驾驶,切勿疲劳驾驶。

如果以后换车,我还是会选马自达。

分享到 评论

single page tool kit by vue

给过年回家的自己定一个小目标,使用vue开发一个单页面小应用。

应用主要实现2个功能,其一是为了复刻光伏开发速算的功能,其二是为了拓展aircase的分销渠道。
同时也借此熟悉前端开发的工作,希望之后也把icarus blog的主题更新为vue like.

WSL暂时不支持webpack相关网络接口,构架方案需要更换。
—————– 分割线 —————–

todo:

  1. 挂linux系统开发
  2. 把树莓派复活用VNC开发
  3. 买个NMB… (<-实力作死)

—————– Feb 4 2017
跟随LARAVIST视频学习vue 1.0相关知识内容,
课程虽然短但是演示内容比较直白容易理解。

目前进度学到episode 4, 内容只覆盖到前端页面内的功能应用。之后更想看到的内容为MVVC的具体分层,数据库链接还有和后端的互动,部署。

分享到 评论