Quantcast
Channel: CSDN博客推荐文章
Viewing all 35570 articles
Browse latest View live

python: hasattr()、setattr()、getattr()、delattr() 内建函数

$
0
0

Func

Func 语法 作用 retype
hasattr hasattr(object, name) 判断 对象中是否含有 该属性。 True / False
setattr setattr(object, name, values) 给对象的属性 赋值,若属性不存在,先创建再赋值。 None
getattr getattr(object, name[,default]) 获取 属性数值。 属性存在时,返回 属性数值;否则根据 默认输出值 返回 或 报 AttributeError。
delattr delattr(object, name) 删除属性。 属性存在则无返回,否则报 AttributeError。

实验代码

# -*- coding: utf-8 -*-

class test():
    city = 'Nanjing'
    def run(self):
        return 'Hello Nanjing'

t = test()


############################################################
#                   hasattr(object, name)
############################################################
# hasattr 只单纯地 返回 True 或 False。用于判断 对象中是否含有 该属性。
assert hasattr(t, 'city') == True
assert hasattr(t, 'capital') == False


############################################################
#               setattr(object, name, values)
############################################################
# setattr 没有 返回。给对象的属性赋值,若属性不存在,先创建再赋值。
assert not hasattr(t, 'capital')
setattr(t, 'capital', 'Jiangshu')
assert hasattr(t, 'capital')


############################################################
#               getattr(object, name[,default])
############################################################
# getattr 在属性 存在 时,返回 属性数值
assert getattr(t, 'city') == 'Nanjing'
assert getattr(t, 'run')

# getattr 在属性 不存在 时,有 指定默认输出值 的情况下,返回 默认输出值
assert getattr(t, 'year', 'Not found') == 'Not found'

# getattr 在属性 不存在 时,没有 指定默认输出值 的情况下,返回 AttributeError
try:
    getattr(t, 'year')
except AttributeError:
    pass

# getattr 和 setattr 的联合使用
assert getattr(t, 'year', setattr(t, 'year', '2017')) == '2017'
assert getattr(t, 'year') == '2017'


############################################################
#               delattr(object, name)
############################################################
# delattr 没有 返回。若属性 存在,则删除之。
assert hasattr(t, 'year')
delattr(t, 'year')
assert not hasattr(t, 'year')

# delattr 没有 返回。若属性 不存在,则报 AttributeError。
try:
    delattr(t, 'year')
except AttributeError:
    pass


作者:JNingWei 发表于2017/11/17 11:15:04 原文链接
阅读:83 评论:0 查看评论

[python爬虫] BeautifulSoup和Selenium简单爬取知网信息测试

$
0
0

作者最近在研究复杂网络和知识图谱内容,准备爬取知网论文相关信息进行分析,包括标题、摘要、出版社、年份、下载数和被引用数、作者信息等。但是在爬取知网论文时,遇到问题如下:
  1.爬取内容总为空,其原因是采用动态加载的数据,无法定位,然后作者重新选取了CNKI3.0知网进行了爬取;
  2.但却不含作者信息,需要定位到详情页面,再依次获取作者信息,但是又遇到了新的问题。


一. 网站定位分析

知网网站如下:http://nvsm.cnki.net/kns/brief/default_result.aspx
比如搜索Python关键字,网页反馈内容如下所示,2681篇文章。


但是使用Selenium定位爬取的论文内容总为空,后来网上看到qiuqingyun大神的博客,发现另一个知网接口(CNKI3.0 知识搜索:http://search.cnki.net/)。
强烈推荐大家阅读他的原文:http://qiuqingyu.cn/2017/04/27/python实现CNKI知网爬虫/
搜索python的的图片如下,共3428篇论文。


接下来简单讲述分析的过程,方法都类似,通过DOM树节点分析定位元素。右键浏览器审查元素如下所示,每页包括15篇论文,标签位于<div class="wz_tab">下。


点击具体一条内容,如下所示,定位方法如下:
  1.标题定位<div class="wz_content">下的<h3>标签,并且可以获取URL;
  2.摘要定位<div class="width715">内容;
  3.出处定位<span class="year-count">节点下的title,年份通过正则表达式提取数据;
  4.下载次数和被引用数定位<span class="count">,提取数字第一个和第二个。



接下来直接讲述BeautifulSoup和Selenium两种方式的爬虫。



二. BeautifulSoup爬虫

BeautifulSoup完整代码如下:

# -*- coding: utf-8 -*-
import time              
import re
import urllib   
from bs4 import BeautifulSoup
      
    
#主函数
if __name__ == '__main__':

    url = "http://search.cnki.net/Search.aspx?q=python&rank=relevant&cluster=all&val=&p=0"
    content = urllib.urlopen(url).read()
    soup = BeautifulSoup(content,"html.parser")

    #定位论文摘要
    wz_tab = soup.find_all("div",class_="wz_tab")
    num = 0
    for tab in wz_tab:
        #标题
        title = tab.find("h3")
        print title.get_text()
        urls = tab.find("h3").find_all("a")
        #详情超链接
        flag = 0
        for u in urls:
            if flag==0: #只获取第一个URL
                print u.get('href')
                flag += 1
        #摘要
        abstract = tab.find(attrs={"class":"width715"}).get_text()
        print abstract
        #获取其他信息
        other = tab.find(attrs={"class":"year-count"})
        content = other.get_text().split("\n")
        """
            由于无法分割两个空格,如:《怀化学院学报》  2017年 第09期
            故采用获取标题titile内容为出版杂志
            <span title="北方文学(下旬)">《北方文学(下旬)》  2017年 第06期</span>
        """
        #出版杂志+年份
        cb_from = other.find_all("span")
        flag = 0 
        for u in cb_from:
            if flag==0: #获取标题
                print u.get("title")
                flag += 1
        mode = re.compile(r'\d+\.?\d*')
        number = mode.findall(content[0])
        print number[0] #年份
        
        #下载次数 被引次数
        mode = re.compile(r'\d+\.?\d*')
        number = mode.findall(content[1])
        if len(number)==1:
            print number[0]
        elif len(number)==2:
            print number[0], number[1]

        num = num + 1
输出如下图所示:


但是爬取的URL无法跳转,总是显示登录页面,比如“http://epub.cnki.net/kns/detail/detail.aspx?filename=DZRU2017110705G&dbname=CAPJLAST&dbcode=cjfq”,而能正确显示的是的“http://www.cnki.net/KCMS/detail/detail.aspx?filename=DZRU2017110705G&
dbname=CAPJLAST&dbcode=CJFQ&urlid=&yx=&v=MTc2ODltUm42ajU3VDN
mbHFXTTBDTEw3UjdxZVlPZHVGeTdsVXJ6QUpWZz1JVGZaZbzlDWk81NFl3OU16”。
显示如下图所示:


解决方法:这里我准备采用Selenium技术定位超链接,再通过鼠标点击进行跳转,从而去到详情页面获取作者或关键词信息。


三. Selenium爬虫

爬取代码如下:

# -*- coding: utf-8 -*-
import time              
import re              
import sys    
import codecs    
import urllib   
from selenium import webdriver            
from selenium.webdriver.common.keys import Keys            
  
      
#主函数
if __name__ == '__main__':

    url = "http://search.cnki.net/Search.aspx?q=python&rank=relevant&cluster=all&val=&p=0"
    driver = webdriver.Firefox()
    driver.get(url)
    #标题
    content = driver.find_elements_by_xpath("//div[@class='wz_content']/h3")
    #摘要
    abstracts = driver.find_elements_by_xpath("//div[@class='width715']")
    #出版杂志+年份
    other = driver.find_elements_by_xpath("//span[@class='year-count']/span[1]")
    mode = re.compile(r'\d+\.?\d*')
    #下载次数 被引次数
    num = driver.find_elements_by_xpath("//span[@class='count']")

    #获取内容
    i = 0
    for tag in content:
        print tag.text
        print abstracts[i].text
        print other[i].get_attribute("title")
        number = mode.findall(other[i].text)
        print number[0] #年份
        number = mode.findall(num[i].text)
        if len(number)==1: #由于存在数字确实 如(100) ()
            print number[0]
        elif len(number)==2:
            print number[0],number[1]
        print ''
        
        i = i + 1
        tag.click()
        time.sleep(1)
输出如下所示:
>>> 
网络资源辅助下的Python程序设计教学 
本文对于Python学习网络资源做了归纳分类,说明了每类资源的特点,具体介绍了几个有特色的学习网站,就网络资源辅助下的Python学习进行了讨论,阐释了利用优质网络资源可以提高课堂教学效果,增加教学的生动性、直观性和交互性。同时说明了这些资源的利用能够方便学生的编程训练,使学生有更多的时间和机会动手编程,实现编程教学中...
电子技术与软件工程
2017
11 0

Python虚拟机内存管理的研究 
动态语言的简洁性,易学性缩短了软件开发人员的开发周期,所以深受研发人员的喜爱。其在机器学习、科学计算、Web开发等领域都有广泛的应用。在众多的动态语言中,Python是用户数量较大的动态语言之一。本文主要研究Python对内存资源的管理。Python开发效率高,但是运行效率常为人诟病,主要原因在于一切皆是对象的语言实现...
南京大学
2014
156 0
接下来是点击详情页面,窗口转化捕获信息,代码如下:
# -*- coding: utf-8 -*-
import time              
import re              
import sys    
import codecs    
import urllib   
from selenium import webdriver            
from selenium.webdriver.common.keys import Keys            
  
      
#主函数
if __name__ == '__main__':

    url = "http://search.cnki.net/Search.aspx?q=python&rank=relevant&cluster=all&val=&p=0"
    driver = webdriver.Firefox()
    driver.get(url)
    #标题
    content = driver.find_elements_by_xpath("//div[@class='wz_content']/h3")
    #摘要
    abstracts = driver.find_elements_by_xpath("//div[@class='width715']")
    #出版杂志+年份
    other = driver.find_elements_by_xpath("//span[@class='year-count']/span[1]")
    mode = re.compile(r'\d+\.?\d*')
    #下载次数 被引次数
    num = driver.find_elements_by_xpath("//span[@class='count']")

    #获取当前窗口句柄  
    now_handle = driver.current_window_handle

    #获取内容
    i = 0
    for tag in content:
        print tag.text
        print abstracts[i].text
        print other[i].get_attribute("title")
        number = mode.findall(other[i].text)
        print number[0] #年份
        number = mode.findall(num[i].text)
        if len(number)==1: #由于存在数字确实 如(100) ()
            print number[0]
        elif len(number)==2:
            print number[0],number[1]
        print ''
        
        i = i + 1
        tag.click()
        time.sleep(2)

        #跳转 获取所有窗口句柄  
        all_handles = driver.window_handles  
      
        #弹出两个界面,跳转到不是主窗体界面  
        for handle in all_handles:  
            if handle!=now_handle:     
                #输出待选择的窗口句柄  
                print handle  
                driver.switch_to_window(handle)  
                time.sleep(1)  
  
                print u'弹出界面信息'  
                print driver.current_url  
                print driver.title  
  
                #获取登录连接信息  
                elem_sub = driver.find_element_by_xpath("//div[@class='summary pad10']")  
                print u"作者", elem_sub.text   
                print ''  
  
                #关闭当前窗口  
                driver.close()  
              
        #输出主窗口句柄  
        print now_handle  
        driver.switch_to_window(now_handle) #返回主窗口 开始下一个跳转
        
但部分网站还是出现无法访问的问题,如下所示:


最后作者拟爬取万方数据进行分析。
最后希望文章对你有所帮助,如果错误或不足之处,请海涵~
(By:Eastmount 2017-11-17 深夜12点  http://blog.csdn.net/eastmount/ )



作者:Eastmount 发表于2017/11/17 11:16:57 原文链接
阅读:124 评论:3 查看评论

Linux学习总结(43)——企业运维最常用的150个Linux命令

$
0
0
一、线上查询及帮助命令 (2 个)
man
查看命令帮助,命令的词典,更复杂的还有 info,但不常用。
help
查看 Linux 内置命令的帮助,比如 cd 命令。


二、文件和目录操作命令 (18 个)
ls
全拼 list,功能是列出目录的内容及其内容属性信息。
cd
全拼 change directory,功能是从当前工作目录切换到指定的工作目录。
cp
全拼 copy,其功能为复制文件或目录。
find
查找的意思,用于查找目录及目录下的文件。
mkdir
全拼 make directories,其功能是创建目录。
mv
全拼 move,其功能是移动或重命名文件。
pwd
全拼 print working directory,其功能是显示当前工作目录的绝对路径。
rename
用于重命名文件。
rm
全拼 remove,其功能是删除一个或多个文件或目录。
rmdir
全拼 remove empty directories,功能是删除空目录。
touch
创建新的空文件,改变已有文件的时间戳属性。
tree
功能是以树形结构显示目录下的内容。
basename
显示文件名或目录名。
dirname
显示文件或目录路径。
chattr
改变文件的扩展属性。
lsattr
查看文件扩展属性。
file
显示文件的类型。
md5sum
计算和校验文件的 MD5 值。


三、查看文件及内容处理命令(21 个)
cat
全拼 concatenate,功能是用于连接多个文件并且打印到屏幕输出或重定向到指定文件中。
tac
tac 是 cat 的反向拼写,因此命令的功能为反向显示文件内容。
more
分页显示文件内容。
less
分页显示文件内容,more 命令的相反用法。
head
显示文件内容的头部。
tail
显示文件内容的尾部。
cut
将文件的每一行按指定分隔符分割并输出。
split
分割文件为不同的小片段。
paste
按行合并文件内容。
sort
对文件的文本内容排序。
uniq
去除重复行。oldboy
wc
统计文件的行数、单词数或字节数。
iconv
转换文件的编码格式。
dos2unix
将 DOS 格式文件转换成 UNIX 格式。
diff
全拼 difference,比较文件的差异,常用于文本文件。
vimdiff
命令行可视化文件比较工具,常用于文本文件。
rev
反向输出文件内容。
grep/egrep
过滤字符串,三剑客老三。
join
按两个文件的相同字段合并。
tr
替换或删除字符。
vi/vim
命令行文本编辑器。


四、文件压缩及解压缩命令(4 个)
tar
打包压缩。oldboy
unzip
解压文件。
gzip
gzip 压缩工具。
zip
压缩工具。


五、信息显示命令(11 个)
uname
显示操作系统相关信息的命令。
hostname
显示或者设置当前系统的主机名。
dmesg
显示开机信息,用于诊断系统故障。
uptime
显示系统运行时间及负载。
stat
显示文件或文件系统的状态。
du
计算磁盘空间使用情况。
df
报告文件系统磁盘空间的使用情况。
top
实时显示系统资源使用情况。
free
查看系统内存。
date
显示与设置系统时间。
cal
查看日历等时间信息。


六、搜索文件命令(4 个)
which
查找二进制命令,按环境变量 PATH 路径查找。
find
从磁盘遍历查找文件或目录。
whereis
查找二进制命令,按环境变量 PATH 路径查找。
locate
从数据库 (/var/lib/mlocate/mlocate.db) 查找命令,使用 updatedb 更新库。


七、用户管理命令(10 个)
useradd
添加用户。
usermod
修改系统已经存在的用户属性。
userdel
删除用户。
groupadd
添加用户组。
passwd
修改用户密码。
chage
修改用户密码有效期限。
id
查看用户的 uid,gid 及归属的用户组。
su
切换用户身份。
visudo
编辑 / etc/sudoers 文件的专属命令。
sudo
以另外一个用户身份(默认 root 用户)执行事先在 sudoers 文件允许的命令。


八、基础网络操作命令(11 个)
telnet
使用 TELNET 协议远程登录。
ssh
使用 SSH 加密协议远程登录。
scp
全拼 secure copy,用于不同主机之间复制文件。
wget
命令行下载文件。
ping
测试主机之间网络的连通性。
route
显示和设置 linux 系统的路由表。
ifconfig
查看、配置、启用或禁用网络接口的命令。
ifup
启动网卡。
ifdown
关闭网卡。
netstat
查看网络状态。
ss
查看网络状态。


九、深入网络操作命令(9 个)
nmap
网络扫描命令。
lsof
全名 list open files,也就是列举系统中已经被打开的文件。
mail
发送和接收邮件。
mutt
邮件管理命令。
nslookup
交互式查询互联网 DNS 服务器的命令。
dig
查找 DNS 解析过程。
host
查询 DNS 的命令。
traceroute
追踪数据传输路由状况。
tcpdump
命令行的抓包工具。


十、有关磁盘与文件系统的命令(16 个)
mount
挂载文件系统。
umount
卸载文件系统。
fsck
检查并修复 Linux 文件系统。
dd
转换或复制文件。
dumpe2fs
导出 ext2/ext3/ext4 文件系统信息。
dump
ext2/3/4 文件系统备份工具。
fdisk
磁盘分区命令,适用于 2TB 以下磁盘分区。
parted
磁盘分区命令,没有磁盘大小限制,常用于 2TB 以下磁盘分区。
mkfs
格式化创建 Linux 文件系统。
partprobe
更新内核的硬盘分区表信息。
e2fsck
检查 ext2/ext3/ext4 类型文件系统。
mkswap
创建 Linux 交换分区。
swapon
启用交换分区。
swapoff
关闭交换分区。
sync
将内存缓冲区内的数据写入磁盘。
resize2fs
调整 ext2/ext3/ext4 文件系统大小。


十一、系统权限及用户授权相关命令(4 个)

chmod
改变文件或目录权限。
chown
改变文件或目录的属主和属组。
chgrp
更改文件用户组。
umask
显示或设置权限掩码。


十二、查看系统用户登陆信息的命令(7 个)
whoami
显示当前有效的用户名称,相当于执行 id -un 命令。
who
显示目前登录系统的用户信息。
w
显示已经登陆系统的用户列表,并显示用户正在执行的指令。
last
显示登入系统的用户。
lastlog
显示系统中所有用户最近一次登录信息。
users
显示当前登录系统的所有用户的用户列表。
finger
查找并显示用户信息。


十三、内置命令及其它(19 个)
echo
打印变量,或直接输出指定的字符串
printf
将结果格式化输出到标准输出。
rpm
管理 rpm 包的命令。
yum
自动化简单化地管理 rpm 包的命令。
watch
周期性的执行给定的命令,并将命令的输出以全屏方式显示。
alias
设置系统别名。
unalias
取消系统别名。
date
查看或设置系统时间。
clear
清除屏幕,简称清屏。
history
查看命令执行的历史纪录。
eject
弹出光驱。
time
计算命令执行时间。
nc
功能强大的网络工具。
xargs
将标准输入转换成命令行参数。
exec
调用并执行指令的命令。
export
设置或者显示环境变量。
unset
删除变量或函数。
type
用于判断另外一个命令是否是内置命令。
bc
命令行科学计算器


十四、系统管理与性能监视命令 (9 个)
chkconfig
管理 Linux 系统开机启动项。
vmstat
虚拟内存统计。
mpstat
显示各个可用 CPU 的状态统计。
iostat
统计系统 IO。
sar
全面地获取系统的 CPU、运行队列、磁盘 I/O、分页(交换区)、内存、 CPU 中断和网络等性能数据。
ipcs
用于报告 Linux 中进程间通信设施的状态,显示的信息包括消息列表、共享内存和信号量的信息。
ipcrm
用来删除一个或更多的消息队列、信号量集或者共享内存标识。
strace
用于诊断、调试 Linux 用户空间跟踪器。我们用它来监控用户空间进程和内核的交互,比如系统调用、信号传递、进程状态变更等。
ltrace
命令会跟踪进程的库函数调用, 它会显现出哪个库函数被调用。


十五、关机 / 重启 / 注销和查看系统信息的命令(6 个)
shutdown
关机。
halt
关机。
poweroff
关闭电源。
logout
退出当前登录的 Shell。
exit
退出当前登录的 Shell。
Ctrl+d
退出当前登录的 Shell 的快捷键。


十六、进程管理相关命令(15 个)
bg
将一个在后台暂停的命令,变成继续执行  (在后台执行)。
fg
将后台中的命令调至前台继续运行。
jobs
查看当前有多少在后台运行的命令。
kill
终止进程。
killall
通过进程名终止进程。
pkill
通过进程名终止进程。
crontab
定时任务命令。
ps
显示进程的快照。
pstree
树形显示进程。
nice/renice
调整程序运行的优先级。
nohup
忽略挂起信号运行指定的命令。
pgrep
查找匹配条件的进程。
runlevel
查看系统当前运行级别。
init
切换运行级别。
service
启动、停止、重新启动和关闭系统服务,还可以显示所有系统服务的当前状态。
作者:u012562943 发表于2017/11/17 11:25:27 原文链接
阅读:107 评论:0 查看评论

itext7学习笔记——第5章实践&example

$
0
0

    本章的例子,请参考我翻译的博文:itext7学习笔记——第5章,里面有详细的解释,有什么不懂得也可以评论或者私信我!

## 例子1:添加注释和内容

    我们读取一个带有表单的PDF文档,往里面添加文档注释、一些文本和一个新的复选框,代码如下:

import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfButtonFormField;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.io.font.FontConstants;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfString;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.action.PdfAction;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
import com.itextpdf.kernel.pdf.annot.PdfTextAnnotation;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import java.io.File;
import java.io.IOException;

/**
 * Simple adding annotations example.
 */
public class C05E01_AddAnnotationsAndContent {

    public static final String SRC = "src/main/resources/pdf/job_application.pdf";
    public static final String DEST = "results/chapter05/edited_job_application.pdf";

    public static void main(String args[]) throws IOException {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
        new C05E01_AddAnnotationsAndContent().manipulatePdf(SRC, DEST);
    }

    public void manipulatePdf(String src, String dest) throws IOException {

        //Initialize PDF document
        PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest));

        //Add text annotation
        PdfAnnotation ann = new PdfTextAnnotation(new Rectangle(400, 795, 0, 0))
                .setTitle(new PdfString("iText"))
                .setContents("Please, fill out the form.")
                .setOpen(true);
        pdfDoc.getFirstPage().addAnnotation(ann);

        PdfCanvas canvas = new PdfCanvas(pdfDoc.getFirstPage());
        canvas.beginText().setFontAndSize(PdfFontFactory.createFont(FontConstants.HELVETICA), 12)
                .moveText(265, 597)
                .showText("I agree to the terms and conditions.")
                .endText();

        //Add form field
        PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
        PdfButtonFormField checkField = PdfFormField.createCheckBox(pdfDoc, new Rectangle(245, 594, 15, 15),
                "agreement", "Off", PdfFormField.TYPE_CHECK);
        checkField.setRequired(true);
        form.addField(checkField);

        //Update reset button
        form.getField("reset").setAction(PdfAction.createResetForm(new String[]{"name", "language",
                "experience1", "experience2", "experience3", "shift", "info", "agreement"}, 0));

        pdfDoc.close();

    }
}

## 例子2:改变表单字段属性

    我们读取一个带有表单的PDF文档,然后改变字段的属性,添加属性或者删除属性,代码如下:

import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.io.font.FontConstants;
import com.itextpdf.kernel.color.Color;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.*;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Simple filling out form example.
 */
public class C05E02_FillAndModifyForm {

    public static final String SRC = "src/main/resources/pdf/job_application.pdf";
    public static final String DEST = "results/chapter05/filled_out_job_application.pdf";

    public static void main(String args[]) throws IOException {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
        new C05E02_FillAndModifyForm().manipulatePdf(SRC, DEST);
    }

    public void manipulatePdf(String src, String dest) throws IOException {

        //Initialize PDF document
        PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest));


        PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
        Map<String, PdfFormField> fields = form.getFormFields();

        fields.get("name").setValue("James Bond").setBackgroundColor(Color.ORANGE);
        fields.get("language").setValue("English");

        fields.get("experience1").setValue("Yes");
        fields.get("experience2").setValue("Yes");
        fields.get("experience3").setValue("Yes");

        List<PdfString> options = new ArrayList<PdfString>();
        options.add(new PdfString("Any"));
        options.add(new PdfString("8.30 am - 12.30 pm"));
        options.add(new PdfString("12.30 pm - 4.30 pm"));
        options.add(new PdfString("4.30 pm - 8.30 pm"));
        options.add(new PdfString("8.30 pm - 12.30 am"));
        options.add(new PdfString("12.30 am - 4.30 am"));
        options.add(new PdfString("4.30 am - 8.30 am"));
        PdfArray arr = new PdfArray(options);
        fields.get("shift").setOptions(arr);
        fields.get("shift").setValue("Any");

        PdfFont courier = PdfFontFactory.createFont(FontConstants.COURIER);
        fields.get("info").setValue("I was 38 years old when I became an MI6 agent.", courier, 7f);

        pdfDoc.close();

    }
}

## 例子3:添加页眉、页脚和水印

    我们读取一个带有ufo信息的PDF文档,往里面添加页眉、页脚和水印,代码如下:

import com.itextpdf.io.font.FontConstants;
import com.itextpdf.kernel.color.Color;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.extgstate.PdfExtGState;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.VerticalAlignment;

import java.io.File;
import java.io.IOException;

/**
 * Simple adding content example.
 */
public class C05E03_AddContent {

    public static final String SRC = "src/main/resources/pdf/ufo.pdf";

    public static final String DEST = "results/chapter05/add_content.pdf";

    public static void main(String args[]) throws IOException {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
        new C05E03_AddContent().manipulatePdf(SRC, DEST);
    }

    public void manipulatePdf(String src, String dest) throws IOException {

        //Initialize PDF document
        PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest));

        Document document = new Document(pdfDoc);
        Rectangle pageSize;
        PdfCanvas canvas;
        int n = pdfDoc.getNumberOfPages();
        for (int i = 1; i <= n; i++) {
            PdfPage page = pdfDoc.getPage(i);
            pageSize = page.getPageSize();
            canvas = new PdfCanvas(page);
            //Draw header text
            canvas.beginText().setFontAndSize(PdfFontFactory.createFont(FontConstants.HELVETICA), 7)
                    .moveText(pageSize.getWidth() / 2 - 24, pageSize.getHeight() - 10)
                    .showText("I want to believe")
                    .endText();
            //Draw footer line
            canvas.setStrokeColor(Color.BLACK)
                    .setLineWidth(.2f)
                    .moveTo(pageSize.getWidth() / 2 - 30, 20)
                    .lineTo(pageSize.getWidth() / 2 + 30, 20).stroke();
            //Draw page number
            canvas.beginText().setFontAndSize(PdfFontFactory.createFont(FontConstants.HELVETICA), 7)
                    .moveText(pageSize.getWidth() / 2 - 7, 10)
                    .showText(String.valueOf(i))
                    .showText(" of ")
                    .showText(String.valueOf(n))
                    .endText();
            //Draw watermark
            Paragraph p = new Paragraph("CONFIDENTIAL").setFontSize(60);
            canvas.saveState();
            PdfExtGState gs1 = new PdfExtGState().setFillOpacity(0.2f);
            canvas.setExtGState(gs1);
            document.showTextAligned(p,
                    pageSize.getWidth() / 2, pageSize.getHeight() / 2,
                    pdfDoc.getPageNumber(page),
                    TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45);
            canvas.restoreState();
        }

        pdfDoc.close();

    }
}

## 例子4:改变页面大小和方向

    我们读取一个带有ufo信息的PDF文档,改变每一页的大小,并使偶数页颠倒,代码如下:

import com.itextpdf.kernel.color.*;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.*;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;

import java.io.File;
import java.io.IOException;

/**
 * Simple changing page properties example.
 */
public class C05E04_ChangePage {

    public static final String SRC = "src/main/resources/pdf/ufo.pdf";
    public static final String DEST = "results/chapter05/change_page.pdf";

    public static void main(String args[]) throws IOException {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
        new C05E04_ChangePage().manipulatePdf(SRC, DEST);
    }

    public void manipulatePdf(String src, String dest) throws IOException {

        //Initialize PDF document
        PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest));


        float margin = 72;
        for (int i = 1; i <= pdfDoc.getNumberOfPages(); i++) {
            PdfPage page = pdfDoc.getPage(i);
            // change page size
            Rectangle mediaBox = page.getMediaBox();
            Rectangle newMediaBox = new Rectangle(mediaBox.getLeft() - margin, mediaBox.getBottom() - margin,
                    mediaBox.getWidth() + margin * 2, mediaBox.getHeight() + margin * 2);
            page.setMediaBox(newMediaBox);
            // add border
            PdfCanvas over = new PdfCanvas(page);
            over.setStrokeColor(Color.GRAY);
            over.rectangle(mediaBox.getLeft(), mediaBox.getBottom(), mediaBox.getWidth(), mediaBox.getHeight());
            over.stroke();
            // change rotation of the even pages
            if (i % 2 == 0) {
                page.setRotation(180);
            }
        }

        pdfDoc.close();

    }
}

Example代码下载

    本章代码可在如下地址下载(IDEA工程):iText7——第五章源代码工程

作者:u012397189 发表于2017/11/17 11:26:43 原文链接
阅读:95 评论:0 查看评论

Rosonblatt线性感知器

$
0
0

前叙

读前简介

机器学习的流派很多,现在比较流行的便是联结学派,其计算的重点在于权重更新,而其它学派比如贝叶斯学派,基于统计学,进化学派则注重结构学习.

本篇博客以线性感知器为基础,将会对神经网络与一些机器学习算法进行介绍,如果你只想简单的了解,那么可以浏览一遍即可,当然你也可以花费些时间读这篇文章,那么你也可以受益许多.

神经网络与联结学派

神经网络就是联结学派的”作品”,从最基本的线性感知器到现在的深度学习都隶属于联结学派,其实现人工智能的思想在于利用计算机模拟生物神经网络,而计算过程最后则转化为求最优解问题,计算过程的核心则在于迭代与权值更新,主要陷阱为局部最优解陷阱等等.

而联结学派的核心观点即为:智能的本质是连接机制,神经网络是一个由大量简单的处理单元组成的高度复杂的大规模非线性自适应系统.联结主义模拟人脑智能行为四个层面为: 
a.物理结构; 
b.计算模拟 
c.存储与操作 
d.训练

神经网络图解:

神经网络图解

Rosonblatt感知器图解

Rosonblatt感知器图解

基本计算过程与权值修正

基本计算过程:

  1. 数据输入
  2. 计算诱导局部域,计算公式如下 
    这里写图片描述
    最后求出的超平面: 
    Resenblatt感知器中的超平面
  3. 诱导局部域输入输出函数(硬限幅函数sgn()),并输出最后结果
# 硬限幅函数 python语言
def sgn(v):
    if v> 0:
        return 1
    else:
        return -1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

权值更新(图片来自他处):

感知器收敛算法

代码

# 单样本感知器算法
import numpy as np
b = 1 # 偏置
# 该数据量下 初始权值为 0 时 Rosebblatt感知器 训练失败
a = 0.3 # 学习率
x = np.array([[1,1,3],[1,2,5],[1,1,8],[1,2,15],[1,3,7],[1,4,29]])
d = np.array([1,1,-1,-1,1,-1])
w = np.array([b,0,0])
def sgn(v):
    if v> 0:
        return 1
    else:
        return -1
def comy(myw,myx):
    return  sgn(np.dot(myw.T,myx))
def neww(oldw,myd,myx,a):
    print("comy:",comy(oldw,myx))
    return oldw+a*(myd - comy(oldw,myx))*myx
i = 0
for xn in x:
    print("wn:",xn)
    w =neww(w,d[i],xn,a)
    i+=1
    print("w:",w)
for xn in x:
    print("%d or %d => %d"%(xn[1],xn[2],comy(w,xn)))
test = np.array([b,9,19])
print("%d or %d => %d"%(test[1],test[2],comy(w,test)))
test = np.array([b,9,64])
print("%d or %d => %d"%(test[1],test[2],comy(w,test)))
  • 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

梯度下降与批量修正算法

公式如下(图片来自书籍):

这里写图片描述

具体算法过程如下: 
1) 初始化权值.学习率,以及期望误差率 
2) 读取所有样本数据 
3) 依次对样本进行训练.更新权值,其更新策略如(8-1)所示 
4) 检查误差率是否小于指定误差率,或者训练次数已达到,否则转到第二步执行

code

import numpy as np
b = 1 # 偏置
# 该数据量下 初始权值为 0 时 Rosebblatt感知器 训练失败
a = 0.5 # 学习率
x = np.array([[1,1,3],[1,2,5],[1,1,8],[1,2,15]])
d = np.array([1,1,-1,-1])
w = np.array([b,0,0])
wucha = 0
ddcount = 50
def sgn(v):
    if v> 0:
        return 1
    else:
        return -1
def comy(myw,myx):
    return  sgn(np.dot(myw.T,myx))
# 权值更新策略
def tiduxz(myw,myx,mya):
    i = 0
    sum_x =np.array([0,0,0])
    for xn in myx:
        if comy(myw,xn)!=d[i]:
            sum_x+=d[i]*xn
        i+=1
    return mya*sum_x
i = 0
while True:
    tdxz = tiduxz(w,x,a)
    print('tdxz:',tdxz)
    w = w+tdxz
    print("w:",w)
    i = i+1
    if abs(tdxz.sum())<=wucha or i >= ddcount:break
test = np.array([1,9,19])
print("%d or %d => %d"%(test[1],test[2],comy(w,test)))
test = np.array([1,3,22])
print("%d or %d => %d"%(test[1],test[2],comy(w,test)))
print()
  • 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

Rosonblatt感知器 优化

LMS(最小均方算法:Least-Mean-Square)

均方误差MSE:参数估计中均方误差是指参数估计值与参数真值之差平方的期望值,即样本预测输出值与实际输出值之差平方的期望值.

而MSE的策略则是使MSE最小, 
代价函数: 
LMS的代价函数 
在之前的例子中继续使用批量修正算法,并在其误差信号基础上计算梯度向量: 
在其误差信号基础上计算梯度向量 
权值生成方案: 
权值生成方案

# 代码来自<机器学习实践指南2>
import numpy as np
# LMS算法实现逻辑或运算
b = 1 # 偏置
# 该数据量下 初始权值为 0 时 Rosebblatt感知器 训练失败
a = 0.1 # 学习率
x = np.array([[1,1,1],[1,1,0],[1,0,1],[1,0,0]])
d = np.array([1,1,1,0])
w = np.array([b,0,0])
expect_e=0.005
maxtrycount=20
def sgn(v):
    if v> 0:
        return 1
    else:
        return 0
def get_v(myw,myx):
    return sgn(np.dot(myw.T,myx))
def neww(oldw,myd,myx,a):
    mye = get_e(oldw,myx,myd)
    return (oldw+a*mye*myx,mye)
def get_e(myw,myx,myd):
    return myd-get_v(myw,myx) # 实际输出值 - 样本预测输出值
mycount = 0
while True:
    mye = 0
    i = 0
    for xn in x:
        w,e = neww(w, d[i], xn, a)
        i+=1
        mye+=pow(e,2) # 在 ANN 领域 MSE(均方误差)是指样本预测输出至于实际输出值之差平方的期望
    mye/=float(i)
    mycount+=1
    print(u"第 %d 次调整后的权值:"%mycount)
    print("w:",w)
    print(u"误差: %f "%mye)
    if abs(mye) < expect_e or mycount > maxtrycount:break
for xn in x:
    print("%d or %d => %d"%(xn[1],xn[2],get_v(w,xn)))
  • 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

LMS退火算法

LMS算法的一个限制在于学习率的设定: 
当学习率较大时,收敛速度较快 
当学习率较小时才能保证权值的修正是再让代价函数一步比一步小 
因而比较科学的方法应该是学习率随着权值的不断修改而不断减小,于是便有了LMS退火算法,其公式如下: 
LMS退火算法中学习率的变化公式

退火算法原理源于固体退火原理,其为基于蒙特卡罗迭代求解法的一种启发式随机搜索过程

修改之前的例子:

a0 = 0.1
a = 0.0
def neww(oldw,myd,myx,a):
    mye = get_e(oldw,myx,myd)
    a=a0/(1+float(mycount)/r)
    return (oldw+a*mye*myx,mye)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Rosonblatt感知机的局限

Rosonblatt感知机的局限在于其本质为一个线性感知机,因此当样本线性不可分时则使用delta法则进行感知机的训练,而delta的关键思想在于使用梯度下降来搜索可能的权向量的假设空间,已找到最佳拟合训练样本的权向量.

通过这种方式可以一定程度上对非线性数据进行分类,但想要解决Rosonblatt感知器无法处理非线性关系(无法学习”异或”逻辑运算)的问题,需要的是双层感知机,或者多层感知机(也就是神经网络),实际上在历史上正是因为Rosonblatt无法学习线性关系才导致了神经网络十几年的低潮,也正是双层感知机找到了异或的学习方法以及传统冯诺依曼计算机模拟智能遇到了不可逾越的瓶颈才再一次掀起了神经网络的热潮.

参考资料

  • [1] 麦好 <机器学习实践指南 案例应用解析 第二版> 机械工业出版社 2017.7
作者:FontThrone 发表于2017/11/17 12:02:18 原文链接
阅读:69 评论:0 查看评论

Cordova App 打包全揭秘

$
0
0

这里写图片描述


本文作者:大师兄(高武军)

现就职于某公司移动端架构师兼产品开发。
主要开发产品:mdn(适配app和微信的移动端解决方案),pageui(移动端ui组件库),formBuilder(可以让前端建表和操作表的表单设计器)。

课程介绍 点击查看原文

Cordova 是一个开源的移动开发框架。允许你用标准的 Web 技术——HTML5,CSS3 和 JavaScript 做跨平台开发。应用在每个平台的具体执行被封装了起来,并依靠符合标准的 API 绑定去访问每个设备的功能。

本课程是一个系列基础教程,目标是带领读者上手实战,你可以掌握和 Cordova 相关环境搭建,创建项目,添加插件等核心技能。随心随意打包自己的 App 应用。


导读:混合开发 APP

近年来随着移动设备类型与操作系统的增多,用户需求也日益增长,因此在项目启动前,大家都会考虑到它的需求、成本、需要投入的时间,自己的团队成员与技术成熟度等一系列因素。在这种情况下,App 的开发方案也尽显多元。

曾经 Html5 有一段小浪潮,很多人看到或参与过这样一个讨论:是选择原生开发、混合开发,还是 Web 开发?究竟哪个才是最佳实践,笔者认为只有实践过的人才知道,尤其是在当今这个充满变数的移动互联网时代。

混合移动应用程序开发的流行

当涉及到移动应用程序开发时,目前还没有一种可以适合所有场景的方式。你可以选择开发本地应用程序、基于网络的移动应用程序或是混合移动应用程序,而在以上选项中,混合移动应用程序开发应该是最具优势的。

那么什么是混合应用程序开发呢?

App 混合开发,顾名思义是一个开发模式,它指的是开发 App 时一部分功能用 native 构建,另一部分功能用 Html5 构建。介于 web-app、native-app 这两者之间的 App,英文名叫:Hybrid App。

其实,早在几年前就已经出现了 App 混合开发模式,到2014年末才开始流行,2016年已经被广泛使用,而2017年甚至达到鼎盛期。

混合开发模式的流行离不开它自身的优势,因为 Hybrid App 总体特性更接近 Native App,但是和 Web App 区别较大,同时使用了网页语言编码,所以开发成本和难度比 Native App 要小很多。因此说,Hybrid App(混合模式移动应用)兼具“Native App 良好用户交互体验的优势”和“Web App 跨平台开发的优势”。目前有名的混合开发框架有 Cordova,React-Native,Weex,Ionic 等。

Cordova

Cordova 是 Apache 的一个开源项目。

Cordova 的体系架构从上往下分为,前端(html,js),Html 渲染引擎(各平台的浏览器组件),cordova plugin。Cordova Plugin 为 Cordova 重最核心的部分,扩展了 js 访问手机硬件和原生 API 的接口。

开发者可自定义 Cordova Plugin 扩展自己的原生接口,添加到 Cordova。总体来说 Cordova 即可以简单的部署到多平台,也支持单平台的深层定制。

ReactNative

Facebook 推出的跨平台框架。 使用 JS 和 React 就可以开发 App,React 是 Facebook 自己的 JS 库。用 react-native 开发的界面会完全转化为 native 界面。部署的时候不用重新编译,可以热加载而且可以植入原生代码。

react-native 是通过 JavaScript 将 native 中的方法映射到 JS 中,没有使用浏览器组件(除低版本 iOS),严格意义上来说开发出来的并不是 Hybrid App。所以,开发时比较依赖 react-native 暴露出来的接口,除此之外,初次学习成本比较高,需要学习 react 的使用(一套前端不能复用到 PC、手机浏览器、微信公众号网页)。

Weex

阿里推出的跨平台框架,Weex 的理念是write once run anywhere 也就是三端体验一致,让大家专注于业务,写一份代码 iOS、Android、H5 都能够适用。当然也有为企业节省开发成本的考虑。所以 Weex 技术方案的关键在于要拥有一个强大的解析渲染引擎。

Weex 所采用的技术架构方案:JS 引擎用 V8,JS 开发框架基于 vue.js。可以看出学习的成本也是非常高的。

Ionic

Ionic 是一个专注于用 Web 开发技术,基于 Html5 创建类似于手机平台原生应用的一个开发框架。绑定了 AngularJS 和 Sass。这个框架的目的是从 Web 的角度开发手机应用,基于 Cordova 的编译平台,可以实现编译成各个平台的应用程序。

Ionic 所采用的 JS 开发框架基于 AngularJS,并且还提供了很多 UI 组件,封装了 Cordova 常用的 Native API,但是看出学习的成本也是非常高的。

Cordova 的优势在于你熟悉了 Cordova 开发方式,熟悉了一套框架,把 Html5 开发手机 App 的坑大部分都踩过一遍之后,开发第二个 App 会极大的提高你的开发速度!

所以那些会 Html5 技术想更进一步掌握跨平台,高性能 App 开发技术,增加职场竞争力的前端人员。优秀的 Cordova 将是你的第一选择。

Cordova——混合型框架中的佼佼者

Cordova 主张一站式开发,简而言之,就是一个纯 Html5 的开发人员也可以开发和发布 Android 和 iOS 的 App了,而不需要专门的 Android 和 iOS 开发人员。

而在众多混合型框架中,Apache 作为幕后老大,背景强大,Cordova 可以说是佼佼者。Cordova 基于标准的 Web 技术——HTML、JavaScript 和 CSS,用 JavaScript 包装平台的 API 供开发者调用,具备强大的编译工具为不同平台生成应用,同时拥有丰富的第三方资源和产业链。

Cordova 的特点有以下:

  • 插件丰富

Cordova 的插件是其生态系统的重要组成部分,能帮助你快速地抵达移动设备的原生 API 上面。它提供了Cordova 和原生组件相互通信的接口,将其绑定到了标准的设备 API 上。这使你能够通过 JavaScript 调用原生代码。

Apache Cordova 项目维护着一组插件叫做核心插件。这些核心插件可以让你的应用程序访问设备功能,比如:电源、相机、联系人、摄像头、麦克风、传感器、数据、网络状态等。除了核心插件,Cordova 还有一些第三方插件提供若干个附加功能。

  • 可移植性

基于浏览器的移动 Web 可移植性和跨平台最突出表现为混合 App 也能节省跨平台的时间与成本,开发者只需编写一次核心代码就可部署到多个平台,而原生 App 的跨平台性能最差。

目前已有部分开发商采取了只编写一次应用程序,就可以在6个主要的移动平台和应用程序商店(App Store)里进行发布的方式,这些移动平台和应用程序商店包括:iOS、Android、BlackBerry、webOS、Bada 以及 Symbian 等。

当然这种方式也存在缺点,笔者认为其最主要的缺点有两个:一是性能不够好,二是兼容性较差。

但随着 Android 5.0+ 的普及以及 iOS 9.0+ 的普及,性能缺陷和兼容性问题都在减少,也就是说,如果未来某天 Android 最低支持版本从5.0开始,iOS 最低支持版本从9.0开始了,那么混合开发 App 的缺点就变得不那么明显了。很明显现在这都不是问题。

随着移动互联网的发展,现在基本是 App 满天飞,如果我去下载一个 App,那么基本都能看到有两种选择,一种是 Android 版本,一种是 iOS 版本。不管我的手机是哪种操作系统,安装完一个 App 之后,后续如果有新的版本发布的时候,我还必须去更新,才能享用新版本里的功能。比如我装了“京东”这个 App,前几天正好碰到“618”活动,那么之前一个月 App Store 就提醒我要去更新最新的 App 版本,以免错过“618”活动中新的功能使用。相对来说 iOS 系统更新 App 比起 Android 系统用户体验会好一点,但是还是稍显麻烦。

那么有没有一种方式,我只需要开发一个 App 版本,就能去适配通用的操作系统呢,不仅可以适配 Android、iOS,还可以适配其他系统,比如 Windows Phone、 Palm WebOS、Blackberry 等等。有,Cordova 就能提供这种能力,代码写一次,就能到处运行,跟我们日常开发网站效果一样,基于写 Web App,根据输出平台要求不同,就能提供不同类型的安装包。Cordova 其设计初衷是希望用户群体能够通过跨平台开发的方法降低原生开发的成本,为此,开发人员需要安装原生开发环境,配置工程,使用 HTML5、CSS3、JS 和原生 SDK 生成应用。

使用 Apache Cordova 的人群

  • 移动应用开发者,想扩展一个应用的使用平台,而不通过每个平台的语言和工具集重新实现。
  • Web 开发者,想包装部署自己的 Web App 将其分发到各个应用商店门户。
  • 移动应用开发者,有兴趣混合原生应用组建和一个 WebView(一个特别的浏览器窗口)可以接触设备 A 级 PI,或者你想开发一个原生和 WebView 组件之间的插件接口。

或许在未来几年,Android 和 iOS 开发人员需求量将会逐渐减少,而 Html5 开发人员需求量会与日俱增,那么,从 Android 或 iOS 转型为 Html5 的开发人员会更加地走俏。


下一篇

更多课程内容

导读:混合开发 APP

第01课:一起搭建 Cordova 开发环境

第02课:Cordova 生命周期

第03课:Android 与 IOS 打包

作者撰写中…

第04课:JS 是如何和本地 API 进行通信

作者撰写中…

第05课:利用 Hooks 预处理打包流程

作者撰写中…

第06课:Cordova Plugin 的使用和自定义

作者撰写中…

第07课:手机按键与 Cordova

作者撰写中…

第08课:App 自动更新设计

作者撰写中…

第09课:Cordova 实战开发技巧(一)

作者撰写中…

第10课:Cordova 实战开发技巧(二)

作者撰写中…

第11课:Cordova 实战开发技巧(三)

作者撰写中…

作者:GitChat 发表于2017/11/17 12:49:17 原文链接
阅读:94 评论:0 查看评论

linux常用的读取文件内容指令

$
0
0

linux常用于读取文件内容指令主要有以下七种:
cat,tac,nl,more,less,head,tail

cat 文件名 –将文件内容显示在屏幕上
cat -n 文件名 –将文件内容显示在屏幕上,并显示行号
cat -b 文件名 –将文件内容显示在屏幕上,并显示行号,但是不显示空白行行号

tac则是和cat反过来的(名字都是反过来的)
tac 文件名 –将文件内容显示在屏幕上,但是是从最后一行开始往前显示
tac -s separator 文件名 –从separator往后倒序输出,倒序输出不包含separator,输出到最后一行再按照顺序将separator之前的内容输出
tac -b -s separator 文件名 –从separator往后倒序输出,倒序输出包含separator,输出到最后一行再按照顺序将separator之前的内容输出

创建文件readfile.txt,在文件中输入内容

[root@localhost tmp]# cat readfile.txt 
one
two three
four five six
seven eghit nine ten
[root@localhost tmp]# tac readfile.txt 
seven eghit nine ten
four five six
two three
One

tac和cat显示的顺序是相反的

[root@localhost tmp]# tac -s "six" readfile.txt 

seven eghit nine ten
one
two three
four five six
[root@localhost tmp]# tac -b -s "six" readfile.txt 
six
seven eghit nine ten
one
two three
four five 

nl 文件名 (就是nl -b t 文件名) 使用nl指令肯定是显示行号的,主要是操作行号如何显示
nl -b a 文件名 –显示行号,空行也显示行号
nl -b t 文件名 –显示行号,空行不显示行号(默认值)
nl -w 数字x 文件名 –行号字段所占用的位数
nl -n ln 文件名 –行号在字段最前方那段空间最左端显示
nl -n rn 文件名 –行号在字段最前方那段空间最右端端显示,且不加0
nl -n rz 文件名 –行号在字段最前方那段空间最右端端显示,且加0
行号占四位

[root@localhost tmp]# nl -w 4 readfile.txt 
   1    one
   2    two three
   3    four five six
   4    seven eghit nine ten

行号前自动补全0

[root@localhost tmp]# nl -n rz -w 4 readfile.txt 
0001    one
0002    two three
0003    four five six
0004    seven eghit nine ten

行号在最左端显示

[root@localhost tmp]# nl -n ln -w 4 readfile.txt 
1       one
2       two three
3       four five six
4       seven eghit nine ten

可以执行翻页操作的读取文件内容指令
more 文件名
空格:向下翻页
Enter:向下换一行
/字符串: 查找文件内容
q: 离开more,不再显示内容
b: 往回翻页

less 文件名
空格:向下翻页
Pageup: 向上翻页
Pagedown: 向下翻页
/字符串: 向下搜索
?字符串: 向上搜索
n: 重复前一个搜索
N: 反向重复前一个搜索
q: 离开less

haed 文件名 –显示文件头十行
head -n x 文件名 –显示文件头x行,如果x为负数,则显示除最后x行外的前面所有行

tail文件名 –显示文件头十行
tail -n x 文件名 –显示文件头x行,如果x前面有+号,则显示除前面x-1行外的所有行

如果想要看第十一行到第二十行,可以结合管道流来实现
两种方式
先获取头二十行,再获取最后十行

[root@localhost tmp]# head -n 20 man_db.conf | tail -n 10
# --------------------------------------------------------
# MANDATORY_MANPATH         manpath_element
# MANPATH_MAP       path_element    manpath_element
# MANDB_MAP     global_manpath  [relative_catpath]
#---------------------------------------------------------
# every automatically generated MANPATH includes these fields
#
#MANDATORY_MANPATH          /usr/src/pvm3/man
#
MANDATORY_MANPATH           /usr/man

先获取除头十行外的所有行,再获取头十行

[root@localhost tmp]# tail -n +11 man_db.conf | head -n 10
# --------------------------------------------------------
# MANDATORY_MANPATH         manpath_element
# MANPATH_MAP       path_element    manpath_element
# MANDB_MAP     global_manpath  [relative_catpath]
#---------------------------------------------------------
# every automatically generated MANPATH includes these fields
#
#MANDATORY_MANPATH          /usr/src/pvm3/man
#
MANDATORY_MANPATH           /usr/man
作者:u012062455 发表于2017/11/17 13:51:37 原文链接
阅读:83 评论:1 查看评论

Codeforces Round #444 (Div. 2) A-C 题解

$
0
0
A. Div. 64
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Top-model Izabella participates in the competition. She wants to impress judges and show her mathematical skills.

Her problem is following: for given string, consisting of only 0 and 1, tell if it's possible to remove some digits in such a way, that remaining number is a representation of some positive integer, divisible by 64, in the binary numerical system.

Input

In the only line given a non-empty binary string s with length up to 100.

Output

Print «yes» (without quotes) if it's possible to remove digits required way and «no» otherwise.

Examples
input
100010001
output
yes
input
100
output
no
Note

In the first test case, you can get string 1 000 000 after removing two ones which is a representation of number 64 in the binary numerical system.

You can read more about binary numeral system representation here: https://en.wikipedia.org/wiki/Binary_system


打cf真的是一个不断学习的过程,题目问要求去掉几个数之后剩下的数能整除64.
此题要注意有前导0,64的二进制是(1000000),所以搜到第一个1开始,后面的0只要大于等于6个就ok。
代码实现:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<cstdio>
#define ll long long
#define mset(a,x) memset(a,x,sizeof(a))

using namespace std;
const double PI=acos(-1);
const int inf=0x3f3f3f3f;
const double esp=1e-6;
const int maxn=1e6+5;
const int mod=1e9+7;
int dir[4][2]={0,1,1,0,0,-1,-1,0};
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll inv(ll b){if(b==1)return 1; return (mod-mod/b)*inv(mod%b)%mod;}
ll fpow(ll n,ll k){ll r=1;for(;k;k>>=1){if(k&1)r=r*n%mod;n=n*n%mod;}return r;}
string map;

int main()
{
	int n,i,j,k;
	cin>>map;
	for(i=0;i<map.length();i++)
	{
		if(map[i]=='1')
		break;
	}
	int ans=0;
	for(j=i;j<map.length();j++)
	{
		if(map[j]=='0')
		ans++;
	}
	if(ans>=6)
	cout<<"YES"<<endl;
	else
	cout<<"NO"<<endl;
	return 0;
}

B. Cubes for Masha
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Absent-minded Masha got set of n cubes for her birthday.

At each of 6 faces of each cube, there is exactly one digit from 0 to 9. Masha became interested what is the largest natural x such she can make using her new cubes all integers from 1 to x.

To make a number Masha can rotate her cubes and put them in a row. After that, she looks at upper faces of cubes from left to right and reads the number.

The number can't contain leading zeros. It's not required to use all cubes to build a number.

Pay attention: Masha can't make digit 6 from digit 9 and vice-versa using cube rotations.

Input

In first line integer n is given (1 ≤ n ≤ 3) — the number of cubes, Masha got for her birthday.

Each of next n lines contains 6 integers aij (0 ≤ aij ≤ 9) — number on j-th face of i-th cube.

Output

Print single integer — maximum number x such Masha can make any integers from 1 to x using her cubes or 0 if Masha can't make even 1.

Examples
input
3
0 1 2 3 4 5
6 7 8 9 0 1
2 3 4 5 6 7
output
87
input
3
0 1 3 5 6 8
1 2 4 5 7 8
2 3 4 6 7 9
output
98
Note

In the first test case, Masha can build all numbers from 1 to 87, but she can't make 88 because there are no two cubes with digit 8.


好狠毒的一个题,无限WA,就是n组6个数,问从1开始最多能组到多大,要求从1到这个数都存在。
就是模拟啊,然后需要注意的是:这个数最大不超过99,因为如果到了99,需要2个1,2个2……2个9,此时就已经18个数了,所以模拟一下就ok。
代码实现:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<cstdio>
#define ll long long
#define mset(a,x) memset(a,x,sizeof(a))

using namespace std;
const double PI=acos(-1);
const int inf=0x3f3f3f3f;
const double esp=1e-6;
const int maxn=1e6+5;
const int mod=1e9+7;
int dir[4][2]={0,1,1,0,0,-1,-1,0};
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll inv(ll b){if(b==1)return 1; return (mod-mod/b)*inv(mod%b)%mod;}
ll fpow(ll n,ll k){ll r=1;for(;k;k>>=1){if(k&1)r=r*n%mod;n=n*n%mod;}return r;}
int vis[100];
int map[10][10];

int main()
{
	int n,i,j,k,l;
	while(cin>>n)
	{
		mset(vis,0);
		for(i=0;i<n;i++)
		{
			for(j=0;j<6;j++)
			{
				cin>>map[i][j];
				vis[map[i][j]]=1;
			}
		}
		for(i=0;i<n;i++)
		{
			for(j=0;j<6;j++)
			{
				for(k=0;k<n;k++)
				{
					if(i==k)
					continue;
					for(l=0;l<6;l++)
					{
						vis[map[i][j]*10+map[k][l]]=1;
					}
				}
			}
		}
		for(i=1;i<=99;i++)
		{
			if(!vis[i])
			break;
		}
		cout<<i-1<<endl;
	}
	return 0;
}

C. Solution for Cube
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

During the breaks between competitions, top-model Izabella tries to develop herself and not to be bored. For example, now she tries to solve Rubik's cube 2x2x2.

It's too hard to learn to solve Rubik's cube instantly, so she learns to understand if it's possible to solve the cube in some state using 90-degrees rotation of one face of the cube in any direction.

To check her answers she wants to use a program which will for some state of cube tell if it's possible to solve it using one rotation, described above.

Cube is called solved if for each face of cube all squares on it has the same color.

https://en.wikipedia.org/wiki/Rubik's_Cube

Input

In first line given a sequence of 24 integers ai (1 ≤ ai ≤ 6), where ai denotes color of i-th square. There are exactly 4 occurrences of all colors in this sequence.

Output

Print «YES» (without quotes) if it's possible to solve cube using one rotation and «NO» (without quotes) otherwise.

Examples
input
2 5 4 6 1 3 6 2 5 5 1 2 3 5 3 1 1 2 4 6 6 4 3 4
output
NO
input
5 3 5 3 2 5 2 5 6 2 6 2 4 4 4 4 1 1 1 1 6 3 6 3
output
YES
Note

In first test case cube looks like this:

In second test case cube looks like this:

It's possible to solve cube by rotating face with squares with numbers 13, 14, 15, 16.

传送门:点击打开链接

代码实现:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<cstdio>
#define ll long long
#define mset(a,x) memset(a,x,sizeof(a))

using namespace std;
const double PI=acos(-1);
const int inf=0x3f3f3f3f;
const double esp=1e-6;
const int maxn=1e6+5;
const int mod=1e9+7;
int dir[4][2]={0,1,1,0,0,-1,-1,0};
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll inv(ll b){if(b==1)return 1; return (mod-mod/b)*inv(mod%b)%mod;}
ll fpow(ll n,ll k){ll r=1;for(;k;k>>=1){if(k&1)r=r*n%mod;n=n*n%mod;}return r;}
int map[30][30],vis[30];

int main()
{
	int i,j,k,x,ans=0;
	for(i=0;i<6;i++)
	{
		set <int> s;
		for(j=0;j<4;j++)
		{
			cin>>x;
			s.insert(x);
		}
		if(s.size()==1)
		ans++;
		else if(s.size()==2)
		{
			int pre=-1,pre1=-1;
			for(auto it: s)
			{
				if(pre==-1)
				pre=it;
				else
				pre1=it;
			}
			if(pre>pre1)
			swap(pre,pre1);
			map[pre][pre1]++;
		}
		else
		{
			cout<<"NO"<<endl;
			return 0;
		}
	}
	if(ans==2)
	{
		for(i=1;i<=6;i++)
		{
			for(j=1;j<=6;j++)
			{
				if(map[i][j]>=2)
				{
					cout<<"NO"<<endl;
					return 0;
				}
			}
		}
		cout<<"YES"<<endl;
	}
	else
	cout<<"NO"<<endl;
	return 0;
}


作者:Ever_glow 发表于2017/11/17 15:19:33 原文链接
阅读:43 评论:0 查看评论

Go实战--golang中的JQUERY(PuerkitoBio/goquery、从html中获取链接)

$
0
0

生命不止,继续 go go go !!!
jQuery应该说是家喻户晓。

jQuery is a fast, small, and feature-rich JavaScript library. It makes things like HTML document traversal and manipulation, event handling, animation, and Ajax much simpler with an easy-to-use API that works across a multitude of browsers. With a combination of versatility and extensibility, jQuery has changed the way that millions of people write JavaScript.

jQuery 是一个 JavaScript 函数库。
jQuery 库包含以下特性:
HTML 元素选取
HTML 元素操作
CSS 操作
HTML 事件函数
JavaScript 特效和动画
HTML DOM 遍历和修改
AJAX
Utilities

在golang的世界中,
github.com/PuerkitoBio/goquery 这个库就实现了类似 jQuery 的功能,让我们能方便的使用 Go 语言操作 HTML 文档。

记住,如果使用golang做爬虫方面的事儿,你可能会用到goquery啊!

参考:
http://blog.studygolang.com/2015/04/go-jquery-goquery/

PuerkitoBio/goquery

github地址:
https://github.com/PuerkitoBio/goquery

Star: 4833

描述:
A little like that j-thing, only in Go.

获取:
go get github.com/PuerkitoBio/goquery

创建 Document 对象
goquery 暴露了两个结构体:Document 和 Selection.
Document 表示一个 HTML 文档,Selection 用于像 jQuery 一样操作,支持链式调用。goquery 需要指定一个 HTML 文档才能继续后续的操作。

查找到指定节点
Selection 有一系列类似 jQuery 的方法,Document 结构体内嵌了 *Selection,因此也能直接调用这些方法。主要的方法是 Selection.Find(selector string),传入一个选择器,返回一个新的,匹配到的 *Selection,所以能够链式调用。

属性操作
经常需要获取一个标签的内容和某些属性值,使用 goquery 可以很容易做到

官方例子

package main

import (
  "fmt"
  "log"

  "github.com/PuerkitoBio/goquery"
)

func ExampleScrape() {
  doc, err := goquery.NewDocument("http://metalsucks.net")
  if err != nil {
    log.Fatal(err)
  }

  // Find the review items
  doc.Find(".sidebar-reviews article .content-block").Each(func(i int, s *goquery.Selection) {
    // For each item found, get the band and title
    band := s.Find("a").Text()
    title := s.Find("i").Text()
    fmt.Printf("Review %d: %s - %s\n", i, band, title)
  })
}

func main() {
  ExampleScrape()
}

输出:

Review 0: Cavalera Conspiracy - Psychosis
Review 1: Cannibal Corpse - Red Before Black
Review 2: All Pigs Must Die - Hostage Animal
Review 3: Electric Wizard - Wizard Bloody Wizard
Review 4: Trivium - The Sin and the Sentence
import (
    "fmt"
    "log"

    "github.com/PuerkitoBio/goquery"
)

func linkScrape() {
    doc, err := goquery.NewDocument("http://jonathanmh.com")
    if err != nil {
        log.Fatal(err)
    }

    doc.Find("body a").Each(func(index int, item *goquery.Selection) {
        linkTag := item
        link, _ := linkTag.Attr("href")
        linkText := linkTag.Text()
        fmt.Printf("Link #%d: '%s' - '%s'\n", index, linkText, link)
    })
}

func main() {
    linkScrape()
}

输出:

Link #0: 'Skip to content' - '#content'
Link #1: 'JonathanMH' - 'https://jonathanmh.com/'
Link #2: 'Blog' - 'https://jonathanmh.com/category/blog/'
Link #3: 'Hire Me' - 'https://jonathanmh.com/hire-me/'
Link #4: 'About' - 'https://jonathanmh.com/about/'
Link #5: 'twitter' - 'https://twitter.com/JonathanMH_com'
Link #6: 'rss feed' - 'http://jonathanmh.com/feed/'
Link #7: 'github' - 'https://github.com/JonathanMH'
Link #8: 'stackoverflow' - 'http://stackoverflow.com/users/896285/jonathan-m-hethey'
Link #9: 'instagram' - 'http://instagram.com/jonathanmh'
Link #10: 'facebook' - 'https://www.facebook.com/pages/JonathanMH/159526834122370'
Link #11: 'linkedin' - 'http://www.linkedin.com/in/jonathanmh'
Link #12: 'hire me' - '/hire-me'
Link #13: '' - 'https://twitter.com/JonathanMH_com'
Link #14: '' - 'https://www.facebook.com/JonathanMH-159526834122370/'
Link #15: '' - 'https://www.instagram.com/jonathanmh/'
Link #16: '' - 'https://github.com/jonathanmh/'
Link #17: 'Work every day like you just got fired' - 'https://jonathanmh.com/work-every-day-like-just-got-fired/'
Link #18: 'Vue.js API Client / Single Page App (SPA) Tutorial' - 'https://jonathanmh.com/vue-js-api-client-single-page-app-spa-tutorial/'
Link #19: 'Building a Simple Searchable API with Express (Backend)' - 'https://jonathanmh.com/building-a-simple-searchable-api-with-express-backend/'
Link #20: 'Music Monday: Doom Soundtrack' - 'https://jonathanmh.com/music-monday-doom-soundtrack/'
Link #21: 'Brick by Brick' - 'https://jonathanmh.com/brick-by-brick/'
Link #22: 'Taking Screenshots with Headless, The Chrome Debuggping Protocol (CDP) and Golang' - 'https://jonathanmh.com/taking-screenshots-headless-chrome-debuggping-protocol-cdp-golang/'
Link #23: 'Firefox has re-joined the Browser Wars' - 'https://jonathanmh.com/firefox-re-joined-browser-wars/'
Link #24: 'A Mastodon Review, is it the next Twitter / Facebook by the People?' - 'https://jonathanmh.com/mastodon-review-next-twitter-facebook-people/'
Link #25: 'Testing Coin Hive Crowd Source Monero Mining' - 'https://jonathanmh.com/testing-coin-hive-crowd-source-monero-mining/'
Link #26: 'Glass Half' - 'https://jonathanmh.com/glass-half/'
Link #27: 'read older posts' - '/blog/page/2/'
Link #28: 'twitter' - 'https://twitter.com/JonathanMH_com'
Link #29: 'rss feed' - 'http://jonathanmh.com/feed/'
Link #30: 'github' - 'https://github.com/JonathanMH'
Link #31: 'stackoverflow' - 'http://stackoverflow.com/users/896285/jonathan-m-hethey'
Link #32: 'instagram' - 'http://instagram.com/jonathanmh'
Link #33: 'facebook' - 'https://www.facebook.com/pages/JonathanMH/159526834122370'
Link #34: 'linkedin' - 'http://www.linkedin.com/in/jonathanmh'
Link #35: '.htaccess' - 'https://jonathanmh.com/tag/htaccess/'
Link #36: 'Adobe' - 'https://jonathanmh.com/tag/adobe/'
Link #37: 'Android' - 'https://jonathanmh.com/tag/android/'
Link #38: 'Arch Linux' - 'https://jonathanmh.com/tag/arch-linux/'
Link #39: 'atom' - 'https://jonathanmh.com/tag/atom/'
Link #40: 'bash' - 'https://jonathanmh.com/tag/bash/'
Link #41: 'blogging' - 'https://jonathanmh.com/tag/blogging/'
Link #42: 'Brackets' - 'https://jonathanmh.com/tag/brackets/'
Link #43: 'cigtrack' - 'https://jonathanmh.com/tag/cigtrack/'
Link #44: 'CodeIgniter' - 'https://jonathanmh.com/tag/codeigniter/'
Link #45: 'CSS' - 'https://jonathanmh.com/tag/css/'
Link #46: 'Digital Ocean' - 'https://jonathanmh.com/tag/digital-ocean/'
Link #47: 'express.js' - 'https://jonathanmh.com/tag/express-js/'
Link #48: 'facebook' - 'https://jonathanmh.com/tag/facebook/'
Link #49: 'ghost' - 'https://jonathanmh.com/tag/ghost/'
Link #50: 'git' - 'https://jonathanmh.com/tag/git/'
Link #51: 'github' - 'https://jonathanmh.com/tag/github/'
Link #52: 'gitlab' - 'https://jonathanmh.com/tag/gitlab/'
Link #53: 'go' - 'https://jonathanmh.com/tag/go/'
Link #54: 'golang' - 'https://jonathanmh.com/tag/golang/'
Link #55: 'Google' - 'https://jonathanmh.com/tag/google/'
Link #56: 'Gulp' - 'https://jonathanmh.com/tag/gulp/'
Link #57: 'gvim' - 'https://jonathanmh.com/tag/gvim/'
Link #58: 'JavaScript' - 'https://jonathanmh.com/tag/javascript/'
Link #59: 'kickstarter' - 'https://jonathanmh.com/tag/kickstarter/'
Link #60: 'Linux' - 'https://jonathanmh.com/tag/linux/'
Link #61: 'markdown' - 'https://jonathanmh.com/tag/markdown/'
Link #62: 'mindset' - 'https://jonathanmh.com/tag/mindset/'
Link #63: 'MVC' - 'https://jonathanmh.com/tag/mvc/'
Link #64: 'Nginx' - 'https://jonathanmh.com/tag/nginx/'
Link #65: 'node.js' - 'https://jonathanmh.com/tag/node-js/'
Link #66: 'npm' - 'https://jonathanmh.com/tag/npm/'
Link #67: 'PHP' - 'https://jonathanmh.com/tag/php/'
Link #68: 'plugin' - 'https://jonathanmh.com/tag/plugin/'
Link #69: 'Raspberry PI' - 'https://jonathanmh.com/tag/raspberry-pi/'
Link #70: 'SCSS' - 'https://jonathanmh.com/tag/scss/'
Link #71: 'social media' - 'https://jonathanmh.com/tag/social-media/'
Link #72: 'ssh' - 'https://jonathanmh.com/tag/ssh/'
Link #73: 'Terminal' - 'https://jonathanmh.com/tag/terminal/'
Link #74: 'toolbox' - 'https://jonathanmh.com/tag/toolbox/'
Link #75: 'UberWriter' - 'https://jonathanmh.com/tag/uberwriter/'
Link #76: 'Ubuntu' - 'https://jonathanmh.com/tag/ubuntu/'
Link #77: 'vim' - 'https://jonathanmh.com/tag/vim/'
Link #78: 'web crawling' - 'https://jonathanmh.com/tag/web-crawling/'
Link #79: 'WordPress' - 'https://jonathanmh.com/tag/wordpress/'
Link #80: 'Blog' - 'https://jonathanmh.com/category/blog/'
Link #81: 'Hire Me' - 'https://jonathanmh.com/hire-me/'
Link #82: 'About' - 'https://jonathanmh.com/about/'
Link #83: 'twitter' - 'https://twitter.com/JonathanMH_com'
Link #84: 'rss feed' - 'http://jonathanmh.com/feed/'
Link #85: 'github' - 'https://github.com/JonathanMH'
Link #86: 'stackoverflow' - 'http://stackoverflow.com/users/896285/jonathan-m-hethey'
Link #87: 'instagram' - 'http://instagram.com/jonathanmh'
Link #88: 'facebook' - 'https://www.facebook.com/pages/JonathanMH/159526834122370'
Link #89: 'linkedin' - 'http://www.linkedin.com/in/jonathanmh'
Link #90: 'JonathanMH' - 'https://jonathanmh.com/'
Link #91: 'Proudly powered by WordPress' - 'https://wordpress.org/'
package main

import (
    "os"
    "strings"
    "text/template"

    "github.com/PuerkitoBio/goquery"
)

const rstLink = "`{{.Text}} <{{.Href}}>`_\n"

type htmlLink struct {
    Text string
    Href string
}

func main() {
    url := "https://www.baidu.com"

    doc, err := goquery.NewDocument(url)
    if err != nil {
        panic(err)
    }

    tmpl := template.Must(template.New("test").Parse(rstLink))
    doc.Find("a").Each(func(_ int, link *goquery.Selection) {
        text := strings.TrimSpace(link.Text())
        href, ok := link.Attr("href")
        if ok {
            tmpl.Execute(os.Stdout, &htmlLink{text, href})
        }
    })
}

输出:

` </>`_
`手写 <javascript:;>`_
`拼音 <javascript:;>`_
`关闭 <javascript:;>`_
`百度首页 </>`_
`设置 <javascript:;>`_
`登录 <https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F>`_
`新闻 <http://news.baidu.com>`_
`hao123 <http://www.hao123.com>`_
`地图 <http://map.baidu.com>`_
`视频 <http://v.baidu.com>`_
`贴吧 <http://tieba.baidu.com>`_
`学术 <http://xueshu.baidu.com>`_
`登录 <https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F>`_
`设置 <http://www.baidu.com/gaoji/preferences.html>`_
`更多产品 <http://www.baidu.com/more/>`_
`新闻 <http://news.baidu.com/ns?cl=2&rn=20&tn=news&word=>`_
`贴吧 <http://tieba.baidu.com/f?kw=&fr=wwwt>`_
`知道 <http://zhidao.baidu.com/q?ct=17&pn=0&tn=ikaslist&rn=10&word=&fr=wwwt>`_
`音乐 <http://music.baidu.com/search?fr=ps&ie=utf-8&key=>`_
`图片 <http://image.baidu.com/search/index?tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&word=>`_
`视频 <http://v.baidu.com/v?ct=301989888&rn=20&pn=0&db=0&s=25&ie=utf-8&word=>`_
`地图 <http://map.baidu.com/m?word=&fr=ps01000>`_
`文库 <http://wenku.baidu.com/search?word=&lm=0&od=0&ie=utf-8>`_
`更多» <//www.baidu.com/more/>`_
`把百度设为主页 <//www.baidu.com/cache/sethelp/help.html>`_
`关于百度 <http://home.baidu.com>`_
`About  Baidu <http://ir.baidu.com>`_
`百度推广 <http://e.baidu.com/?refer=888>`_
`使用百度前必读 <http://www.baidu.com/duty/>`_
`意见反馈 <http://jianyi.baidu.com/>`_
`京公网安备11000002000001号 <http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=11000002000001>`_

这里写图片描述

作者:wangshubo1989 发表于2017/11/17 15:24:08 原文链接
阅读:1059 评论:0 查看评论

Linux 压缩,解压缩,打包指令

$
0
0

linux压缩文件扩展名有以下几种:
*.Z compress程序压缩的扩展名
*.gz gzip压缩后的扩展名
*.bz2 bzip2压缩后的扩展名
*.tar tar打包后的扩展名,没有被压缩过
*.tar.gz tar打包后经过gzip压缩后的扩展名
*.tar.bz2 tar打包后经过bzip2压缩后的扩展名

这些扩展名的意义是方便识别是那种压缩指令进行压缩的,从而就知道使用哪种指令进行解压缩。

其中compress指令由于压缩效率低下,并且gzip和bzip2都支持解压缩compress压缩过的文件,所以这个指令已经基本上没人使用了。
gzip 文件名
参数:
-v: 显示压缩比等信息
-c: 将压缩的数据输出到屏幕上,可以通过数据流重导向来处理
-d: 解压缩参数

使用-v参数显示压缩比,压缩后文件名为man_dbtest.conf.gz,压缩后
源文件不存在了

[root@localhost tmp]# gzip -v man_dbtest.conf 
man_dbtest.conf:     61.9% -- replaced with man_dbtest.conf.gz

加上-d参数,解压缩

[root@localhost tmp]# gzip -d man_dbtest.conf.gz 

使用-c参数,重导向数据流,自定义压缩后文件名,同时源文件依然存在。

[root@localhost tmp]# gzip -cv man_dbtest.conf > man_dbtest.conf2.gz
man_dbtest.conf:     61.9%

由于man_dbtest.conf是一个文本文件,可以使用zcat指令读取压缩后文件内容。

[root@localhost tmp]# zcat man_dbtest.conf.gz

bzip2 文件
-v: 显示压缩比信息
-c: 将压缩的数据输出到屏幕上,可以通过数据流重导向来处理
-d: 解压缩参数
bzip2的指令和gzip几乎是一致的,上面的操作均可以换成bzip2来执行,同样可以使用bzcat指令来读取用bzip2压缩过的文本文件。

上面讲的gzip和bzip2指令只能对文件进行压缩,没法对文件夹进行压缩。如果要想对文件夹进行压缩,可以使用tar指令先将文件夹打包,然后再压缩。
tar指令的参数非常多
-j: 通过bzip2支持进行压缩/解压缩
-z: 通过gzip支持进行压缩/解压缩
-v: 在压缩/解压缩过程中,将正在处理的文件名显示出来
-c: 建立压缩文件
-t: 查看压缩文件中有哪些文件名
-x: 解压缩或者解打开
-f: 后面接要被处理的文件名
-C: 大写的C,若要特定指定也锁目录,可以使用这个参数
注意,ctx三个参数不可同时出现。

对于tar指令,只需记住以下六个就够用了:
bzip2支持的压缩/解压缩方式
压缩:tar -jcv -f filename.tar.bz2 要被压缩的文件或者文件夹
查询:tar -jtv -f filename.tar.bz2
解压缩:tar -jxv -f filename.tar.bz2 -C 要将压缩文件解压缩到的目录

gzip支持的压缩/解压缩方式
压缩:tar -zcv -f filename.tar.gz 要被压缩的文件或者文件夹
查询:tar -ztv -f filename.tar.gz
解压缩:tar -zxv -f filename.tar.gz -C 要将压缩文件解压缩到的目录

创建文件夹tardirtest

[root@localhost tmp]# mkdir tardirtest
[root@localhost tmp]# cp man_dbtest.conf tardirtest/
[root@localhost tmp]# cp man_db.conf.gz tardirtest/
[root@localhost tmp]# cp man_db.conf.bz2 tardirtest/
[root@localhost tmp]# ll tardirtest/
total 16
-rw-r--r-- 1 root root 1986 Nov 17 15:13 man_db.conf.bz2
-rw-r--r-- 1 root root 1998 Nov 17 15:13 man_db.conf.gz
-rw-r--r-- 1 root root 5171 Nov 17 15:11 man_dbtest.conf

使用bzip2支持的压缩/解压缩方式

[root@localhost tmp]# tar -jcv -f tardirtest.tar.bz2 tardirtest/
tardirtest/
tardirtest/man_dbtest.conf
tardirtest/man_db.conf.gz
tardirtest/man_db.conf.bz2
[root@localhost tmp]# ll tardirtest*
-rw-r--r-- 1 root root 6899 Nov 17 15:19 tardirtest.tar.bz2

tardirtest:
total 16
-rw-r--r-- 1 root root 1986 Nov 17 15:13 man_db.conf.bz2
-rw-r--r-- 1 root root 1998 Nov 17 15:13 man_db.conf.gz
-rw-r--r-- 1 root root 5171 Nov 17 15:11 man_dbtest.conf

压缩后源文件依然存在,查看压缩文件内文件名

[root@localhost tmp]# tar -jtv -f tardirtest.tar.bz2 
drwxr-xr-x root/root         0 2017-11-17 15:13 tardirtest/
-rw-r--r-- root/root      5171 2017-11-17 15:11 tardirtest/man_dbtest.conf
-rw-r--r-- root/root      1998 2017-11-17 15:13 tardirtest/man_db.conf.gz
-rw-r--r-- root/root      1986 2017-11-17 15:13 tardirtest/man_db.conf.bz2

解压缩,解压缩后存放在/tmp/tardirtest2/ 文件夹下

[root@localhost tmp]# tar -jxv -f tardirtest.tar.bz2 -C tardirtest2/
tardirtest/
tardirtest/man_dbtest.conf
tardirtest/man_db.conf.gz
tardirtest/man_db.conf.bz2
[root@localhost tmp]# cd tardirtest2/
[root@localhost tardirtest2]# ll
total 0
drwxr-xr-x 2 root root 71 Nov 17 15:13 tardirtest
[root@localhost tardirtest2]# cd tardirtest/
[root@localhost tardirtest]# ll
total 16
-rw-r--r-- 1 root root 1986 Nov 17 15:13 man_db.conf.bz2
-rw-r--r-- 1 root root 1998 Nov 17 15:13 man_db.conf.gz
-rw-r--r-- 1 root root 5171 Nov 17 15:11 man_dbtest.conf
作者:u012062455 发表于2017/11/17 15:39:51 原文链接
阅读:64 评论:0 查看评论

android 使用Robotium自动化测试

$
0
0

Robotium是一款国外的Android自动化测试框架,主要针对Android平台的应用进行黑盒自动化测试,它提供了模拟各种手势操作(点击、长按、滑动等)、查找和断言机制的API,能够对各种控件进行操作。Robotium结合Android官方提供的测试框架达到对应用程序进行自动化的测试。另外,Robotium 4.0版本已经支持对WebView的操作。Robotium 对Activity,Dialog,Toast,Menu 都是支持的。

我这里介绍是eclipse进行黑盒测试。

1、重签名apk

把apk的后缀名改成zip,然后删掉里面META-INF这个文件夹,重新把后缀名改回apk。

复制eclipse下面默认的签名证书:



使用cmd命令进入需要签名的目录,apk和签名证书放在一起。

重签名的命令:

jarsigner -verbose -keystore debug.keystore -storepass android -signedjar OsmdroidSample_news.apk -digestalg SHA1 -sigalg MD5withRSA OsmdroidSample.apk androiddebugkey

eclipse默认调试签名证书是debug.keystore,密码是android,别名androiddebugkey,别名的密码android

如果出现找不到证书链,那就是签名的别名不对


OsmdroidSample_news.apk成功的apk。其实重签名就是删除之前的签名,改成默认eclipse默认的调试的签名证书。

重签名之后apk,就装在真机上。

2、查看apk里面id的自带工具

在F:\adt-bundle-windows-x86_64-20140321\sdk\tools目录下有个文件uiautomatorviewer.bat ,双击这个文件

点击刚刚装的apk

在点击下图


相关的界面出来,在右侧能找到id。对后面写测试点击id就有用了。

切换界面了还是要点击红色箭头那个。

3、eclipse创建项目写代码了


下一步,填写名称,再下一步选第一个,第二个是白盒测试


最后就是finish了。

创建完项目之后就是配置




选择JUint


下一步,选择JUint4 finish就行了。

新建一个libs文件夹,把jar复制进行。



配置好了。下面可以开始写代码了。


4、写代码

manifest的配置

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="android.support.v7.appcompat.test"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="19" />

    <instrumentation
        android:name="android.test.InstrumentationTestRunner"
        android:targetPackage="com.osmdroid.sample" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <uses-library android:name="android.test.runner" />
    </application>

</manifest>

其中android:targetPackage="com.osmdroid.sample"这个就是你要测试应用程序的包名。

部分示例代码:

package com.osmdroid.test;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.robotium.solo.Solo;

import android.test.ActivityInstrumentationTestCase2;
import android.widget.Button;
import android.widget.TextView;

public class OsmdroidTest extends ActivityInstrumentationTestCase2{
	private static final String cls = "com.osmdroid.sample.MainActivity";
	private static Class<?> target;
	private Solo solo;
	static {
		try {
			target = Class.forName(cls);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	public OsmdroidTest() {
		super(target);
	}

	@Before
	protected void setUp() throws Exception {
		solo = new Solo(getInstrumentation(), getActivity());
	}

	@After
	protected void tearDown() throws Exception {
		solo.finishOpenedActivities();
	}

	@Test
	public void test() {
		solo.sleep(1000);
		solo.clickOnView((Button) solo.getView("com.osmdroid.sample:id/"
				+ "button"));
		solo.sleep(500);
		solo.goBack();
		
		solo.sleep(1000);
		solo.clickOnView((Button) solo.getView("com.osmdroid.sample:id/"
				+ "button1"));
		solo.sleep(500);
		solo.goBack();
		
		solo.sleep(1000);
		solo.clickOnView((Button) solo.getView("com.osmdroid.sample:id/"
				+ "button3"));
		solo.sleep(500);
		solo.goBack();
		
		solo.sleep(1000);
		solo.clickOnView((Button) solo.getView("com.osmdroid.sample:id/"
				+ "button4"));
		solo.sleep(500);
		solo.goBack();
		
		solo.sleep(1000);
		solo.clickOnView((Button) solo.getView("com.osmdroid.sample:id/"
				+ "button5"));
		solo.sleep(500);
		solo.goBack();
		
		solo.sleep(1000);
		solo.clickOnView((Button) solo.getView("com.osmdroid.sample:id/"
				+ "button6"));
		solo.sleep(500);
		solo.goBack();
		
		solo.sleep(1000);
		solo.clickOnView((Button) solo.getView("com.osmdroid.sample:id/"
				+ "button7"));
		solo.sleep(500);
		solo.goBack();
		
		solo.sleep(1000);
		solo.clickOnView((Button) solo.getView("com.osmdroid.sample:id/"
				+ "button2"));
		solo.sleep(500);
		solo.goBack();
		
		
		
//		EditText earthP = (EditText) solo
//				.getView("com.osmdroid.sample:id/EditTextValue_1");
//		solo.clearEditText(earthP); 
//		solo.enterText(earthP, "804671.2996");
//		
//		EditText x = (EditText) solo.getView("com.osmdroid.sample:id/EditTextOutputX");
//		String xValue = x.getText().toString();
//		assertEquals("计算不正确", "2636657.570", xValue);
//		solo.goBack();
	}

}

@Before 被这个注解的方法会阻塞 @Test 注解方法,在 @Test 注解方法前执行,如果存在多个 @Before 方法,执行顺序随机。这个注解的方法主要用来执行一些测试的设置。

@After 被这个注解标志的方法,会在所有的 @Test 方法之后执行,主要用来释放资源的操作

@Test 被这个注解标志的方法,就是你的测试方法,一个单元测试类可以有多个测试方法。

@Test(timeout=) 带参数的 @Test 注解标签,如果方法在参数时间内没有成功完成,则返回失败。

@BeforeClass 被这个标签标注的方法,会在Class第一次加载调用,所以你可以在里面执行一个 static 方法,比如一些 static 方法是很费资源的,例如 JDBC 操作。

@AfterClass 对应着 

@BeforeClass ,你可以进行一些 static 操作之后的资源释放。

具体的Solo 的更多用法请参考javadoc 文档。

右键Run As 选择Android Junit  Test 就可以跑起来了。

5、注意事项

就是如果你在这个电脑上重签名,可能发给人家进行测试编译时候回出现:

Test run failed: Permission Denial: starting instrumentation ComponentInfo{com.osmdroid.test/android.test.InstrumentationTestRunner} from pid=8661, uid=8661 not allowed because package com.osmdroid.test does not have a signature matching the target com.osmdroid.sample

那就是签名证书不对了

还是让他重新签名,安装吧。

有些时候运行失败,重启一下eclipse吧。


这就是黑盒测试,比较简单,成本还好。如果是白盒测试,那就成本要高了。


作者:qq_16064871 发表于2017/11/17 15:44:13 原文链接
阅读:52 评论:0 查看评论

【MQ】ActiveMQ(三)——spring管理ActiveMQ,实现发送和接收效果

$
0
0

一、前言

      在前一篇博客中,小编向大家简单的介绍了一下ActiveMQ的消息处理方式,包括了点对点,发布订阅两种模式。写向大家展示了一下如何使用,但是在真正开发的时候我们是不会写那么一大片代码,从建立连接工厂,再由连接工厂创建连接对象,连接对象打开连接,连接对象然后创建session,session创建目的地,用于连接数据。

      这个过程是比较复杂的,在开发的时候一般我们会使用Spring ,把这些操作来交给Spring管理,因为Spring的核心功能中包括了依赖注入,由spring容器创建连接工厂,方便操作。

二、ActiveMQ整合Spring

2.1 引入相关jar

      spring相关:

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>

      ActiveMQ相关:

      <!--ActiveMQ-->
      <dependency>
        <groupId>org.apache.activemq</groupId>
        <artifactId>activemq-all</artifactId>
        <version>${activemq.version}</version>
      </dependency>

2.2 建立applicationContext-mq.xml文件,用于配置整合信息

  • 这里主要事实配置连接工程ConnectionFactory。

      这里是把ActiveMQConnectionFactory交给spring的jsm的SingleConnectionFactory管理:

  • 配置了生产者

      使用spring提供的jsm工具类,可以进行消息发送和接收

  • 配置队列或主题的目的地
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">

    <!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 -->
    <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" value="tcp://192.168.137.15:61616" />
    </bean>
    <!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
    <bean id="connectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory">
        <!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory -->
        <property name="targetConnectionFactory" ref="targetConnectionFactory" />
    </bean>

    <!-- 配置生产者 -->
    <!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->
        <property name="connectionFactory" ref="connectionFactory" />
    </bean>

    <!--这个是队列目的地,点对点的 -->
    <bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
        <constructor-arg>
            <value>Ares-queue</value>
        </constructor-arg>
    </bean>
    <!--这个是主题目的地,一对多的 -->
    <bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
        <constructor-arg value="Ares_topic" />
    </bean>

    <!-- 接收消息 -->
    <!-- 配置监听器 -->
    <bean id="queueConsumeListener" class="com.dmsd.mq.activemq.listener.QueueConsumeListener" />
    <bean id="transactionBizMessageListener" class="com.dmsd.mq.activemq.listener.TransactionBizMessageListener" />

    <!-- 消息监听容器 -->
    <bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory" />
        <property name="destination" ref="queueDestination" />
        <property name="messageListener" ref="transactionBizMessageListener" />
    </bean>
</beans>

三、发送消息到Queue

      查询职工id为3的查询职员的相关信息,并把 查询的信息放入到mq 中,这里呢,小编为了突出存放的过程,就查询了10次,并且都存储到mq中:

      这里就用到了jms提供的配置类jmsTemplate的实例,通过jmsTemplate来进行存储消息操作:

package com.dmsd.mq.activemq;

import com.dmsd.dao.TStuffMapper;
import com.dmsd.pojo.TStuff;
import com.dmsd.tool.JacksonJsonUntil;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Service;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;

/**
 * Created by Ares on 2017/11/14.
 */
@Service
public class QueneProducer implements QueneProducerFacade {

    //注入ActiveMQ的模板,在spring中注入的bean
    @Autowired
    JmsTemplate jmsTemplate;

    //注入Queue的目的地址,在spring中配置的bean
    @Autowired
    ActiveMQQueue queueDestination; 

    @Autowired
    TStuffMapper tStuffMapper;

    /**
     * 发送消息到队列-王雷-2017年11月14日16:25:34
     */
    @Override
    public void QueneProducer()  {
        for (int i=0;i<10;i++){
            System.out.println("开始发送消息=====》"+i);

            //使用JmsTemplate对象发送消息。
            jmsTemplate.send(queueDestination, new MessageCreator() {
                @Override
                public Message createMessage(Session session) throws JMSException {
                    //根据职工id查询职员
                    TStuff tStuff = tStuffMapper.selectByPrimaryKey((long) 3);
                    //转换为json
                    String json = null;
                    try {
                        json = JacksonJsonUntil.objectToJson(tStuff);
                    } catch (JsonProcessingException e) {
                        e.printStackTrace();
                    }
                    //创建一个消息对象并返回
                    TextMessage textMessage = session.createTextMessage(json);
                    return textMessage;
                }
            });
            System.out.println("第"+i+"条消息发送完成");
        }
    }
}

      Controller代码:

package com.dmsd.mq.activemq.controller;

import com.dmsd.mq.activemq.QueneProducerFacade;
import com.dmsd.tool.AresResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * Created by Ares on 2017/11/16.
 */
@Controller
public class ActiveMqController {

    //定义打印日志相关
    private static final Logger logger = LoggerFactory.getLogger(ActiveMqController.class);

    @Autowired
    QueneProducerFacade queneProducerFacade;


    @RequestMapping(value="/QueneProducer",method = RequestMethod.GET)
    @ResponseBody
    @CrossOrigin
    public AresResult QueneProducer(){
        try {
            queneProducerFacade.QueneProducer();
            return AresResult.build("0000","消息上传mq成功");
        }catch (Exception e){
            logger.error("消息上传mq失败");
            e.printStackTrace();
        }
        return AresResult.build("1111","消息上传mq失败");
    }
}

      运行项目:
      MQ初始的情况: 在队列中没有消息,pending message为0,

这里写图片描述

      向MQ中存储10条消息:

这里写图片描述

这里写图片描述

      MQ中的情况:Messages Enqueued增加了10 ,Messages Dequeued 的值也增加了10。说明刚进去的消息已经被消费者消费了。

      Messages Enqueued 进入队列的消息 进入队列的总数量,包括出队列的。 这个数量只增不减

      Messages Dequeued 出了队列的消息 可以理解为是消费这消费掉的数量

这里写图片描述

四、从ActiveMQ中取出消息

      这里我们使用了监听机制,ActiveMQ有三种消息监听器:MessageListener、SessionAwareMessageListener、MessageListenerAdapter。关于这三种的区别,小编在后面的博客向大家介绍。

      在上文中,小编向大家介绍了ActiveMQ整合spring。如果我们需要配置消息接收,也需要在配置文件中配置消息监听器:

      这里我们配置了监听器,一直监听要监听的队列,当队列有消息的时候,就会获取的message,然后传给后台使用。

  <!-- 接收消息 -->
    <!-- 配置监听器 -->
    <bean id="queueConsumeListener" class="com.dmsd.mq.activemq.listener.QueueConsumeListener" />
    <bean id="transactionBizMessageListener" class="com.dmsd.mq.activemq.listener.TransactionBizMessageListener" />

    <!-- 消息监听容器 -->
    <bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory" />
        <property name="destination" ref="queueDestination" />
        <property name="messageListener" ref="transactionBizMessageListener" />

      使用SessionAwareMessageListener监听器:

      可能很多朋友被监听器吓到了,其实就是一个类,这个类实现了SessionAwareMessageListener接口,实现了onMessage(message,session)方法,当监听器所监听的队列有了数据后,就可以把数据获取到,并且使用。

package com.dmsd.mq.activemq.listener;

import com.dmsd.api.StuffServiceFacade;
import com.dmsd.pojo.TStuff;
import com.dmsd.tool.AresResult;
import com.dmsd.tool.JacksonJsonUntil;
import org.apache.activemq.Message;
import org.apache.activemq.command.ActiveMQTextMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.listener.SessionAwareMessageListener;

import javax.jms.JMSException;
import javax.jms.Session;
import javax.jms.TextMessage;
import java.io.IOException;

/**
 * Created by Ares on 2017/11/15.
 */
public class TransactionBizMessageListener implements SessionAwareMessageListener<Message> {

    @Autowired
    StuffServiceFacade stuffServiceFacade;


    @Override
    public void onMessage(Message message, Session session) throws JMSException {
        //获取消息内容
        ActiveMQTextMessage msg = (ActiveMQTextMessage) message;
        System.out.println(msg);
        String text = null;
        text = msg.getText();
        System.out.println(text);
        //json转换为对象
        try {
            TStuff tstuff = JacksonJsonUntil.jsonToPojo(text, TStuff.class);
            TStuff stuff = new TStuff();
            stuff.setSex(tstuff.getSex());
            stuff.setName("德玛西亚");
            stuff.setClassid(tstuff.getClassid());
            stuff.setAddress(tstuff.getAddress());
            int i = stuffServiceFacade.insertStuff(stuff);
            if (i>0){
                System.out.println("添加职员成功");
            }
            else {
                System.out.println("添加职员失败");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

      当队列中有消息的时候,会自动获取消息,然后执行onmessage方法,小编在onmessage方法中把队列中的消息取出来了,存储到数据库中了。

      打印的存储情况:

这里写图片描述

      数据库中存储的数据:

这里写图片描述

五、小结

      这个发送和接收的过程和spring结合只有是比较简单了,使用也比较方便了,重点还是要理解这个过程,spring和activeMQ整合的过程。下面的博客中小编会向大家ActiveMQ的三种消息监听方式。

作者:kisscatforever 发表于2017/11/17 16:24:49 原文链接
阅读:38 评论:0 查看评论

Unity Shader 学习笔记(11) 渲染队列、透明效果

$
0
0

Unity Shader 学习笔记(11) 渲染队列、透明效果

参考书籍:《Unity Shader 入门精要》
【浅墨Unity3D Shader编程】之四 热带雨林篇: 剔除、深度测试、Alpha测试以及基本雾效合辑
3D数学 学习笔记(10) 背面剔除(Clipping)、裁切(Backface Culling)、光栅化(Rasterzation)
官网API:ShaderLab: SubShader Tags

透明测试所在步骤:


渲染队列(render queue)

用SubShader的Queue标签来觉得模型归于那个渲染队列。索引号越小,越早被渲染。


半透明物体的渲染顺序

常用顺序:
1. 先渲染所有不透明物体,开启深度测试和深度写入。
2. 半透明物体按离摄像机距离远近排序,从后往前渲染,开启深度测试,关闭深度写入。

部分相互重叠的物体不适用,解决方法是分割网格。

A为半透明,B为不透明

  • 正确:先渲染B,后渲染A。
  • 错误:先渲染A,后渲染B。A不写入深度缓冲,B发现深度缓冲没有东西,就会直接覆盖A的颜色。

A和B都为半透明

  • 正确:先渲染B,后渲染A。
  • 错误:先渲染A,后渲染B。A先写入颜色缓冲,B再和A混合,结果相反,使B看起来在A前面。


透明度测试

把一个片元透明度不满足条件(小于某个阈值)的舍弃掉,否则进行深度测试、深度写入等。CG中用clip(float x)函数进行透明度测试,如果给定任一分量为负,则舍弃当前像素的输出颜色。等价下面代码:

void clip(float4 x)
{
    if (any(x < 0))
        disacard;
}
Shader "Custom/AlphaTest" {
    Properties {
        ...
        _Cutoff ("Alpha Cutoff", Range(0,1)) = 0.5          // 透明测试阈值
    }
    SubShader {
        // 渲染队列:透明测试;不受投影器影响;指名这个Shader提前归入TransparentCutout组(指明Shader使用了透明测试)。
        Tags { "Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout" }

        Pass {
            ...

            fixed4 frag(v2f i) : SV_TARGET {
                ...

                fixed4 texColor = tex2D(_MainTex,i.uv);

                // 透明测试(小于阈值就discard,丢掉片元,类似直接return)。等价下面的判断。
                clip(texColor.a - _Cutoff);                 
                //if ((texColor.a - _Cutoff) < 0.0) { discard; }

                ...
                // 计算光照等。
            }
            ...
        }
    }
    // 保证使用透明度测试的物体可以正确地向其他物体投射阴影。
    FallBack "Transparent/Cutout/VertexLit"
}

透明度混合

将当前片元的透明度与已在颜色缓冲中的颜色值进行混合。需要关闭深度写入(不影响在其背后的物体),但不关闭深度测试(在不透明物体后面时,同样会被去掉)。
Unity提供混合命令:Blend,自动打开混合模式,源颜色的混合因子SrcFactor设为SrcAlpha,目标颜色的混合因子DstFactor设为OneMinusSrcAlpha(1 - SrcAlpha),混合后的颜色:
DstColornew = SrcAlpha × SrcColor + ( 1 - SrcAlpha ) × DstColorold

Properties {
    ...
    _AlphaScale ("Alpha Scale", Range(0,1)) = 1     // 整体透明度
}
SubShader {
    // RenderType选择Transparent用来指名这个Shader使用了透明度混合。
    Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }

    Pass {
        Tags { "LightMode"="ForwardBase" }

        ZWrite Off                          // 关闭深度写入
        Blend SrcAlpha OneMinusSrcAlpha     // 开启混合模式。SrcAlpha:源颜色混合因子,OneMinusSrcAlpha:已存在颜色混合因子

        ...

        fixed4 frag(v2f i) : SV_TARGET {
            ...
            //clip(texColor.a - _Cutoff);                   // 没有使用透明测试。
            ...
            // 透明通道乘于材质参数,即最后颜色乘于透明度
            return fixed4(ambient + diffuse,texColor.a * _AlphaScale);      
        }
        ...
    }
}

开启深度写入的半透明效果

只使用透明度混合 和 开启深度写入与透明度混合对比:

使用两个Pass:
1. 开启深度写入,但不输出颜色。
2. 进行正常的透明度混合,按照像素级别的深度顺序进行透明渲染。

在透明度混合的代码中添加一个Pass即可。ColorMask用于射着颜色通道的写掩码(write mask),可以是RGBA或其他组合,0为不输出任何颜色。

// 新加一个Pass块,先把深度信息写入深度缓冲,剔除掉了被自身遮挡的片元。
Pass {
    ZWrite On
    ColorMask 0         // 颜色通道掩码。为0:不写入任何颜色通道,不输出任何颜色。
}

// 下一个Pass和上面的透明度混合代码相同
Pass {
    Tags { "LightMode"="ForwardBase" }

    ZWrite Off
    Blend SrcAlpha OneMinusSrcAlpha
    ...
}

双面渲染的透明效果

直接透明混合物体 和 双面渲染的透明物体对比:

使用两个Pass:
1. 第一个Pass只渲染背面。
2. 第二个Pass只渲染正面。

SubShader {
        Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }

        Pass {
            Tags { "LightMode"="ForwardBase" }

            Cull Front      // 剔除正面(只渲染背面)

            // 透明混合代码一样
        }

        Pass {
            Tags { "LightMode"="ForwardBase" }

            Cull Back       // 剔除背面

            // 同上一个Pass
        }
    }

常见混合类型

类似Photoshop的混合模式。


作者:l773575310 发表于2017/11/17 16:32:31 原文链接
阅读:29 评论:0 查看评论

第25章 信号驱动式I/O

$
0
0

(1)建立SIGIO信号的信号处理函数

(2)设置套接字属主

(3)开启套接字的信号驱动式I/O标志

#include "../Gnet.h"

int fd;

void sig_io(int sig)
{
    char buf[MAX_LINE];
    int nread;
    struct sockaddr_in client_addr;
    socklen_t client_addr_len;

    printf("in sig_io\n");
    nread = recvfrom(fd, buf, MAX_LINE, 0,(struct sockaddr*)&client_addr, &client_addr_len);
    if(nread > 0)
        sendto(fd, buf, nread, 0, (struct sockaddr*)&client_addr, client_addr_len);
    else
        printf("nread < 0\n");

    printf("out sig_io\n");
}

void do_server(int udpfd)
{
    const int on = 1;
    sigset_t old, new;

    fd = udpfd;

    signal(SIGIO, sig_io);//注册信号处理函数
    if(fcntl(udpfd, F_SETOWN, getpid()) < 0)
        perr_exit("fcntl F_SETOWN error.27");//设置套接字属主
    if(ioctl(udpfd, FIONBIO, &on) < 0)
        perr_exit("ioctl FIONBIO error.29*");//非阻塞IO
    if(ioctl(udpfd, FIOASYNC, &on) < 0)
        perr_exit("ioctl FIOASYNC error.31");//信号驱动IO

    sigemptyset(&new);
    sigaddset(&new, SIGIO);
    sigprocmask(SIG_UNBLOCK, &new, &old);
}

int main(int argc, const char* argv[])
{
    int udpfd;
    struct sockaddr_in server_addr;

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(SERVER_PORT);

    udpfd = Socket(AF_INET, SOCK_DGRAM, 0);
    Bind(udpfd, (const struct sockaddr*)&server_addr, sizeof(server_addr));
    printf("waiting for connecting.\n");

    do_server(udpfd);
    while(1)
        ;

    return 0;
}

github:https://github.com/gongluck/unp-notes
作者:gongluck93 发表于2017/11/17 17:29:49 原文链接
阅读:18 评论:0 查看评论

(12)intellij Cannot create package/ Java class in Intellij IDEA with Maven template

$
0
0

           i create a project on github,and clone it to my computer git repository. i want to create a java file , but right on the java file and select new tab, i can not find java class option,where my java class option?

           the answer is, "You can mark any folder in project as Source folder with right click → Mark directory as → Sources root."

           and picture as follow.


summary:

               i'm problem solver , learn english and computer  technology.

作者:lovesummerforever 发表于2017/11/17 18:12:44 原文链接
阅读:0 评论:0 查看评论

js系列教程13-原型、原型链、作用链、闭包全解

$
0
0

全栈工程师开发手册 (作者:栾鹏)

快捷链接:
js系列教程1-数组操作全解
js系列教程2-对象和属性全解
js系列教程3-字符串和正则全解
js系列教程4-函数与参数全解
js系列教程5-容器和算法全解
js系列教程6-BOM操作全解
js系列教程7-DOM操作全解
js系列教程8-事件全解
js系列教程9-表单元素全解
js系列教程10-canvas绘图全解
js系列教程11-json、ajax、comet全解
js系列教程12-离线应用与存储全解
js系列教程13-原型、原型链、作用链、闭包全解

【对象、变量】

一个对象就是一个类,可以理解为一个物体的标准化定义。它不是一个具体的实物,只是一个标准。而通过对象实例化得到的变量就是一个独立的实物。比如通过一个对象定义了“人”,通过“人”这个标准化定义,实例化了“小明”这个人。其中“人”就是对象,“小明”就是变量。实例化的过程就是通过构造函数,来初始化设置标准定义中是具体指。比如在创建“小明”这个变量时,同时设置了他的名称,性别等信息。在变量中包含对对象的引用,所以可以通过变量操作对象,或引用对象的函数、属性。比如“小明”有手有脚(属性),可以抬头低头(函数)。

这里写图片描述

【原型、原型链】

什么是派生?

原型对象派生另一个对象,就是创建了原型对象的副本,占有独立的内存空间,并在副本上添加一个独特的属性和方法。

在js系统中,Object对象派生了Number对象、Boolean对象、String对象、Function对象、Array对象、RegExp对象、Error对象、Date对象。当然你可以通过Object对象派生自己的对象。

这里写图片描述

在js系统中,Function对象又派生了Number函数、Boolean函数、String函数、Object函数、Function函数、Array函数、RegExp函数、Error函数、Date函数、自定义函数。

这也就是为什么说函数是一种特殊的对象。因为函数是通过Function对象派生的。

从上面的介绍我们知道一切对象派生于Object对象。Object对象中包含了一系列属性和方法,可以参考js系列教程2-对象、对象属性全解

这里主要介绍__proto__和constructor属性。由于所有对象都继承自Object对象,所以所有对象(包括函数)都拥有这两个属性。

每个对象的proto属性是保存当前对象的原型对象。

所以Number对象、Boolean对象、String对象、Object对象、
Function对象、Array对象、RegExp对象、Error对象、Date对象的proto都指向Object对象。

Number函数、Boolean函数、String函数、Object函数、Function函数、Array函数、RegExp函数、Error函数、Date函数、自定义函数的proto都指向Function对象。

这种派生对象使用__proto__指针保存对原型对象的链接,就形成了原型链。对象通过原型链相互连接。所有的对象都在原型链上。所有的原型链顶端都是Object对象。

我们在原型对象中的一般用来实现所有可能的派生对象或实例变量的公共方法和公共属性。

构造/实例化

上面讲了什么是派生,原型链的形成。

那什么是实例化呢?

实例化即创建一个变量的过程,是将对象浅复制一个副本,然后通过构造函数来对这个占有独立空间的变量进行初始化。

你可以用“人”派生了“男人”、“女人”。男人实例化了“小明”、“小王”。

准确说法应该是这个占有独立空间的副本也是一个对象,这个指向副本的链接才是变量,叫做引用变量。所以变量也可以进行实例化,其实实例化的是变量指向的副本对象。这个我就把副本对象叫做变量以区分实例化和派生。

这里写图片描述

所以在js中要想实例化一个对象,进而创建一个变量的过程都需要有一个原型对象,和一个构造函数。我们把这个原型对象叫做函数的构造绑定对象,把函数叫做原型对象的构造函数。

要注意区分函数的原型对象是Function对象

为了表达这种对象与构造函数的紧密关系,js在在对象中使用constructor属性保存当前对象的构造函数的引用,在构造函数中使用prototype保存对对象的引用。对象实例化的变量中,constructor指向构造函数、__proto__指向这个对象。我们也可以称这个对象是这个变量的原型对象。

我们可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值。

而我们使用函数当做构造函数时,并没有创建这个原型对象呀?

这是因为在定义函数时,系统除了将函数的proto属性指向Function对象外,还会自动由Object对象派生了一个对象,作为这个函数的构造绑定对象,在函数中用prototype指向这个对象。

原型链的向上搜索

派生对象或实例化对象,都要为新对象分配一个独占的空间。并且把原型对象的属性和方法复制一份给新对象,而这个复制仅仅是引用复制(即浅复制)

(其实在js中有很多种构造方式,每种构造方式都有不同的实例过程,在java、c++、c#中,实例化对象的过程是固定的,这也就造成了js的功能复杂性。这里讨论大家常用的实例化方法,即使用new来创建对象的方法)

当然我们也可以在修改原型对象的属性或替换原型对象。

在查询属性或方法时,当前对象没有查询到时,会自动在原型对象中查询,依次沿原型链向上。

由于在派生和实例化的过程中,新对象和新变量都会保留对原型对象的引用。当函数调用时,需查找和获取的变量和元素都会通过原型链机制一层层的往上搜索在原型对象或继承来的对象中获得。

实例化对象产生新变量的三种方式

1、字面量方式

通过Object函数创建D变量。

var D={}

Object对象通过Object构造函数,实例化获得变量D。变量D的__proto__指向Object对象。

var a = {};
console.log(a.prototype);  //undefined,未定义
console.log(a.__proto__);  //{},对象Object
console.log(a.constructor); //[Function: Object],函数Object
console.log(a.__proto__.constructor);  //[Function: Object],函数Object

2、构造函数方式

通过构造函数B创建对象C

function B(){}
var C=new B()

B函数定义时,系统会自动由Object对象派生一个中间对象作为函数的构造绑定对象Temp。通过函数B实例化变量时,就是对Temp对象进行实例化得到变量C。变量C就拥有Temp对象的属性方法(就是原始Object对象的属性和方法)+构造函数中的属性方法。变量的__proto__ 指向这个Temp对象,变量的Constructor指向函数。

var A = function(){};
console.log(A.prototype);  //A {},A函数的构造绑定对象
console.log(A.__proto__);  //[Function],Function对象
var a = new A();
console.log(a.__proto__); //A {},A函数的构造绑定对象
console.log(a.constructor); //[Function: A],函数A
console.log(a.constructor.prototype); //A {},A函数的构造绑定对象
console.log(a.__proto__.__proto__); // {},(Object对象)
console.log(a.__proto__.__proto__.__proto__); //null

3、通过Object.creat创建对象

如图中通过对象D创建对象E

var E=Object.creat(D)

E变量的原型链指向对象D。

var a1 = {'age':1}
var a2 = Object.create(a1);
console.log(a2.__proto__); //Object { age: 1 }
console.log(a2.constructor); //[Function: Object]

案例讲解

现在我们再来看案例。是不是清晰多了。js在线测验网站http://tool.lu/coderunner/

function Person () {
}
var person1 = new Person();       
Person.prototype.age= 18;
Person.__proto__.name= "小明";
var person2 = new Person(); 
console.log(person1.age);//18
console.log(person2.age); //18
console.log(person2.name);  //未定义

var person1 = new Person(); 这条语句。通过函数实例化了一个变量,系统自动创建一个Object对象派生的中间对象Temp作为与构造函数绑定的原型对象。Person.prototype就指向这个中间对象Temp。
Person.prototype.age修改了Temp对象。
Person.__proto__.name,我们知道函数都是由Function对象派生的,这句话就是修改的Function对象对象。
var person2 = new Person(); 这个语句同样通过函数实例化一个对象。一个构造函数只能绑定一个原型对象,所以这个原型对象就是Temp对象
person1.age访问了age属性,先在当前空间中查找,没有找到,于是沿原型链向上查找这个原型对象Temp。查找成功。
person2.name在变量和原型对象Temp中都不存在,所以显示未定义。

下面的留给读者自己理解

var a1 = {'age':1}
console.log(a1.prototype);  //undefined,未定义
console.log(a1.__proto__);  //{},对象Object
console.log(a1.constructor); //[Function: Object],函数Object
console.log(a1.__proto__.constructor);  //[Function: Object],函数Object

var a2 = Object.create(a1);
console.log(a2.__proto__); //{ age: 1 },对象a1
console.log(a2.constructor); //[Function: Object],对象Function

var Person = function(){};
console.log(Person.prototype);  //Person {},函数Person的构造绑定对象
console.log(Person.__proto__);  //[Function],对象Function
var person1 = new Person();
console.log(person1.__proto__); //Person {},函数Person的构造绑定对象
console.log(person1.constructor); //[Function: Person],函数Person
console.log(person1.constructor.prototype); //Person {},函数Person的构造绑定对象
console.log(person1.__proto__.__proto__); // {},(Object对象)
console.log(person1.__proto__.__proto__.__proto__); //null


Person.prototype.age= 18;
Person.__proto__.name= "小明";
var person2 = new Person(); 
console.log(person1.age);//18
console.log(person2.age); //18
console.log(person2.name);  //未定义

【作用域】

javascript中的作用域可以理解为一个语句执行的环境大小,有全局的作用域,函数作用域和eval作用域。在JS中没有块级作用域。

讲到作用域,不得不讲执行环境,执行环境在JS中是最为重要的概念。执行环境定义了变量或函数有权访问的其他数据,决定了他们各自的行为。每个执行环境都有一个与之关联的环境对象,环境中定义的所有变量和函数都保存在这个环境对象中。在web浏览器中全局环境被认为是window对象,某个执行环境中的所有代码执行完毕后就被该环境销毁,保存在其中的所有变量和函数定义也随即销毁。

每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。

当代码在一个环境中执行时,会创建环境对象的一个作用域链。作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端始终是当前执行的代码所在外部环境的环境对象。作用域链中的下一个环境对象来自包含(外部)环境,再下一个环境对象则来自于再下一个包含环境,这样一直延续到全局执行环境,全局执行环境的环境对象始终都是作用域链中的最后一个对象。

需注意的是:在局部作用域中定义的变量可以在全局环境和局部环境中交互使用。内部环境可以通过作用域链访问所有的外部环境,但外部环境不可以访问内部环境中的任何变量和函数。每个环境都可以向上搜索作用域链,以查询变量和函数名,但任何环境都不可以通过向下搜索作用域链而进入另一个执行环境。

作用域链本质上是一个指向环境对象的指针列表,他只引用但不包含环境对象。

【闭包】

闭包是指有权访问另一个函数作用域中的变量的函数,这里要把它与匿名函数区分开(匿名函数:创建一个函数并将它赋值给一个变量,这种情况下创建的函数叫匿名函数,匿名函数的name属性是空字符串),创建闭包的常见方式就是在一个函数内部创建另一个函数。闭包保存的是整个变量的对象。

闭包的作用:在函数执行过程中,为读取和写入变量的值,就需要在作用域链中查找变量,这时灵活方便的闭包就派上用场,我们知道当一个函数被调用时就会创建一个执行环境及相应的作用域链,那么闭包就会沿着作用域链向上获取到开发者想要的变量及元素。

闭包灵活方便,也可以实现封装,这样就只能通过对象的特定方法才能访问到其属性。但是,不合理的使用闭包会造成空间的浪费,内存的泄露和性能消耗。

当函数被创建,就有了作用域,当被调用时,就有了作用域链,当被继承时就有了原型链,当需要获取作用域链或原型链上的变量或值时,就有了闭包。

作者:luanpeng825485697 发表于2017/11/17 20:02:13 原文链接
阅读:42 评论:0 查看评论

【拜小白opencv】37-形态学滤波2——膨胀

$
0
0

常言道“温故而知新”,写此文章就是对自己目前学习内容的小小的总结与记录。

本文力求用最简洁的语言,详细的代码将此部分内容讲解清楚,但由于博主同样是刚刚接触OpenCV,或许表达上有些瑕疵,还望读者能够指教探讨,大家共同进步。

博主机器配置为:VS2013+opencv2.4.13+Win-64bit。

若本文能给读者带来一点点启示与帮助,我就很开心了。

====================分割线====================


形态学操作就是基于形状的一系列图像处理操作。OpenCV为进行图像的形态学变换提供了快捷、方便的函数。最基本的形态学操作有二种,他们是:腐蚀与膨胀(Erosion 与 Dilation)。

膨胀与腐蚀能实现多种多样的功能,主要如下:

  • 1、消除噪声。
  • 2、分割(isolate)独立的图像元素,以及连接(join)相邻的元素。
  • 3、寻找图像中的明显的极大值区域或极小值区域。

在进行腐蚀和膨胀的讲解之前,首先需要注意,腐蚀和膨胀是对白色部分(高亮部分)而言的,不是黑色部分。

膨胀就是图像中的高亮部分进行膨胀,“领域扩张”,效果图拥有比原图更大的高亮区域。

腐蚀就是原图中的高亮部分被腐蚀,“领域被蚕食”,效果图拥有比原图更小的高亮区域。


也可以这么理解:

腐蚀是指:将卷积核B滑过图像A,找出卷积核区域内最小像素值作为锚点像素值。这一操作可以扩大低像素值区域。
膨胀是指:将卷积核B滑过图像A,找出卷积核区域内最大像素值作为锚点像素值。这一操作可以缩小低像素值区域。


本文主要说下膨胀内容,腐蚀请见文章:【拜小白opencv】36-形态学滤波1——腐蚀

=================分割线================

1-膨胀

  • 1、膨胀是求局部最大值的操作。从数学角度来说,膨胀或者腐蚀操作就是将图像(或图像的一部分区域,称之为A)与核(称之为B)进行卷积。
  • 2、核可以是任何形状和大小,它拥有一个单独定义出来的参考点,我们称其为锚点(anchorpoint)。多数情况下,核是一个小的,中间带有参考点和实心正方形或者圆形。其实,可以把核视为模板或者掩码。
  • 3、而膨胀就是求局部最大的操作。核B与图像卷积,即计算核B覆盖的区域的像素点的最大值,并把这个最大值赋值给参考点指定的像素。这样就会使图像中高亮区逐渐增大,如下图所示。

                                         图--膨胀原理示意图
膨胀的数学表达式如下:

==============分割线==============

2-膨胀函数dilate()

此函数作用:可实现对高亮区域的增加。
下面来看看dilate()函数的定义:
void dilate( InputArray src, OutputArray dst, InputArray kernel,
                          Point anchor=Point(-1,-1), int iterations=1,
                          int borderType=BORDER_CONSTANT,
                          const Scalar& borderValue=morphologyDefaultBorderValue() );

参数解释
  • 参数1:输入图像,即源图像。图像通道的数量可以是任意的,但图像深度应为CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。
  • 参数2:输出图像,即目标图像,需要和源图片有一样的尺寸和类型。
  • 参数3:InputArray类型的kernel,腐蚀操作的内核。若为NULL时,表示的是使用参考点位于中心3x3的核。我们一般使用函数getStructuringElement配合这个参数的使用。getStructuringElement()函数会返回指定形状和尺寸的结构元素(内核矩阵)。有关getStructuringElement()函数请见下面内容。
  • 参数4:Point类型的anchor,锚的位置,其有默认值(-1,-1),表示锚位于单位(element)的中心,我们一般不用管它。
  • 参数5:int类型的iterations,迭代使用erode()函数的次数,默认值为1。
  • 参数6:int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT。
  • 参数7:const Scalar&类型的borderValue,当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),一般我们不用去管他。需要用到它时,可以看官方文档中的createMorphologyFilter()函数得到更详细的解释。

使用dilate()函数,一般我们只需要填前面的三个参数,后面的四个参数都有默认值。而且往往结合getStructuringElement一起使用。

有关getStructuringElement()函数:
Mat getStructuringElement(int shape, Size ksize, Point anchor=Point(-1,-1));
参数解释:
  • 参数1:表示内核的形状,可以选择如下三种形状之一:矩形--MORPH_RECT; 交叉形--MORPH_CROSS; 椭圆形--MORPH_ELLIPSE 。
  • 参数2:内核的尺寸。
  • 参数3:锚点的位置。
我们一般在调用erode()以及dilate()函数之前,先定义一个Mat类型的变量来获得getStructuringElement函数的返回值。对于锚点的位置,有默认值Point(-1,-1),表示锚点位于中心。且需要注意,十字形的element形状唯一依赖于锚点的位置。而在其他情况下,锚点只是影响了形态学运算结果的偏移。

====================分割线====================

3-代码演示

/*
功能:形态学滤波:膨胀操作
*/

#include <opencv2/core/core.hpp>                
#include <opencv2/highgui/highgui.hpp>                
#include <opencv2/imgproc/imgproc.hpp>               
#include <iostream>              
using namespace std;
using namespace cv;

int main()
{
	Mat srcImage, dstImage; //源图像,输出图像
	//---------【1】读取源图像并检查图像是否读取成功---------      
	srcImage = imread("D:\\OutPutResult\\ImageTest\\xing.jpg");
	if (!srcImage.data)
	{
		cout << "读取图片错误,请重新输入正确路径!\n";
		system("pause");
		return -1;
	}
	imshow("【源图像】", srcImage);
	//---------【2】获取自定义核---------
	Mat element = getStructuringElement(MORPH_RECT, Size(4, 4));
	//---------【3】进行膨胀操作---------
	dilate(srcImage, dstImage, element);
	//---------【4】显示效果图---------
	imshow("【效果图--膨胀操作】", dstImage);
	waitKey(0);
	return 0;
}

===========分割线===============

4-显示结果


=================分割线===========

5-程序说明

只要记住腐蚀和膨胀都是对白色部分(也就是高亮部分)而言,不是黑色部分。
因此膨胀操作后,“拜小白”的文字显示比较小,是因为周围白色部分变大了。

================END=================


作者:sinat_36264666 发表于2017/11/17 20:16:45 原文链接
阅读:21 评论:0 查看评论

不推荐使用注解 @Deprecated

$
0
0
加上 @Deprecated 后
方法名称显示:



中划线(删除线)
意为:
发生这些变化并不会影响编译,只是提醒一下程序员,这个方法以后是要被删除的,最好别用。
就是如果一个类从另外一个类继承,并且override被继承类的Deprecated方法,在编译时将会出现一个警告。

参考:
作者:wide288 发表于2017/11/17 20:19:01 原文链接
阅读:55 评论:0 查看评论

cocos-lua学习笔记(七)场景迁移及迁移动画

$
0
0


如何使用cocos-lua去迁移场景呢,我下面的例子详细的说明了如何使用。

使用的版本是3.7,也就是目前最新版本的引擎。

主场景类

local MainScene = class("MainScene", function()
    return display.newScene("MainScene")
end)

function MainScene:ctor()
    print("MainScene:ctor")
        --这是一个按钮
    local btn = ccui.Button:create("button/btnDog_N.png", "button/btnDog_P.png", "button/btnDog_D.png", 0)
        :pos(display.cx, 100)
        :addTo(self)
        --按钮文字
        btn:setTitleText("点我迁移场景")
        --字体大小
        btn:setTitleFontSize(25)
        --偏移
        btn:setTitleOffset(20, 100)
        --字体颜色
        btn:setTitleColor(cc.c3b(255, 255, 255))
        --按钮的回调函数
        btn:addTouchEventListener(function(sender, eventType)
        if (0 == eventType)  then
            print("pressed")
        elseif (1 == eventType)  then
              print("move")
        elseif  (2== eventType) then
            nextScene = require("app.scenes.DogScene").new()
            print(nextScene)
            local transition = display.wrapSceneWithTransition(nextScene, "fade", 0.5)
            --替换,释放mainscence
            --display.replaceScene(transition)

            --这个画页不释放
            cc.Director:getInstance():pushScene(transition)
        elseif  (3== eventType) then
            print("cancel")
        end
    end)

end

function MainScene:onEnter()
end

function MainScene:onExit()
      print("onExit")
end

return MainScene


Dog场景类

local DogScene = class("DogScene", function()
    return display.newScene("DogScene")
end)

function DogScene:ctor()
    print("DogScene")
        --这是一个按钮
    local btn = ccui.Button:create("dog.png", "dog.png", "dog.png", 0)
        :pos(display.cx, 100)
        :addTo(self)
        --按钮文字
        btn:setTitleText("按钮")
        --字体大小
        btn:setTitleFontSize(25)
        --偏移
        btn:setTitleOffset(20, 100)
        --字体颜色
        btn:setTitleColor(cc.c3b(255, 255, 255))
        --按钮的回调函数
        btn:addTouchEventListener(function(sender, eventType)
        if (0 == eventType)  then
            print("pressed")
            btn:setColor(cc.c3b(200, 200, 200))
        elseif (1 == eventType)  then
              print("move")
        elseif  (2== eventType) then
            print("pushScene")
            btn:setColor(cc.c3b(255, 255, 255))
            cc.Director:getInstance():popScene()
        elseif  (3== eventType) then
            print("cancel")
        end
    end)

    --按钮无效
    --btn:setEnabled(false)
end

function DogScene:onEnter()
end

function DogScene:onExit()
end

return DogScene



点击 此处进行下载  <-点这里去下载我的代码~~~~~~~~~~~~~~~~~~~~~~~~~~~~~




效果如下:




让我们打开display.lua 这里面有一段如下注释。


可用的过渡效果有:

-   crossFade 淡出当前场景的同时淡入下一个场景
-   fade 淡出当前场景到指定颜色,默认颜色为 cc.c3b(0, 0, 0),可用 wrapSceneWithTransition() 的最后一个参数指定颜色
-   fadeBL 从左下角开始淡出场景
-   fadeDown 从底部开始淡出场景
-   fadeTR 从右上角开始淡出场景
-   fadeUp 从顶部开始淡出场景
-   flipAngular 当前场景倾斜后翻转成下一个场景,默认从左边开始翻转,可以指定为:
    -   cc.TRANSITION_ORIENTATION_LEFT_OVER 从左边开始
    -   cc.TRANSITION_ORIENTATION_RIGHT_OVER 从右边开始
    -   cc.TRANSITION_ORIENTATION_UP_OVER 从顶部开始
    -   cc.TRANSITION_ORIENTATION_DOWN_OVER 从底部开始
-   flipX 水平翻转,默认从左往右翻转,可用的附加参数同上
-   flipY 垂直翻转,默认从上往下翻转,可用的附加参数同上
-   zoomFlipAngular 倾斜翻转的同时放大,可用的附加参数同上
-   zoomFlipX 水平翻转的同时放大,可用的附加参数同上
-   zoomFlipY 垂直翻转的同时放大,可用的附加参数同上
-   jumpZoom 跳跃放大切换场景
-   moveInB 新场景从底部进入,直接覆盖现有场景
-   moveInL 新场景从左侧进入,直接覆盖现有场景
-   moveInR 新场景从右侧进入,直接覆盖现有场景
-   moveInT 新场景从顶部进入,直接覆盖现有场景
-   pageTurn 翻页效果,如果指定附加参数为 true,则表示从左侧往右翻页
-   rotoZoom 旋转放大切换场景
-   shrinkGrow 收缩交叉切换场景
-   slideInB 新场景从底部进入,现有场景同时从顶部退出
-   slideInL 新场景从左侧进入,现有场景同时从右侧退出
-   slideInR 新场景从右侧进入,现有场景同时从左侧退出
-   slideInT 新场景从顶部进入,现有场景同时从底部退出
-   splitCols 分成多列切换入新场景
-   splitRows 分成多行切换入新场景,类似百叶窗
-   turnOffTiles 当前场景分成多个块,逐渐替换为新场景

]]

-- end --



我们来更改一下代码

            local transition = display.wrapSceneWithTransition(nextScene, "zoomFlipX", 0.9)

效果如下:




我们再来更改一种

            local transition = display.wrapSceneWithTransition(nextScene, "pageTurn", 0.9,true)


效果如下:





另外一个要说明的是

如果使replaceScene迁移场景,当前场景会被释放   
display.replaceScene(transition)

如果使pushScene,当前场景会在栈底,下一个场景会进栈。        
cc.Director:getInstance():pushScene(transition)


作者:hiwoshixiaoyu 发表于2017/11/17 21:58:02 原文链接
阅读:22 评论:0 查看评论

计组、离散,对编程特别重要吗?

$
0
0

  今天,到青岛主持一个信息化教学培训班,回家很晚了。在群中胡逛一会休息。
  有学生提问。
【学生】
  老师我以后想考计算机专业,计算机组成原理、还有离散数学我专业都没学,这些对编程是不是特别重要?
【迂者】
  正好我的博客中这篇文章今天有新评论,你先看看。《将“操作系统”当“高级C语言”如何?
【学生】
  恩,我好好看看。
【迂者】
  编程,我们说编得一手好程序,要懂计算,懂计算机,关键在思维,用计算机语言写出来的那些东东,只不过是表达方式之一而已。思维是内功,写出语句是招式。内功重要还是招式重要?它们之间的关系如何?练武之人如何看内功和招式,在这里都适用?
【学生】
  恩,我好好看看。
【迂者】
  思维的训练也离不开具体的编程。两者不偏废,交叉并行前进。
【学生】
  我也一直认同这个观点,思维才是最重要的。
  思维锻炼出来了,写代码只是一个翻译过程。
  不过我还有待学习
  恩,用编程去表达思维。
【迂者】
  但如果现在就着急就业了,只能先在拳脚招式上下功夫,先弄口饭吃,在工作中加紧学,也算是一种途径。

作者:sxhelijian 发表于2017/11/17 22:30:52 原文链接
阅读:70 评论:0 查看评论
Viewing all 35570 articles
Browse latest View live