-
Notifications
You must be signed in to change notification settings - Fork 0
/
content.json
1 lines (1 loc) · 260 KB
/
content.json
1
[{"title":"CentOS 7 下Tomcat启动超慢的原因及解决方案","date":"2019-01-24T19:25:00.000Z","path":"archives/tomcat-start-slow-random/","text":"现象CentOS 7系统中安装好openjdk和Tomcat后,启动过程很慢,长达数分钟,日志如下:12345678910111213141517:27:53.596 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.3817:27:53.644 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/docs]17:32:31.001 WARNING [localhost-startStop-1] org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [276,660] milliseconds.17:32:31.022 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/docs] has finished in [277,378] ms17:32:31.022 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/manager]17:32:31.101 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/manager] has finished in [79] ms17:32:31.101 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/examples]17:32:31.509 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/examples] has finished in [408] ms17:32:31.510 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/host-manager]17:32:31.559 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/host-manager] has finished in [49] ms17:32:31.559 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/ROOT]17:32:31.576 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/ROOT] has finished in [17] ms17:32:31.605 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [\"http-nio-8080\"]17:32:31.660 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [\"ajp-nio-8009\"]17:32:31.662 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 278084 ms tomcat启动耗时278084ms折合278秒,对于刚刚安装的干净tomcat,这肯定是不对劲的。其中有一条日志引起了笔者的注意:117:32:31.001 WARNING [localhost-startStop-1] org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [276,660] milliseconds. 显然tomcat执行到这里时出问题了,google了一下,经过一番搜索明白了其中的缘由。 原因在tomcat官方wiki文档的HowToFasterStartUp章节中,Entropy Source部分有一段这样的说明: Tomcat 7+严重依赖SecureRandom类为其sessionID和其他地方提供随机值。如果用于初始化SecureRandom的熵源缺少熵,则可能会在启动期间导致延迟,具体取决于您的JRE。发生这种情况时,您会在日志中看到警告,例如: org.apache.catalina.util.SessionIdGenerator createSecureRandomINFO: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [5172] milliseconds.有一种方法可以通过设置以下系统属性来配置JRE以使用非阻塞熵源:-Djava.security.egd = file:/dev/./urandom另请注意,使用非阻塞源替换阻塞熵源实际上会降低安全性,因为您获得的随机数据较少。 从这里我们得知Tocmat的Session ID是通过SHA1PRNG算法计算得到的,计算Session ID的时候必须有一个密钥,为了提高安全性Tomcat在启动的时候会通过随机生成一个密钥,它强依赖于获取熵池中的随机数来进行创建。那么什么是/dev/random?什么是熵池? /dev/random从维基百科得知,在UNIX操作系统(包括类UNIX系统)中,/dev/random是一个特殊的设备文件,可以用作随机数生成器或伪随机数生成器。Linux内核中的是第一个以背景噪声产生真正的随机数产生的实现,它允许程序访问来自设备驱动程序或其它来源的背景噪声。Linux上有两个通用的随机设备:/dev/random和/dev/urandom。其中/dev/random的随机性最好,因为它是一个阻塞的设备。而/dev/random的一个副本是/dev/urandom(“unblocked”,非阻塞的随机数生成器),它会重复使用熵池中的数据以产生伪随机数据。这表示对/dev/urandom的读取操作不会产生阻塞,但其输出的熵可能小于/dev/random的。所以它可以作为生成较低强度密码的伪随机数生成器,不建议用于生成高强度长期密码。 熵池熵池本质上是若干字节,/proc/sys/kernel/random/entropy_avail中存储了熵池现在的大小,/proc/sys/kernel/random/poolsize是熵池的最大容量,单位都是bit。如果entropy_avail的值小于要产生的随机数bit数,那么/dev/random就会堵塞。 为什么熵池不够用? 熵池实际上是从各种noice source中获取数据,noice source可能是键盘事件、鼠标事件、设备时钟中等。linux内核从2.4升级到2.6时,处于安全性的考虑,废弃了一些source。source减少了,熵池补给的速度当然也变慢,进而不够用。其实,通过消耗熵池,可以构造DDOS攻击。原理很简单,熵池空了,依赖随机数的业务(SSL,加密等)就不能正常进行。 通过以上信息,笔者得知该问题是由于熵池不足导致的。怎么解决? 解决方案方法一、降低熵生成的随机性要求使用非阻塞性的生成器/dev/urandom代替/dev/random。 1、可在JVM环境中配置通过配置发生器指定熵收集守护进程修改$JAVA_PATH/jre/lib/security/java.security中参数securerandom.source为:1securerandom.source=file:/dev/./urandom 2、也可在Tomcat环境中配置通过配置JRE使用非阻塞的Entropy Source获取熵在$TOMCAT_HOME/bin/catalina.sh中加入:123if [[ \"$JAVA_OPTS\" != *-Djava.security.egd=* ]]; then JAVA_OPTS=\"$JAVA_OPTS -Djava.security.egd=file:/dev/./urandom\"fi 这个系统属性egd表示熵收集守护进程(entropy gathering daemon)。 方法二、使用熵生成器补充熵池(推荐)1、[硬件随机数生成器]安装并使用rng-tools作为额外的熵随机数生成器(推荐)12345678910# 安装rng-toolsyum install rng-tools -y# 测试rngdrngd -f# 启动rngdsystemctl start rngd# 设置自启动systemctl enable rngd# 查看自启动列表systemctl list-unit-files cat /dev/random命令会消耗熵池,rngd守护进程会补充熵池,可使用如下命令来测试随机数生成的情况:123456789101112131415161718cat /dev/random | rngtest -c 100# 测试结果rngtest 6Copyright (c) 2004 by Henrique de Moraes HolschuhThis is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.rngtest: starting FIPS tests...rngtest: bits received from input: 2000032rngtest: FIPS 140-2 successes: 100rngtest: FIPS 140-2 failures: 0rngtest: FIPS 140-2(2001-10-10) Monobit: 0rngtest: FIPS 140-2(2001-10-10) Poker: 0rngtest: FIPS 140-2(2001-10-10) Runs: 0rngtest: FIPS 140-2(2001-10-10) Long run: 0rngtest: FIPS 140-2(2001-10-10) Continuous run: 0rngtest: input channel speed: (min=13.823; avg=42.721; max=10761.019)Kibits/srngtest: FIPS tests speed: (min=93.041; avg=129.531; max=136.239)Mibits/srngtest: Program run time: 45733452 microseconds 2、[软件随机数生成器]在rng-tools仍不满足的情况下,可使用haveged作为额外的熵随机数生成器 haveged项目的目的是提供一个简单易用的不可预测随机数生成器,基于HAVEGE算法。Haveged可以解决在某些情况下,系统熵过低的问题。此程序无法保证熵的质量,如果对安全要求较高,请考虑使用硬件随机数生成器rng-tools。 要检查是否需要 Haveged,可使用下面命令查看当前收集到的熵:1cat /proc/sys/kernel/random/entropy_avail 如果结果比较低 (<1000),建议安装 haveged,否则加密程序会处于等待状态,直到系统有足够的熵。123456# 安装havegedyum install haveged -y# 启动havegedsystemctl start haveged# 设置自启动systemctl enable haveged 安装 haveged 之后,可以再次查看系统熵看下有无提升。 因为方法一存在一定的不安全性,且需要对环境进行配置,为了满足熵的需要,这里笔者选择了第二种方法,使用rng-tools作为额外的熵随机数生成器,同以上操作后顺利解决了问题。 操作后重启tomcat日志如下,启动速度快了两个数量级:123456789101112131417:58:07.068 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.3817:58:07.088 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/docs]17:58:07.740 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/docs] has finished in [652] ms17:58:07.740 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/manager]17:58:07.815 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/manager] has finished in [75] ms17:58:07.816 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/examples]17:58:08.241 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/examples] has finished in [425] ms17:58:08.241 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/host-manager]17:58:08.268 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/host-manager] has finished in [27] ms17:58:08.269 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/ROOT]17:58:08.306 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/ROOT] has finished in [37] ms17:58:08.335 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [\"http-nio-8080\"]17:58:08.424 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [\"ajp-nio-8009\"]17:58:08.429 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 1411 ms 参考文档:https://stackoverflow.com/questions/40383430/tomcat-takes-too-much-time-to-start-java-securerandomhttps://bugs.java.com/bugdatabase/view_bug.do?bug_id=6202721http://openjdk.java.net/jeps/123https://zh.wikipedia.org/zh-hans//dev/randomhttps://wiki.apache.org/tomcat/HowTo/FasterStartUphttps://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security_guide/sect-security_guide-encryption-using_the_random_number_generatorhttps://wiki.archlinux.org/index.php/Rng-toolshttps://wiki.archlinux.org/index.php/Havegedhttps://www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged","tags":[{"name":"软件开发","slug":"软件开发","permalink":"http://inplus.top/tags/软件开发/"},{"name":"tomcat","slug":"tomcat","permalink":"http://inplus.top/tags/tomcat/"}]},{"title":"python3爬虫之有道翻译(下)","date":"2018-08-10T22:01:00.000Z","path":"archives/youdao-spider-bottom/","text":"上一篇我们讲到分析有道翻译接口请求,并利用python3构造参数爬取接口。在本篇中,我将会针对有道翻译接口进行图形化界面的设计。 一、器欲尽其能,必先得其法。 像java中的AWT和Swing一样,在python3中也自带了GUI工具包,利用其中的Tkinter组件,我们可以方便快捷的设计我们的图形界面。 PS:需要注意的是,在python2和python3中其导入方式存在差异。1234# Python2.x:from Tkinter import *# Python3.x:from tkinter import * 二、操千曲而后晓声,观千剑而后识器。 那么该如何使用该模块呢,通过下面一个Hello World程序我们可以对tkinter有一个简单的认识。12345678910111213141516171819202122232425import tkinter as tkclass Application(tk.Frame): def __init__(self, master=None): super().__init__(master) self.master = master self.pack() self.create_widgets() def create_widgets(self): self.hi_there = tk.Button(self) self.hi_there[\"text\"] = \"你好\\n(点击我)\" self.hi_there[\"command\"] = self.say_hi self.hi_there.pack(side=\"top\") self.quit = tk.Button(self, text=\"退出\", fg=\"red\", command=self.master.destroy) self.quit.pack(side=\"bottom\") def say_hi(self): print(\"大家好!\")root = tk.Tk()app = Application(master=root)app.mainloop() 三、只要功夫深,铁杵磨成针对tkinter有了简单的了解后,首先我们在面板上添加文本区组件和按钮组件,将主要功能展示出来 其次,我们针对不同的语言增加翻译选项 重新调整组件和布局 这样,一个简单的GUI界面就实现了,好像有点丑,一股浓浓的windows经典风格。。。 四、不畏浮云遮望眼,只缘身在最高层。 我们前面都是直接使用tkinter模块下的 GUI 组件,这些组件看上去特别复(chou)古(lou),仿佛将我门带回了20年前。为了更好的视觉效果,Tkinter后来引入了一个ttk组件作为补充(主要就是简单包装、美化一下),并使用功能更强大的Combobox取代了原来的Listbox,且新增了 LabeledScale(带标签的 Scale)、Notebook(多文档窗口)、Progressbar(进度条)、Treeview(树)等组件。ttk作为一个模块被放在tkinter包下,使用ttk组件与使用普通的Tkinter组件并没有多大的区别,只要导入ttk模块即可。 其实,tkinter中还存在一个进阶组件ttk,tk带有17个小部件,其中11个已经存在于tkinter中:Button,Checkbutton,Entry,Frame,Label,LabelFrame,Menubutton,PanedWindow,Radiobutton,Scale和Scrollbar。 6个新的窗口小部件类是:Combobox,Notebook,Progressbar,Separator,Sizegrip和Treeview。所有这些类都是Widget的子类。导入方式如下:123456789# Python2.x:from Tkinter import *# 导入ttkfrom ttk import *# Python3.x:from tkinter import *# 导入ttkfrom tkinter import ttk 然后我们利用ttk模块,对组件样式进行优化,并且利用pyperclip模块对剪贴板进行相应的读写操作。 还可利用Progressbar进度条组件,增加进度条显示 以及菜单、多标签和弹出窗体的实现 我们还可利用pyinstaller将程序打包成exe在windows平台上进行方便的使用,这样我们利用python的GUI就完成了有道词典的图形界面制作。 最后,附上完整代码:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285# -*- coding:utf-8 -*-import timeimport threadingimport tkinter as tkfrom tkinter import ttkfrom tkinter import messagebox as mBoximport hashlibimport jsonimport randomimport pyperclipimport webbrowserimport base64import osfrom urllib import parsefrom urllib import request\"\"\"类说明:有道词典翻译的类\"\"\"class YOUDAO: def _quit(self): self.exitFlag = False mBox.showinfo(title='小y温馨提示', message='感谢您的使用~') self.root.quit() self.root.destroy()# exit() def _progressGo(self): self.proBar.grid(row=0, column=0) for i in range(100): if not self.exitFlag: return self.proBar[\"value\"] = i + 1 self.root.update() time.sleep(0.06) self.proBar.grid_forget() def __init__(self, width=500, height=300): self.w = width self.h = height self.title = '有道词典(特别开心版)' self.root = tk.Tk(className=self.title) # 绑定关闭窗口为自定义函数 self.root.protocol(\"WM_DELETE_WINDOW\", self._quit) self.radio = tk.StringVar() self.radio.set('AUTO') self.exitFlag = True self.errorFlag = 0 self.nextFlag = 0 # 创建tabControl tabControl = ttk.Notebook(self.root) # 创建tab tab1 = ttk.Frame(tabControl) tabControl.add(tab1, text='O(∩_∩)O~') tabControl.pack(expand=1, fill=\"both\") tab2 = ttk.Frame(tabControl) tabControl.add(tab2, text='点我点我') tabControl.pack(expand=1, fill=\"both\") ttk.Label(tab2, text=\"作者长得帅\").pack(pady=100) # 创建Frame空间 # pack控件布局 frame1 = ttk.Frame(tab1) frame2 = ttk.LabelFrame(tab1, text='翻译区') frame3 = ttk.Frame(tab1) # 创建MenuBar menuBar = tk.Menu(self.root) self.root.config(menu=menuBar) # 创建menu menu1 = tk.Menu(menuBar, tearoff=0) menuBar.add_cascade(label='菜单', menu=menu1) # 添加菜单项 menu1.add_command(label='关于作者', command=lambda:webbrowser.open('http://inplus.top')) menu1.add_separator() menu1.add_command(label='退出', command=self._quit) toLangDictList = [{'自动':'AUTO'}, {'汉->日':'ja'}, {'汉->韩':'ko'}, {'汉->法':'fr'}, {'汉->俄':'ru'}, {'汉->西班牙':'es'}, {'汉->葡萄牙':'pt'}, {'汉->越':'vi'}] # 控件内容设置 # 使用grid布局需要填写行列 # 使用pack的side布局方式可以依次排开 # ipadx控制左右内边距,ipady控制上下内边距 # padx控制左右外边距,padx控制上下外边距 # row控制行数,column控制列数 # rowspan控制占据行数,columnspan控制占据列数 # sticky控制位置,W、N、S、E、W+N等等八个方位 ttk.Label(frame1, text=\"模式:\").pack(side=tk.LEFT) for i in range(len(toLangDictList)): textKey = list(toLangDictList[i].keys())[0] textValue = list(toLangDictList[i].values())[0] # Radiobutton的indicatoron默认为1,当设置成0时,则其外观是Sunken tk.Radiobutton(frame1, text=textKey, variable=self.radio, value=textValue, command=lambda:self.text_translateAnsy(1), indicatoron=0).pack(side=tk.LEFT) label1 = ttk.Label(frame2, text=\"请输入要翻译的文本:\") self.text1 = tk.Text(frame2, height=6, width=35) translateButton1 = ttk.Button(frame2, text=\"翻译▼\", command=lambda:self.text_translateAnsy(1)) translateButton3 = ttk.Button(frame2, text=\"从剪贴板翻译\", command=self.pasteAndExecute) label2 = ttk.Label(frame2, text=\"翻译结果:\") self.text2 = tk.Text(frame2, height=6, width=35) translateButton2 = ttk.Button(frame2, text=\"自动▲\", command=lambda:self.text_translateAnsy(2)) translateButton4 = ttk.Button(frame2, text=\"复制结果到剪贴板\", command=lambda:pyperclip.copy(self.text2.get(1.0, tk.END)[:-1])) self.proBar = ttk.Progressbar(frame3, length=200, mode=\"determinate\", orient=tk.HORIZONTAL) self.proBar[\"maximum\"] = 100 self.proBar[\"value\"] = 0 # ttk需要使用style style = ttk.Style() style.configure(\"BW.TLabel\", foreground='red', font=('楷体', 12, 'bold')) label_tip = ttk.Label(frame3, text='作者:风澈', style=\"BW.TLabel\") frame1.pack(pady=10) frame2.pack() frame3.pack() label1.grid(row=2, column=0) self.text1.grid(row=2, column=1, rowspan=2) translateButton1.grid(row=3, column=2) translateButton3.grid(row=3, column=0, padx=5) label2.grid(row=4, column=0) self.text2.grid(row=4, column=1, rowspan=2) translateButton2.grid(row=4, column=2) translateButton4.grid(row=5, column=0, padx=5) label_tip.grid(row=1, column=0) \"\"\" 创建线程,异步调用 \"\"\" def text_translateAnsy(self, mode): if self.nextFlag == 1: return translateT = threading.Thread(target=self.text_translate, args=(mode,)) translateT.setDaemon(True) translateT.start() self.progressT = threading.Thread(target=self._progressGo(), args=(mode,)) self.progressT.start() \"\"\" 函数说明:执行翻译 \"\"\" def text_translate(self, mode): self.nextFlag = 1 # 主通道 urlMain = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule' # 备用通道 urlBak = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule' # text1翻译至text2 if mode == 1: textGet = self.text1 textSet = self.text2 toLang = self.radio.get() # text2翻译至text1 if mode == 2: textGet = self.text2 textSet = self.text1 toLang = 'AUTO' if self.errorFlag == 1: urlMain = urlBak # 获取将要源text的值,并剔除最后一个字符,即text自带的一个换行符 contentWord = textGet.get(1.0, tk.END)[:-1] # 因为有道网页是textarea,识别\\r\\n但不识别\\n,在此做替换 contentWord.replace('\\n', '\\r\\n') if not contentWord: self.nextFlag = 0 self.proBar.grid_forget() return translateResults = self.conn(urlMain, contentWord, 'AUTO' , toLang) # 找到翻译结果 try: if translateResults[\"errorCode\"] == 0: newResult = '' for translateResult in translateResults[\"translateResult\"]: newResult += translateResult[0]['tgt'] + '\\n' elif translateResults[\"errorCode\"] == 40: newResult = '输入个汉语呗~~' else: mBox.showerror(title='小y温馨提示', message='网络连接异常') self.nextFlag = 0 self.proBar.grid_forget() return except: # 异常时启用备用地址翻译 if self.errorFlag == 0: self.errorFlag = 1 return self.text_translate(mode) mBox.showerror(title='小y温馨提示', message='网络连接异常') self.nextFlag = 0 self.proBar.grid_forget() return # 结束前设置进度条100,显得更符合逻辑 self.proBar[\"value\"] = 100 self.root.update() textSet.delete(1.0, tk.END) textSet.insert(tk.INSERT, newResult[:-1]) self.nextFlag = 0 self.proBar.grid_forget() \"\"\" 函数说明:连接服务器执行翻译 \"\"\" def conn(self, url, contentWord, fromLang, toLang): # 构造有道的加密参数 client = \"fanyideskweb\" ts = int(time.time() * 1000) salt = str(ts + random.randint(1, 10)) flowerStr = \"p09@Bn{h02_BIEe]$P^nG\" sign = hashlib.md5((client + contentWord + salt + flowerStr).encode('utf-8')).hexdigest() bv = '9deb57d53879cce82ff92bccf83a3e4c' # 创建Form_Data字典,存储请求体 Form_Data = {} # 需要翻译的文字 Form_Data['i'] = contentWord # 下面这些都先按照我们之前抓包获取到的数据 Form_Data['from'] = fromLang Form_Data['to'] = toLang Form_Data['smartresult'] = 'dict' Form_Data['client'] = client Form_Data['salt'] = salt Form_Data['sign'] = sign Form_Data['ts'] = ts Form_Data['bv'] = bv Form_Data['doctype'] = 'json' Form_Data['version'] = '2.1' Form_Data['keyfrom'] = 'fanyi.web' Form_Data['action'] = 'FY_BY_REALTIME' Form_Data['typoResult'] = 'false' # 对数据进行字节流编码处理 data = parse.urlencode(Form_Data).encode('utf-8') # 创建Request对象 req = request.Request(url=url, data=data, method='POST') # 写入header信息 req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36') req.add_header('cookie', '[email protected]') req.add_header('Referer', 'http://fanyi.youdao.com/') # 传入创建好的Request对象 try: # 超时时间设置3秒 response = request.urlopen(req, timeout=3) except: return # 读取信息并解码 html = response.read().decode('utf-8') # 使用JSON return json.loads(html) '''从剪贴板粘贴并执行翻译 ''' def pasteAndExecute(self): self.text1.delete(1.0, tk.END) self.text1.insert(tk.INSERT, pyperclip.paste()) self.text_translateAnsy(1) \"\"\" 函数说明:tkinter窗口居中 \"\"\" def center(self): ws = self.root.winfo_screenwidth() hs = self.root.winfo_screenheight() x = int((ws / 2) - (self.w / 2)) y = int((hs / 2) - (self.h / 2)) self.root.geometry('{}x{}+{}+{}'.format(self.w, self.h, x, y)) \"\"\" 函数说明:loop等待用户事件 \"\"\" def loop(self): # 禁止修改窗口大小 self.root.resizable(False, False) # 窗口居中 self.center() # 设置图标 self.root.iconbitmap(r'resource\\youdao.ico') # 光标焦点 self.text1.focus() self.root.mainloop()if __name__ == '__main__': app = YOUDAO() # 实例化APP对象 app.loop() # loop等待用户事件 通过此篇文章,你学会了吗? 参考资料:https://docs.python.org/3/library/tkinter.htmlhttps://wiki.python.org/moin/TkInterhttps://docs.python.org/3/library/tkinter.ttk.htmlhttps://cloud.tencent.com/developer/section/1372347https://cloud.tencent.com/developer/section/1372352https://infohost.nmt.edu/tcc/help/pubs/tkinter/web/index.html","tags":[{"name":"python","slug":"python","permalink":"http://inplus.top/tags/python/"},{"name":"爬虫","slug":"爬虫","permalink":"http://inplus.top/tags/爬虫/"}]},{"title":"python3爬虫之有道翻译(上)","date":"2018-07-27T19:25:00.000Z","path":"archives/youdao-spider-top/","text":"平时偶尔会用到翻译工具,其中最常用的就是有道翻译了,web端的有道翻译,在早期是直接可以爬到接口来使用的,但自从有道翻译推出他的API服务的时候,就对这个接口做了反爬虫的机制,从而来推广他的付费接口服务。这个反爬虫机制在爬虫领域算是一个非常经典的技术手段,今天我们就来对它一探究竟吧。 一、莫听穿林打叶声,何妨吟啸且徐行。首先我们使用chrome浏览器打开有道翻译的链接:http://fanyi.youdao.com然后使用F12或ctrl+shift+i唤起“开发者工具”,鼠标右键点击检查一样,也就是审查元素,选择Network网络监听窗口,如下图所示,之后页面中所有的请求都会在这里显示出来: 接着我们在左侧翻译的窗口输入我们需要翻译的文字,比如输入“你好”,然后浏览器就会向有道发起异步ajax请求,在下面就可以看到所有的请求: 我们点开第一条请求,在Headers可以看到,在进行翻译的时候,发送的请求就是图中Request URL后的URL: 接着我们滚动到最下面,可以看到有一个Form Data的地方,这是请求时所携带的参数,这些数据就是在翻译的时候浏览器给服务器发送的数据:Tip:在我们请求多次后,发现每次翻译时有些参数固定不变,而有些参数会动态变化,这就是我们破解有道反爬虫机制的关键点,后面会讲到。 然后再点击Response,这里就是接口返回的结果: 最后我们选择Application应用窗口,点击左侧Storage-Cookies,选择有道翻译的域名,这里存储的是cookie信息,cookie校验也是反爬虫的常见手段,这也是我们后面需要注意的: 二、工欲善其事,必先利其器。 运行平台:WindowsPython版本:Python3.xIDE:Eclipse + PyDev插件 到现在为止,我们得到了url和入参,我们就可以简单写一个爬虫,去调用有道翻译的接口了,我们选用python3来进行爬虫编写。这里使用的是Python3自带的网络请求库urllib,也伪造一下包括cookie在内的请求头,相关代码如下:123456789101112131415161718192021222324252627282930313233343536373839404142import jsonfrom urllib import parsefrom urllib import request # 等待用户输入需要翻译的单词i = input('请输入需要翻译的句子:')# 有道翻译的url链接url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'# 创建Form_Data字典,存储请求体Form_Data = {}# 需要翻译的文字Form_Data['i'] = i# 下面这些都先按照我们之前抓包获取到的数据Form_Data['from'] = 'AUTO'Form_Data['to'] = 'AUTO'Form_Data['smartresult'] = 'dict'Form_Data['client'] = 'fanyideskweb'Form_Data['salt'] = '15326858088180'Form_Data['sign'] = '4805445cac590750301ad08319a79675'Form_Data['ts'] = '1532685808818'Form_Data['bv'] = '9deb57d53879cce82ff92bccf83a3e4c'Form_Data['doctype'] = 'json'Form_Data['version'] = '2.1'Form_Data['keyfrom'] = 'fanyi.web'Form_Data['action'] = 'FY_BY_REALTIME'Form_Data['typoResult'] = 'false'# 对数据进行字节流编码处理data = parse.urlencode(Form_Data).encode('utf-8')# 创建Request对象req = request.Request(url=url, data=data, method='POST')# 写入header信息req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36')req.add_header('cookie', '[email protected]')req.add_header('Referer', 'http://fanyi.youdao.com/')# 传入创建好的Request对象response = request.urlopen(req, timeout=5)# 读取信息并进行字节流解码html = response.read().decode('utf-8')# 把返回来的json字符串解析成字典translate_results = json.loads(html)# 打印返回信息print(\"返回的结果是:%s\" % translate_results) 我们运行这个文件后,当我们输入的是“你好”的时候,我们可以得到“hello”的这个正确的翻译结果。而当我们输入其他需要翻译的字符串的时候,比如输入“我爱你”,那么就会得到一个错误代码{'errorCode': 50},这就是有道词典的反爬虫机制,接下来我们就来一步一步破解它。 三、横看成岭侧成峰,远近高低各不同。我们刚才有讲到,在有道翻译web页面尝试进行了多次翻译,并且每次翻译后都去查看相应的网络请求入参,比较每次请求的Form Data的值,我们注意到,除i代表翻译的源字符串以外,salt和sign以及ts这三个参数是动态变化的,其他的参数都是固定值。这里我分别用“great”和“date”两个单词翻译时候Form Data的数据进行比较: 经过多次变换语种等尝试,观察键值的变化,我们可以对请求携带的参数有如下猜测: i:需要进行翻译的字符串 from:源语言的语种 to:翻译后的语种 smartresult:智能结果,固定值 client:客户端,固定值 salt:加密用到的盐,待定 sign:签名字符串,待定 ts:毫秒时间戳 bv:未知的md5值,固定值 doctype:文档类型,固定值 version:版本,固定值 keyfrom:键来源,固定值 action:操作动作,固定值 typoResult:是否打印错误,固定值 那么这三个动态参数的值是怎么产生的呢?这里我们可以分析一下,这三个值在每次请求的时候都不一样,只有两种情况:第一是每次翻译的时候,浏览器会从有道服务器获取这三个值。这样可以达到每次翻译的时候值不同的需求。第二是在本地,用js代码按照一定的规则生成的。那么我们首先来看第一个情况,我们可以看到在每次发送翻译请求的时候,并没有一个请求是专门用来获取这几个值的: 所以就可以排除了第一种情况。就只剩下一种可能,那就是在本地自己生成的,如果是在本地自己生成的,那么规则是什么呢? 四、欲穷千里目,更上一层楼。这里我们点击Elements审查元素,查看网页源代码,查找所有的js文件,找到一个fanyi.min.js: 同样,我们在Sources-Page中也可以看到该js文件: 打开该js文件,可以看到该js是被压缩过的,我们复制出来使用在线格式化工具对齐进行格式化,然后把格式化后的代码,复制下来,用编辑器打开,然后搜索salt,可以找到相关的代码片段: 这里我们就可以发现动态值的生成原理了: i:需要进行翻译的字符串的前5000字 salt:当前毫秒时间戳与10以内随机数字字符串的拼接 sign:”fanyideskweb”+i+salt+”p09@Bn{h02_BIEe]$P^nG”的md5值 ts:当前毫秒时间戳 在得到salt和sign以及ts的生成原理后,我们就可以开始进一步改写Python代码,来对接有道的接口了:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253import jsonimport randomimport timeimport hashlibfrom urllib import parsefrom urllib import request # 等待用户输入需要翻译的单词i = input('请输入需要翻译的句子:')# 有道翻译的url链接url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'# 构造有道的加密参数client = \"fanyideskweb\"ts = int(time.time() * 1000)salt = str(ts + random.randint(1, 10))flowerStr = \"p09@Bn{h02_BIEe]$P^nG\"sign = hashlib.md5((client + i + salt + flowerStr).encode('utf-8')).hexdigest()bv = '9deb57d53879cce82ff92bccf83a3e4c'# 创建Form_Data字典,存储请求体Form_Data = {}# 需要翻译的文字Form_Data['i'] = i# 下面这些都先按照我们之前抓包获取到的数据Form_Data['from'] = 'AUTO'Form_Data['to'] = 'AUTO'Form_Data['smartresult'] = 'dict'Form_Data['client'] = clientForm_Data['salt'] = saltForm_Data['sign'] = signForm_Data['ts'] = tsForm_Data['bv'] = bvForm_Data['doctype'] = 'json'Form_Data['version'] = '2.1'Form_Data['keyfrom'] = 'fanyi.web'Form_Data['action'] = 'FY_BY_REALTIME'Form_Data['typoResult'] = 'false'# 对数据进行字节流编码处理data = parse.urlencode(Form_Data).encode('utf-8')# 创建Request对象req = request.Request(url=url, data=data, method='POST')# 写入header信息req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36')req.add_header('cookie', '[email protected]')req.add_header('Referer', 'http://fanyi.youdao.com/')# 传入创建好的Request对象response = request.urlopen(req, timeout=5)# 读取信息并进行字节流解码html = response.read().decode('utf-8')# 把返回来的json字符串解析成字典translate_results = json.loads(html)# 打印翻译结果translate_result = translate_results[\"translateResult\"][0][0]['tgt']print(\"翻译的结果是:%s\" % translate_result) 运行,输入内容,翻译结果,一气呵成,大功告成。 五、纸上得来终觉浅,绝知此事要躬行。 像有道翻译这样,通过用js在本地生成随机字符串的反爬虫机制,是爬虫经常会遇到的一个问题。授人以鱼不如授人以渔,还是但愿大家能多多实践与练习,在编写爬虫的过程中也能学到一些反爬虫的知识为我所用。希望通过以上的讲解,能为大家提供一种思路,以后再碰到这种问题的时候知道该如何解决,这样本篇文章的目的也就达到了。 写到这里的时候突然又有了新的想法,那就将此篇作为上篇,期待下一篇吧~ 特别感谢@Jack-Cui @南窗客斯黄","tags":[{"name":"python","slug":"python","permalink":"http://inplus.top/tags/python/"},{"name":"爬虫","slug":"爬虫","permalink":"http://inplus.top/tags/爬虫/"}]},{"title":"hello world之等腰三角形命题","date":"2018-05-02T09:11:00.000Z","path":"archives/helloworld-triangle/","text":"铛里个铛,当里个当,闲言碎语不要讲,大家听我嚷一嗓~ Hello World 中文意思是『你好,世界』。泛指在计算机屏幕上输出“Hello World”这行字符串的计算机程序。一般来说,这是每一种计算机编程语言中最基本、最简单的程序,亦通常是初学者所编写的第一个程序。它还可以用来确定该语言的编译器、程序开发环境,以及运行环境是否已经安装妥当。因为在Brian Kernighan 和Dennis M. Ritchie合著的《The C Programming Language》中使用它做为第一个演示程序,非常著名,所以后来的程序员在学习编程或进行设备调试时延续了这一习惯。 时隔 2 << 9 年一度的hello world大赛又开始了,本届大赛的命题是使用循环等来输出一个由*组成的等腰三角形,如下:123456 * *** ***** ******* ******************** 作为一名有职业素养的码农,当然首先登场的是Write Once, Run Anywhere的来自爪哇的Java语言,让我们来看看他的表现:1234567891011121314151617public class Main { public static void main(String[] args) { int n = 6; for (int i = 1; i <= n; i++) { for (int j = n - 1; j >= i; j--) { System.out.print(\" \"); } for (int k = 1; k <= i; k++) { System.out.print(\"*\"); } for (int h = 1; h < i; h++) { System.out.print(\"*\"); } System.out.println(); } }} 当然,作为一名有职业素养的码农,线性函数少不了,少一个for循环,少一些烦恼~1234567891011121314public class Main { public static void main(String[] args) { int n = 6; for (int i = 1; i <= n; i++) { for (int j = n - 1; j >= i; j--) { System.out.print(\" \"); } for (int k = 1; k <= 2 * i - 1; k++) { System.out.print(\"*\"); } System.out.println(); } }} 老大哥C语言在背后也摩拳擦掌:12345678910111213#include<stdio.h>int main() { int n = 6; for (int i = 0; i < n; i++) { for (int j = n - 1; j > i; j--) printf(\" \"); for (int k = 0; k < 2 * i + 1; k++) printf(\"*\"); printf(\"\\n\"); } return 0;} 简单点,运行的方式简单点,编译的过程请省略,你又不是脚本语言~给我一个浏览器,我能成就你一个等腰三角形,作为脚本语言,看下JavaScript的表现:1234567891011var n = 6;for (var i = 1; i <= n; i++) { var str = \"\"; for (var j = n - 1; j >= i; j--) { str += \" \"; } for (var j = 1; j <= 2 * i - 1; j++) { str += \"*\"; } console.log(str);} 当然,作为一名有职业素养的码农,思维当然不能仅仅局限于编程语言中,那么数据库SQL语言呢,以MySQL为例,我们可以利用存储过程来实现MySQL闪亮登场,统统给我闪开:123456789101112131415161718192021222324252627282930313233DELIMITER $$DROP PROCEDURE IF EXISTS `printStar`$$CREATE PROCEDURE `printStar` (IN num INT) BEGIN DECLARE line INT DEFAULT num ; DECLARE enter TEXT DEFAULT '\\n' ; DECLARE star TEXT DEFAULT '*' ; DECLARE starTemp TEXT DEFAULT '' ; DECLARE blank TEXT DEFAULT ' ' ; DECLARE i INT DEFAULT 0 ; DECLARE j INT DEFAULT 0 ; DECLARE k INT DEFAULT 0 ; WHILE i < line DO SET i = i + 1 ; SET j = 0 ; SET k = line - 1 ; WHILE k >= i DO SET k = k - 1 ; SET starTemp = CONCAT(starTemp, blank) ; END WHILE ; WHILE j < 2 * i - 1 DO SET j = j + 1 ; SET starTemp = CONCAT(starTemp, star) ; END WHILE ; SET starTemp = CONCAT(starTemp, enter) ; END WHILE ; SELECT starTemp ;END $$DELIMITER ;CALL printStar(6); 啊啊啊~SQLServer、Oracle等SQL家族还在场下蠢蠢欲动,没想到半路杀出个python,看到MySQL那冗长的存储过程,python3表示短小精悍才是硬道理:1234567n = 6for i in range(1, n + 1): for j in range(n - i): print(' ', end='') for k in range(2 * i - 1): print('*', end='') print() 咦~咦~咦~(场下嘘声一片),看起来传说中的python也没简洁到哪嘛!只见他的嘴角微微一笑,当然,我还可以这样:123n = 6for i in range(1, n + 1): print(' ' * (n - i), '*' * (2 * i - 1)) python默默的挥了挥衣袖,只留下众人痴呆的表情,胶水语言不发威还真以为我是hello world。。。 人生苦短,我用派森 以上","tags":[{"name":"软件开发","slug":"软件开发","permalink":"http://inplus.top/tags/软件开发/"}]},{"title":"windows环境搭建hadoop伪集群","date":"2018-03-19T23:11:00.000Z","path":"archives/windows-hadoop/","text":"在当前日益兴盛的大数据(big data)时代,hadoop和它的生态体系从中脱颖问出,因为我们开发环境大多在windows上,但因安全策略限制等原因不方便用虚拟机运行Linux和租用云服务器怎么办,不要慌,windows同样可以完美搭建起来hadoop的环境。 环境windows 7-64bitjdk-1.8.0_161hadoop-2.7.1 操作步骤一、下载并安装jdk下载和安装的过程就不多说了,需要注意的是记得设置好JAVA_HOME系统环境变量,因为hadoop的配置文件中用到了这个参数。 我采用的jdk是1.8的,配置JAVA_HOME,如果默认安装,会安装在C:\\Program Files\\Java\\jdk1.8.0_161。此目录存在空格,启动hadoop时将报错,JAVA_HOME is incorrect ...。建议安装在D:\\Java\\jdk1.8.0_161,如果已经安装过了,也不用怕,此时只需要将环境变量JAVA_HOME值中的Program Files替换为Progra~1。如:C:\\Progra~1\\Java\\jdk1.8.0_161。 二、安装配置hadoop1、下载http://hadoop.apache.org/https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common官网和各镜像站提供了最新版本的各个下载包http://archive.apache.org/dist/hadoop/core这边我从归档站下载了hadoop-2.7.1的tar包 2、解压并配置环境变量复制到D盘根目录直接解压,出来一个目录D:\\hadoop-2.7.1,配置到环境变量HADOOP_HOME中,在PATH里加上%HADOOP_HOME%\\bin; 3、下载windows专用二进制文件和工具类依赖库hadoop在windows上运行需要winutils支持和hadoop.dll等文件https://github.com/steveloughran/winutils在github仓库中找到对应版本的二进制库hadoop.dll和winutils.exe文件,然后把文件拷贝到D:\\hadoop-2.7.1\\bin目录中去 注意hadoop.dll等文件不要与hadoop冲突,若出现依赖性错误可以将hadoop.dll放到C:\\Windows\\System32下一份。 4、hadoop环境测试启动windows cmd命令行窗口执行hadoop version,显示如下: 5、最小化配置hadoop伪集群去D:\\hadoop-2.7.1\\etc\\hadoop找到下面4个文件并按如下最小配置粘贴上去: core-site.xml123456<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://localhost:9000</value> </property> </configuration> hdfs-site.xml (将value的路径改为自己的路径,盘符/d:/的前后都有正斜杠)1234567891011121314<configuration> <property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>/d:/hadoop-2.7.1/data/dfs/namenode</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>/d:/hadoop-2.7.1/data/dfs/datanode</value> </property></configuration> mapred-site.xml (拷贝mapred-site.xml.template并改名)123456<configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property></configuration> yarn-site.xml12345678910<configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> <property> <name>yarn.nodemanager.aux-services.mapreduce.shuffle.class</name> <value>org.apache.hadoop.mapred.ShuffleHandler</value> </property></configuration> 6、格式化namenode并启动hadoop启动windows cmd命令行窗口执行hdfs namenode -format,待执行完毕没有报错即可,不需要重复format: 执行完毕后hadoop目录会多出data文件夹: 格式化完成后到hadoop的sbin目录下执行start-all.cmd启动hadoop 再启动一个新的windows cmd命令行窗口执行jps 通过jps命令可以看到ResourceManager、NameNode、NodeManager、DataNode这4个进程都拉起来了,到这里hadoop的安装启动已经完成了。 接着我们可以用浏览器到localhost:8088看mapreduce任务 到localhost:50070 –> Utilites –> Browse the file system看hdfs文件。 如果需要重启hadoop无需再格式化namenode,只要stop-all.cmd再start-all.cmd就可以了。 参考文档:https://wiki.apache.org/hadoop/Hadoop2OnWindows","tags":[{"name":"hadoop","slug":"hadoop","permalink":"http://inplus.top/tags/hadoop/"},{"name":"大数据","slug":"大数据","permalink":"http://inplus.top/tags/大数据/"}]},{"title":"NoSQL之闻名遐迩Redis","date":"2018-01-25T09:11:00.000Z","path":"archives/nosql-redis/","text":"一、NoSQL简介 NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是SQL”,泛指非关系型的数据库。 NoSQL 是一项全新的数据库革命性运动,早期就有人提出,发展至2009年趋势越发高涨。NoSQL的拥护者们提倡运用非关系型的数据存储,相对于铺天盖地的关系型数据库运用,这一概念无疑是一种全新的思维的注入,NoSQL的非关系特性助力大型Web2.0网站的再次起飞,使其成为了后Web2.0时代的宠儿。 单机时代模型 如果每次存储成千上万条数据,这样很会导致mysql的性能很差,存储以及读取速度很慢,然后就演变成缓存+mysql+垂直拆分的方式。 Cache作为中间缓存 将所有的数据先保存到缓存中,然后再存入mysql中,减小数据库压力,提高效率。 但是当数据再次增加到又一个量级,上面的方式也不能满足需求,由于数据库的写入压力增加,Memcached只能缓解数据库的读取压力。读写集中在一个数据库上让数据库不堪重负,大部分网站开始使用主从复制技术来达到读写分离,以提高读写性能和读库的可扩展性。Mysql的master-slave模式成为这个时候的网站标配了。 主从分离模式 在redis的高速缓存,MySQL的主从复制,读写分离的基础之上,这时MySQL主库的写压力开始出现瓶颈,而数据量的持续猛增,由于MyISAM使用表锁,在高并发下会出现严重的锁问题,大量的高并发MySQL应用开始使用InnoDB引擎代替MyISAM。 分表分库模式 将变化小的、业务相关的放在一个数据库,变化多的,不相关的数据放在一个数据库。 二、NoSQL的风声水起 随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题: 1. 对数据库高并发读写的需求 网站要根据用户个性化信息来实时生成动态页面和提供动态信息,所以基本上无法使用动态页面静态化技术,因此数据库并发负载非常高,往往要达到每秒上万次读写请求。关系数据库应付上万次SQL查询还勉强顶得住,但是应付上万次SQL写数据请求,硬盘IO就已经无法承受了。 2. 对海量数据的高效率存储和访问的需求 对于大型的SNS网站,每天用户产生海量的用户动态,以国外的Friendfeed为例,一个月就达到了2.5亿条用户动态,对于关系数据库来说,在一张2.5亿条记录的表里面进行SQL查询,效率是极其低下乃至不可忍受的。 3. 对数据库的高可扩展性和高可用性的需求 在基于Web的架构当中,数据库是最难进行横向扩展的,当一个应用系统的用户量和访问量与日俱增的时候,你的数据库却没有办法像Web服务器和应用服务器那样简单的通过添加更多的硬件和服务节点来扩展性能和负载能力。对于很多需要提供7*24小时不间断服务的网站来说,对数据库系统进行升级和扩展是非常痛苦的事情,往往需要停机维护和数据迁移,为什么数据库不能通过不断的添加服务器节点来实现扩展呢? 在上面提到的“三高”的需求面前,关系数据库遇到了难以克服的障碍,而对于Web2.0网站来说,关系数据库的很多主要特性却往往无用武之地,例如: 1. 数据库事务一致性需求 很多Web实时系统并不要求严格的数据库事务,对读一致性的要求很低,有些场合对写一致性要求也不高。因此数据库事务管理成了数据库高负载下一个沉重的负担。 2. 数据库的写实时性和读实时性需求 对关系数据库来说,插入一条数据之后立刻查询,是肯定可以读出来这条数据的。并不要求这么高的实时性。 3. 对复杂的SQL查询,特别是多表关联查询的需求 任何大数据量的Web系统,都非常忌讳多个大表的关联查询,以及复杂的数据分析类型的复杂SQL报表查询,特别是SNS类型的网站,从需求以及产品设计角度,就避免了这种情况的产生。往往更多的只是单表的主键查询,以及单表的简单条件分页查询,SQL的功能被极大的弱化了。 而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题。 三、NoSQL无与伦比的特点在大数据存取上具备关系型数据库无法比拟的性能优势,例如: 1. 易扩展 NoSQL数据库种类繁多,但是一个共同的特点都是去掉关系数据库的关系型特性。数据之间无关系,这样就非常容易扩展。也无形之间,在架构的层面上带来了可扩展的能力。 2. 大数据量,高性能 NoSQL数据库都具有非常高的读写性能,尤其在大数据量下,同样表现优秀。这得益于它的无关系性,数据库的结构简单。 3. 多样灵活的数据模型 在NoSQL中不仅可以存储String,hash,set、Zset等数据类型,还可以保存javaBean以及多种复杂的数据类型。NoSQL无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。而在关系数据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是一个噩梦。这点在大数据量的Web2.0时代尤其明显。 4. 高可用 NoSQL在不太影响性能的情况,就可以方便的实现高可用的架构。比如Cassandra,HBase模型,通过复制模型也能实现高可用。 四、Redis的脱颖而出 1、redis简介 redis是NoSQL数据库中使用较为广泛的非关系型内存数据库,redis内部是一个key-value存储系统。它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set –有序集合)和hash(哈希类型,类似于Java中的map)。Redis基于内存运行并支持持久化的NoSQL数据库,是当前最热门的NoSql数据库之一,也被人们称为数据结构服务器。 2、redis特点 速度快Redis是用C语言实现的;Redis的所有数据存储在内存中。 持久化Redis的所有数据存储在内存中,对数据的更新将异步地保存到磁盘上。 支持多种数据结构Redis支持五种数据结构:String、List、Set、Hash、Zset 支持多种编程语言Java、php、Python、Ruby、Lua、Node.js 功能丰富除了支持五种数据结构之外,还支持事务、流水线、发布/订阅、消息队列等功能。 源码简单约23000行C语言源代码。 主从复制主服务器(master)执行添加、修改、删除,从服务器执行查询。 高可用及分布式Redis-Sentinel(v2.8)支持高可用Redis-Cluster(v3.0)支持分布式 和Memcached类似,Redis支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set –有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,Redis支持各种不同方式的排序。与Memcached一样,为了保证效率,数据都是缓存在内存中。区别的是Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步(数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。)。 因此,Redis的出现,很大程度补偿了Memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。 3、如何使用redis? 你一定要知道的是:redis的key名要区分大小写,在redis中除了 和空格外,其他的字符都可以做为key名,且长度不做限制,不过为了性能考虑,一般key名不要设置的太长。redis功能强大,支持数据类型丰富,以下是redis操作命令大全,基本上涵盖了redis所有的命令! 1、redis命令基本篇 【 set key value 】 存入一个key和值。如:set myname reson 【 get key 】 读取一个key的值。 【 del key 】 删除一个key。 【 del key1 key2 … keyN 】 删除多个key。如:del myname1 myname2 【 exists key 】 判断一个key是否存在。 【 type key 】 查看key的类型。 【 rename key keyNew 】 重命名key名。如:rename myname myname2 【 dbsize 】 查看当前库中的key的条数。 【 expire key time 】 指定key的过期时间,单位为秒。如:expire myname 9(设置9秒后过期) 【 ttl key 】 查看redis有多长时间过期,单位为秒。 【 keys * 】 列出当前库中所有的key名。 【 keys a* 】 列出当前库中所有以字符串“a”开头的key。 【 select db-index 】 选择一个数据库,如选择第一个数据库:select 0;选择第二个 select 1;默认有16个数据库,这个值可以在redis.conf中配置。 【 flushdb 】 清掉当前库中所有的key(生产环境下需谨慎操作)。 【 flushall 】 清掉所有库中全部的key(生产环境下需谨慎操作)。 【 mset key1 value1 key2 value2 … keyN valueN 】 一次性存入多个key和值。 【 mget key1 key2 … keyN 】 一次性读取多个key。 【 incr key 】 可以对key类型+1的操作(相当于编程语言里面的++),只能操作number型,操作字符串会报错。可对新值进行操作。 【 decr key 】 可以对key类型-1的操作(相当于编程语言里面的–),只能操作number型,操作字符串会报错。 【 incrby key num 】 同incr,对key的值加num,比如 incrby aa 10,对aa+10。 【 decrby key num 】 同上,对key的值减num。 【 append key value 】 对指定key的字符串进行追加,如果key为整形,会被转为字符串。如aa的值为9,执行append aa 10后,会变成910。 【 substr key start end 】 对key进行截取start到end个字符。如aa的值为:abcdef,执行substr aa 2 3后,返回“cd”。 2、redis链表类型(list)命令 【 lpush key value 】 往队列头部插入一个元素 【 rpush key value 】 从尾部插入一个元素 【 lpop key 】 从队列头部删掉一个元素 【 rpop key 】 从队列尾部删掉一个元素,并返回被删除元素的值 【 llen 】 返回队列的长度,即里面有多少个元素。不存在key返回0,不为队列类型的key会返回报错。 【 lrange key start end 】 返回队列从start到end之间的元素信息。 【 ltrim key start end 】 截取一个队列,只保留指定区间内的元素。 3、redis无序集合set类型命令 【 sadd key vaule 】 往集合中插入一个元素,如果value值已存在集合中,则返回0,不会被重复插入。 【 sinter key1 key2 … keyN 】 取出n个key之间的交集。比如 key1里面有值a,b,c,d,e,key2里面有d,e,f,sinter key1 key2返回d,e。 【 sunion key1 key2 … keyN 】 取出n个key之间的并集。比如 key1里面有值a,b,c,d,e,key2里面有d,e,f,sunion key1 key2返回a,b,c,d,e,f。 【 sdiff key1 key2 】 取出n个key之间的差集。比如 key1里面有值a,b,c,d,e,key2里面有d,e,f,sdiff key1 key2返回a,b,c;反过来sdiff key2 key1返回f。 【 smembers key 】 返回key集合中所有的元素,结果是无序的。 【 sismember key value 】 查看value这个值是否在key集合中。存在返回1,不存在返回0。 【 scard key 】 返回集合中有多少个元素。 【 smove key1 key2 value 】 把value从key1中移到key2中去。 【 srem key value1 value2 … valueN 】 从key集合中删掉某些元素。 4、redis有序集合sorted set命令 【 zadd key v k 】 往key中添加一个元素,k为键,v为值。如:zadd artHits 99 12表示id为12的文章点击量为99次。 【 zrange key start end 】 根据v的值由小到大进行排序来获得start到end之间的元素。注:0表示第一个元素,-1表示最后一个元素,-2表示倒数第二个元素,以此类推,如果要获取第一个到倒数第三个之间的元素,命令为:zrange key 0 -3。 【 zrevrange key start end 】 同上,根据v的值由大到小进行排序来获得start到end之间的元素。可以轻松取出点击量最高的前n篇文章。 【 zremrangebyrank key start end 】 删除集合中的元素。排序的方式为按照v由小到大的顺序,如果要删除key集合中的第一个值,则运行 zremrangebyrank artHits 0 0;删除前3个值:zremrangebyrank artHits 0 2。 【 zcard 】 返回key集合中元素的个数。 【 zrank key k 】 返回值k在集合key中排第几位,是按照v由小到大的顺序。排第一名返回0,第二返回1,以此类推。 【 zrevrank key k 】 同上,不同的是,按照v由大到小的顺序。可以轻松取出点击量最高的文章。 【 zscore key k 】 取出集合key中键为k对应的值v。 【 zrem key k 】 删除集合中指定元素。 【 zincrby key num k 】 给集合key中的元素k加上num,值针对整型。比如 zincrby artHits 3 12,给id为12的文章加上3个点击量。此时zscore artHits 12的结果是99+3为102。 5、redis哈希hash类型命令 【 hset key field value 】 设置hash field为指定值,如果key不存在,则先创建。 【 hmset key field1 value1 … fieldN valueN 】 同时设置多个值。 【 hget key field 】 获取指定的hash field 【 hmget key field1 field1 … fieldN 】 获取指定的多个hash field 【 hincrby key field num 】 将指定的hash field加上指定的值。 【 hexists key field 】 查看指定field是否存在。 【 hdel key field 】 删除指定的hash field。 【 hlen key 】 返回指定hash中field的数量。 【 hkeys key 】 返回hash所有的field。 【 hvals 】 返回hash中所有的value。 【 hgetall key 】 返回hash中所有的field和value。","tags":[{"name":"软件开发","slug":"软件开发","permalink":"http://inplus.top/tags/软件开发/"},{"name":"Redis","slug":"Redis","permalink":"http://inplus.top/tags/Redis/"},{"name":"NoSQL","slug":"NoSQL","permalink":"http://inplus.top/tags/NoSQL/"}]},{"title":"JVM的内存区域划分","date":"2017-11-09T09:11:00.000Z","path":"archives/jvm-memory-division/","text":"学过C语言的朋友都知道C编译器在划分内存区域的时候经常将管理的区域划分为数据段和代码段,数据段包括堆、栈以及静态数据区。那么在Java语言当中,内存又是如何划分的呢? 由于Java程序是交由JVM执行的,所以我们在谈Java内存区域划分的时候事实上是指JVM内存区域划分。 在讨论JVM内存区域划分之前,先来看一下Java程序具体执行的过程: 如上图所示,首先Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀),然后由JVM中的类加载器加载各个类的字节码文件,加载完毕之后,交由JVM执行引擎执行。在整个程序执行过程中,JVM会用一段空间来存储程序执行期间需要用到的数据和相关信息,这段空间一般被称作为Runtime Data Area(运行时数据区),也就是我们常说的JVM内存。因此,在Java中我们常常说到的内存管理就是针对这段空间进行管理(如何分配和回收内存空间)。 在知道了JVM内存是什么东西之后,下面我们就来讨论一下这段空间具体是如何划分区域的,是不是也像C语言中一样也存在栈和堆呢? 一、运行时数据区包括哪几部分? 根据《Java虚拟机规范》的规定,运行时数据区通常包括这几个部分:程序计数器(Program Counter Register)、Java栈(VM Stack)、本地方法栈(Native Method Stack)、方法区(Method Area)、堆(Heap)。 如上图所示,JVM中的运行时数据区应该包括这些部分。在JVM规范中虽然规定了程序在执行期间运行时数据区应该包括这几部分,但是至于具体如何实现并没有做出规定,不同的虚拟机厂商可以有不同的实现方式。 二、运行时数据区的每部分到底存储了哪些数据? 下面我们来了解一下运行时数据区的每部分具体用来存储程序执行过程中的哪些数据。 1、程序计数器 程序计数器(Program Counter Register),也有称作为PC寄存器。想必学过汇编语言的朋友对程序计数器这个概念并不陌生,在汇编语言中,程序计数器是指CPU中的寄存器,它保存的是程序当前执行的指令的地址(也可以说保存下一条指令的所在存储单元的地址),当CPU需要执行指令时,需要从程序计数器中得到当前需要执行的指令所在存储单元的地址,然后根据得到的地址获取到指令,在得到指令之后,程序计数器便自动加1或者根据转移指针得到下一条指令的地址,如此循环,直至执行完所有的指令。 虽然JVM中的程序计数器并不像汇编语言中的程序计数器一样是物理概念上的CPU寄存器,但是JVM中的程序计数器的功能跟汇编语言中的程序计数器的功能在逻辑上是等同的,也就是说是用来指示 执行哪条指令的。 由于在JVM中,多线程是通过线程轮流切换来获得CPU执行时间的,因此,在任一具体时刻,一个CPU的内核只会执行一条线程中的指令,因此,为了能够使得每个线程都在线程切换后能够恢复在切换之前的程序执行位置,每个线程都需要有自己独立的程序计数器,并且不能互相被干扰,否则就会影响到程序的正常执行次序。因此,可以这么说,程序计数器是每个线程所私有的。 在JVM规范中规定,如果线程执行的是非native方法,则程序计数器中保存的是当前需要执行的指令的地址;如果线程执行的是native方法,则程序计数器中的值是undefined。 由于程序计数器中存储的数据所占空间的大小不会随程序的执行而发生改变,因此,对于程序计数器是不会发生内存溢出现象(OutOfMemory)的。 2、Java栈 Java栈也称作虚拟机栈(Java Vitual Machine Stack),也就是我们常常所说的栈,跟C语言的数据段中的栈类似。事实上,Java栈是Java方法执行的内存模型。为什么这么说呢?下面就来解释一下其中的原因。 Java栈中存放的是一个个的栈帧,每个栈帧对应一个被调用的方法,在栈帧中包括局部变量表(Local Variables)、操作数栈(Operand Stack)、指向当前方法所属的类的运行时常量池(运行时常量池的概念在方法区部分会谈到)的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些额外的附加信息。当线程执行一个方法时,就会随之创建一个对应的栈帧,并将建立的栈帧压栈。当方法执行完毕之后,便会将栈帧出栈。因此可知,线程当前执行的方法所对应的栈帧必定位于Java栈的顶部。讲到这里,大家就应该会明白为什么 在 使用 递归方法的时候容易导致栈内存溢出的现象了以及为什么栈区的空间不用程序员去管理了(当然在Java中,程序员基本不用关系到内存分配和释放的事情,因为Java有自己的垃圾回收机制),这部分空间的分配和释放都是由系统自动实施的。对于所有的程序设计语言来说,栈这部分空间对程序员来说是不透明的。下图表示了一个Java栈的模型: 局部变量表,顾名思义,想必不用解释大家应该明白它的作用了吧。就是用来存储方法中的局部变量(包括在方法中声明的非静态变量以及函数形参)。对于基本数据类型的变量,则直接存储它的值,对于引用类型的变量,则存的是指向对象的引用。局部变量表的大小在编译器就可以确定其大小了,因此在程序执行期间局部变量表的大小是不会改变的。 操作数栈,想必学过数据结构中的栈的朋友想必对表达式求值问题不会陌生,栈最典型的一个应用就是用来对表达式求值。想想一个线程执行方法的过程中,实际上就是不断执行语句的过程,而归根到底就是进行计算的过程。因此可以这么说,程序中的所有计算过程都是在借助于操作数栈来完成的。 指向运行时常量池的引用,因为在方法执行的过程中有可能需要用到类中的常量,所以必须要有一个引用指向运行时常量。 方法返回地址,当一个方法执行完毕之后,要返回之前调用它的地方,因此在栈帧中必须保存一个方法返回地址。 由于每个线程正在执行的方法可能不同,因此每个线程都会有一个自己的Java栈,互不干扰。 3、本地方法栈 本地方法栈与Java栈的作用和原理非常相似。区别只不过是Java栈是为执行Java方法服务的,而本地方法栈则是为执行本地方法(Native Method)服务的。在JVM规范中,并没有对本地方发展的具体实现方法以及数据结构作强制规定,虚拟机可以自由实现它。在HotSopt虚拟机中直接就把本地方法栈和Java栈合二为一。 4、堆 在C语言中,堆这部分空间是唯一一个程序员可以管理的内存区域。程序员可以通过malloc函数和free函数在堆上申请和释放空间。那么在Java中是怎么样的呢? Java中的堆是用来存储对象本身的以及数组(当然,数组引用是存放在Java栈中的)。只不过和C语言中的不同,在Java中,程序员基本不用去关心空间释放的问题,Java的垃圾回收机制会自动进行处理。因此这部分空间也是Java垃圾收集器管理的主要区域。另外,堆是被所有线程共享的,在JVM中只有一个堆。 5、方法区 方法区在JVM中也是一个非常重要的区域,它与堆一样,是被线程共享的区域。在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。 在Class文件中除了类的字段、方法、接口等描述信息外,还有一项信息是常量池,用来存储编译期间生成的字面量和符号引用。 在方法区中有一个非常重要的部分就是运行时常量池,它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。当然并非Class文件常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法。 在JVM规范中,没有强制要求方法区必须实现垃圾回收。很多人习惯将方法区称为“永久代”,是因为HotSpot虚拟机以永久代来实现方法区,从而JVM的垃圾收集器可以像管理堆区一样管理这部分区域,从而不需要专门为这部分设计垃圾回收机制。不过自从JDK7之后,Hotspot虚拟机便将运行时常量池从永久代移除了。 特别感谢@海子","tags":[{"name":"软件开发","slug":"软件开发","permalink":"http://inplus.top/tags/软件开发/"},{"name":"Java","slug":"Java","permalink":"http://inplus.top/tags/Java/"}]},{"title":"抓取数据包Packet Capture v1.4.7汉化精简版","date":"2017-11-05T18:43:32.000Z","path":"archives/packetcapture/","text":"Packet Capture – 一款依托安卓系统自身VPN来达到免Root抓取数据包的应用程序。 Packet Capture一个使用SSL网络解密的 捕获数据包/网络嗅探 工具,虽然它的功能并不丰富,但是当你开发一个应用时,却不得不说它是一款强大的工具。Packet Capture通过自建一个vpn达到无root,通过中间人方便调试加密流量,流量还区分应用一目了然,这大概是目前最方便的抓包应用了吧。 功能特点: 捕获网络数据包并记录下来 使用中间人技术进行SSL解密 无需root 方便快捷 以十六进制或文本来显示数据包 国际惯例:介绍截图没有更新 12345678910更新日志:v1.4.7- Added image decoder- Minor bug fixv1.3.3Reduce memory usage to prevent out of memory crash.v1.2.3:UI improvements.- Show size of the packet dump file.- Hide packet from this app by default. Google Play:https://play.google.com/store/apps/details?id=app.greyshirts.sslcapture 修改说明: 极致精简,全包仅2.6M 完美简体汉化并剔除无用语言包 去除广告 更改包文本框属性,可直接复制报文文本(新版已自带) 剥离Google sdk 剥离Fabric sdk 剥离Crashlytics,禁用隐私统计 剥离LeakCanary,禁用内存泄漏统计 apk包体积优化 Zipalign对齐优化 修改人员:风澈vio(转载必须注明出处) 下载地址:百度网盘 密码:1024 注意: 使用者由此程序所造成的损失修改者不承担任何责任。 最终版权归原作者所有。 请在法律允许的范围内合理使用本程序。","tags":[{"name":"App","slug":"App","permalink":"http://inplus.top/tags/App/"}]},{"title":"照片编辑器Photo Editor Pro v2.8特别精简版","date":"2017-11-05T12:10:20.000Z","path":"archives/photoeditor/","text":"Photo Editor Pro – 一款轻量级简单易用的照片处理应用程序。 调整照片的颜色,旋转、裁剪、调整大小、添加效果、相框,并可在照片上涂鸦。颜色调整选项包括色相、饱和度、对比度、和亮度。此外,Photo Editor为您的照片提供了各种各样的效果,包括伽玛校正、自动对比度、自动色阶、模糊、锐化、油性涂料、素描、黑 & 白高对比度、深棕,等等。 功能特点: 调整照片的颜色,旋转、裁剪、调整大小、添加效果、相框,并可在照片上涂鸦。 使用曲线微调颜色。 涂鸦模式,添加文本或图片。 轻松旋转,剪裁或调整照片大小。 使用触摸和双指绽放界面轻松编辑照片。 从图库或相机载入照片。 保存照片为JPEG和PNG格式。灵活控制 JPEG品质。 查看、编辑或删除EXIF数据。 保存你的最终成果到图库或SD卡,或将其设置为壁纸。 国际惯例:介绍截图没有更新 1234567891011121314更新日志:v2.8• Android Oreo(8.0) support• Tools: GIF, PDF improvements• ICC improvements• Bug fixesv2.4:• Text/Image: Gradient improvements• Text/Image: Background round• Bug fixesv2.3:• Text/Image: Image background & padding• Tools: PDF Capture (Lollipop+)• Bug fixes 来源:https://www.iudesk.comGoogle Play:https://play.google.com/store/apps/details?id=com.iudesk.android.photo.editor 修改说明: 极致精简,全包仅1.9M,不影响稳定性 去除广告,解锁专业版 剔除无用菜单项,7栏变4栏 / 8宫变7宫 / 8宫变6宫 精简语言并剔除相关选项 彻底剔除Google sdk,告别Google服务检查和notify提醒 剔除无用权限 (保留网页截图所需要的联网权限) 去除第三方市场检测更新 apk包体积优化 Zipalign对齐优化 TinyPNG算法优化 修改人员:风澈vio(转载必须注明出处) 下载地址:百度网盘 密码:1024 注意: 使用者由此程序所造成的损失修改者不承担任何责任。 最终版权归原作者所有。 请在法律允许的范围内合理使用本程序。","tags":[{"name":"App","slug":"App","permalink":"http://inplus.top/tags/App/"}]},{"title":"多线程下载器ADM Pro v6.1.7特别修改版","date":"2017-10-05T19:18:32.000Z","path":"archives/adm/","text":"ADM Pro – 一款强大的多线程下载神器。 PC端的IDM是众所周知的多线程下载利器,那么ADM Pro可以说是安卓设备上最强大的下载器了,ADM Pro,全名Advanced Download Manager Pro,是一款专业的多线程下载工具,提供下载文件的自动分类保存,下载完成后“关机/打开文件/退出程序”的计划下载任务,多线程同步下载,自定义UA标识以及智能限速功能,还可以设置同时下载的任务数,以及很多自带的工具,如内置浏览器和编辑器,代理端口。可谓是各种妙用,体积小巧却功能强大。 功能特点: 强大的下载器 多线程下载 干净的界面 扩展通知 计划任务 智能限速 快速访问的内置浏览器 简单快捷控制的下载列表 更的高级下载管理器 国际惯例:介绍截图没有更新 123456789更新日志:Toolbar with commands in EditorAdvanced options in Editor (path, speed, etc.)Start/Stop in context menu, Interval (select all between two), Properties (see all details)Editor and Properties support batch mode (select downloads and scroll Left/Right, use Settings to on/off visibility options)SD-Card in Path for Editor and Site ManagerSend in Automation - After finishedQuick selection via \"three-point\"Select all in menu List Google Play:https://play.google.com/store/apps/details?id=com.dv.adm.pay 修改说明: 修改线程数上限为64(2048双版齐发) 修改同时下载任务数上限为30 内置PC百度云UA(2048版) 默认搜索引擎从Google替换为Baidu 剔除无用语言 修正并补全部分汉化信息 更改应用名为ADM Pro+ apk包体积优化 Zipalign对齐优化 修改人员:风澈vio(转载必须注明出处) 下载地址: ※城通网盘(进入下载列表-最下方普通低速单线程下载)※** 注意: 使用者由此程序所造成的损失修改者不承担任何责任。 最终版权归原作者所有。 请在法律允许的范围内合理使用本程序。","tags":[{"name":"App","slug":"App","permalink":"http://inplus.top/tags/App/"}]},{"title":"微软远程桌面RD Client v8.1.56.294汉化特别版","date":"2017-10-03T22:51:32.000Z","path":"archives/msrdclient/","text":"Microsoft Remote Desktop – 一款微软官方发布的RDP远程桌面控制工具,方便在手机上控制电脑或服务器。 功能特点: 通过远程桌面网关访问远程资源 远程桌面协议(RDP)和RemoteFX的支持Windows手势丰富的多点触控体验 安全连接到您的数据和突破网络层的认证申请(NLA)技术 从连接中心对所有远程连接进行简单的管理 高品质的视频和音频流媒体与改进的压缩和带宽使用 对Azure的RemoteApp的支持 12更新日志:We fixed an issue for Android O Preview users that caused graphics to appear distorted when you connected to a Windows PC or server. 来源:https://go.microsoft.com/fwlink/p/?LinkId=324281Google Play:https://play.google.com/store/apps/details?id=com.microsoft.rdc.android 修改说明: 简体中文汉化,嵌入式汉化 精简多余语言包 arm架构包体积精简 zipalign对齐优化 修改人员:风澈vio(转载必须注明出处) 下载地址:tip:使用城通网盘下载一次相当于赞助楼楼2分钱~城通网盘(进入下载列表-最下方普通低速单线程下载)百度网盘 密码:1024※ 链接失效或无法下载请联系我 ※ 注意: 使用者由此程序所造成的损失修改者不承担任何责任。 最终版权归原作者所有。 请在法律允许的范围内合理使用本程序。","tags":[{"name":"App","slug":"App","permalink":"http://inplus.top/tags/App/"}]},{"title":"SourceTree 免登录跳过初始设置的方法","date":"2017-09-03T16:36:00.000Z","path":"archives/sourcetreeskipsetting/","text":"由于 svn 时期 “小乌龟” 根深蒂固的影响力,我们通常用到的 git 可视化版本控制工具恐怕要属 Tortoisegit 多一些了。 而 SourceTree 是 Windows 和 Mac OS X 下免费的 Git 和 Hg 客户端管理工具,同时也是 Mercurial 和 Subversion 版本控制系统工具。支持创建、克隆、提交、push、pull 和合并等操作。SourceTree 拥有一个精美简洁的界面,大大简化了开发者与代码库之间的Git操作方式,这对于那些不熟悉Git命令的开发者来说非常实用。 SourceTree 安装之后需要使用账号登陆授权以后才可以使用,以前是可以不登陆的,但是现在是强制登陆。虽然是免费授权,但是不知道是什么原因,登陆经常会失败,翻墙也不行,这里就分享一下跳过下图这个初始化界面的步骤。 Windows版 SourceTree 免登录跳过初始设置的方法 首先,安装完 SourceTree 以后先运行一次,弹出初始化登录页面后退出。 打开 我的电脑,在最上方的地址栏直接输入以下地址: 1%LocalAppData%\\Atlassian\\SourceTree\\ 如图: 在这个目录下新建一个名为 accounts.json 的文件。 使用 记事本 打开这个文件,将以下内容复制到其中后保存。 123456789101112131415161718192021222324[ { \"$id\": \"1\", \"$type\": \"SourceTree.Api.Host.Identity.Model.IdentityAccount, SourceTree.Api.Host.Identity\", \"Authenticate\": true, \"HostInstance\": { \"$id\": \"2\", \"$type\": \"SourceTree.Host.Atlassianaccount.AtlassianAccountInstance, SourceTree.Host.AtlassianAccount\", \"Host\": { \"$id\": \"3\", \"$type\": \"SourceTree.Host.Atlassianaccount.AtlassianAccountHost, SourceTree.Host.AtlassianAccount\", \"Id\": \"atlassian account\" }, \"BaseUrl\": \"https://id.atlassian.com/\" }, \"Credentials\": { \"$id\": \"4\", \"$type\": \"SourceTree.Model.BasicAuthCredentials, SourceTree.Api.Account\", \"Username\": \"\", \"Email\": null }, \"IsDefault\": false }] 文件保存成功后的样子如图: 再次打开 SourceTree 就可以直接跳过登录进入软件页面了。 注意: Windows 系统文件后缀是默认隐藏的,需要先显示文件的后缀名,然后随便新建一个 文本文档 ,将文件全名改为 accounts.json 即可。 显示文件后缀名的方法: 打开 我的电脑 ,点击 工具 菜单中的 文件夹选项 。 如图: 弹出 文件夹选项 ,在 查看选项卡中,将 隐藏已知文件类型的扩展名 选项取消选中后点击 确定 即可。 如图: 方法就是这样,Mac 版的 SourceTree 暂时还不知道怎么跳过,还是老老实实翻墙注册登录吧~ 特别感谢@Jonzzs","tags":[{"name":"软件开发","slug":"软件开发","permalink":"http://inplus.top/tags/软件开发/"},{"name":"git","slug":"git","permalink":"http://inplus.top/tags/git/"}]},{"title":"CentOS 7简单的利用yum源安装Nginx","date":"2017-08-25T01:20:00.000Z","path":"archives/centosnginx/","text":"小伙伴的项目需求要使用80端口部署静态html5的官网,为了稳定高效和后续的扩充,故使用轻巧又强大的Nginx来作80端口的服务器,也方便后续进行反向代理和负载均衡。 下面就简单介绍一下简单的利用yum源安装Nginx,并进行响应配置。 安装环境:CentOS7 64位 Minimal版(VMware) 配置网卡使用桥接,开启网卡并设置:静态ip、网关、子网掩码、DNS12# 编辑网卡配置vi /etc/sysconfig/network-scripts/ifcfg-eno16777736 1234567891011121314151617181920TYPE=EthernetBOOTPROTO=staticIPADDR=192.168.0.200GATEWAY=192.168.0.1NETMASK=255.255.255.0DNS1=192.168.0.1DEFROUTE=yesPEERDNS=yesPEERROUTES=yesIPV4_FAILURE_FATAL=noIPV6INIT=yesIPV6_AUTOCONF=yesIPV6_DEFROUTE=yesIPV6_PEERDNS=yesIPV6_PEERROUTES=yesIPV6_FAILURE_FATAL=noNAME=eno16777736UUID=11b992a7-1630-4a26-bd62-8ce65e3e5c78DEVICE=eno16777736ONBOOT=yes 12# 重启网络服务systemctl restart network 12# 查看ipip addr 配置防火墙http协议默认端口为80端口,SSL加密的https协议的默认端口为443端口。远程访问,需要打开防火墙。CentOS 7 中默认防火墙是firewalld,默认为关闭状态。12345678910111213141516171819# 启动Firewallsystemctl start firewalld# 设置开机自启动systemctl enable firewalld# 开放http80端口firewall-cmd --permanent --add-port=80/tcp# 开放https443端口firewall-cmd --permanent --add-port=443/tcp# 重载防火墙配置使其生效firewall-cmd --reload# 查看所有已开放端口firewall-cmd --list-ports# 移除某端口firewall-cmd --permanent --remove-port=端口名/tcp# 若无firewall-cmd命令则先安装firewalldyum install firewalld -y 1、添加源默认情况Centos7中无Nginx的yum源,最近发现Nginx官网提供了Centos的源地址。因此可以在http://nginx.org/en/linux_packages.html#stable找到链接,并执行如下命令添加源:1rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm 2、安装Nginx查看源是否已经添加成功:1yum search nginx 查看源信息:1yum info nginx 检查源已经添加源成功,执行下列命令进行安装:1yum install -y nginx 3、启动Nginx安装完成后nginx就已经启动了,可以查看进程:1ps -ef | grep nginx 若未启动则执行命令进行启动Nginx:1systemctl start nginx 如果一切进展顺利的话,现在你可以通过你的域名或IP来访问你的Web页面来预览一下Nginx的默认页面 如果看到这个页面,那么说明你的CentOS 7 中 web服务器已经正确安装。 如果不能连接到Nginx,原因很多,但是可以先检查:①Nginx服务是否真的运行起来了。②服务器防火墙是否放行80端口。 4、其他配置开机自启:1systemctl enable nginx Nginx配置信息12345678# 网站文件存放默认目录/usr/share/nginx/html# 网站默认站点配置/etc/nginx/conf.d/default.conf# 自定义Nginx站点配置文件存放目录/etc/nginx/conf.d/# Nginx全局配置/etc/nginx/nginx.conf 修改配置后无缝重载:123systemctl reload nginx或nginx -s reload 指定配置文件启动:1nginx -c nginx.conf 这样你可以改变配置使Nginx像守护进程一样运行,Nginx运行进程的数量等等。","tags":[{"name":"软件开发","slug":"软件开发","permalink":"http://inplus.top/tags/软件开发/"},{"name":"nginx","slug":"nginx","permalink":"http://inplus.top/tags/nginx/"}]},{"title":"CentOS 7 MySQL自动备份shell脚本","date":"2017-08-11T10:20:00.000Z","path":"archives/centosmysqlautobak/","text":"在数据库的日常维护工作中,除了保证业务的正常运行以外,就是要对数据库进行备份,以免造成数据库的丢失,从而给企业带来重大经济损失。 通常备份可以按照备份时数据库状态分为热备和冷备,按照备份数据库文件的大小分为增量备份、差异备份和全量备份。 这里,我们讲解一种全量备份的方法,来实现定时备份数据到mysql脚本文件,并且支持过期删除。 系统环境:CentOS7 64位 Minimal版(VMware)MySQL5.7 原理与工具:shell脚本mysqldump程序crontab命令 1、新建shell脚本1vi /opt/mysqlBackup.sh 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273#!/bin/bash# 以下配置信息请自己修改mysql_user=\"USER\" #MySQL备份用户mysql_password=\"PASSWORD\" #MySQL备份用户的密码mysql_host=\"localhost\"mysql_port=\"3306\"mysql_charset=\"utf8\" #MySQL编码backup_db_arr=(\"db1\" \"db2\") #要备份的数据库名称,多个用空格分开隔开 如(\"db1\" \"db2\" \"db3\")backup_location=/opt/mysql #备份数据存放位置,末尾请不要带\"/\",此项可以保持默认,程序会自动创建文件夹expire_backup_delete=\"ON\" #是否开启过期备份删除 ON为开启 OFF为关闭expire_days=3 #过期时间天数 默认为三天,此项只有在expire_backup_delete开启时有效# 本行开始以下不需要修改backup_time=`date +%Y%m%d%H%M` #定义备份详细时间backup_Ymd=`date +%Y-%m-%d` #定义备份目录中的年月日时间backup_3ago=`date -d '3 days ago' +%Y-%m-%d` #3天之前的日期backup_dir=$backup_location/$backup_Ymd #备份文件夹全路径welcome_msg=\"Welcome to use MySQL backup tools!\" #欢迎语# 判断MYSQL是否启动,mysql没有启动则备份退出mysql_ps=`ps -ef |grep mysql |wc -l`mysql_listen=`netstat -an |grep LISTEN |grep $mysql_port|wc -l`if [ [$mysql_ps == 0] -o [$mysql_listen == 0] ]; then echo \"ERROR:MySQL is not running! backup stop!\" exitelse echo $welcome_msgfi# 连接到mysql数据库,无法连接则备份退出mysql -h$mysql_host -P$mysql_port -u$mysql_user -p$mysql_password <<enduse mysql;select host,user from user where user='root' and host='localhost';exitendflag=`echo $?`if [ $flag != \"0\" ]; then echo \"ERROR:Can't connect mysql server! backup stop!\" exitelse echo \"MySQL connect ok! Please wait......\" # 判断有没有定义备份的数据库,如果定义则开始备份,否则退出备份 if [ \"$backup_db_arr\" != \"\" ];then #dbnames=$(cut -d ',' -f1-5 $backup_database) #echo \"arr is (${backup_db_arr[@]})\" for dbname in ${backup_db_arr[@]} do echo \"database $dbname backup start...\" `mkdir -p $backup_dir` `mysqldump -h$mysql_host -P$mysql_port -u$mysql_user -p$mysql_password $dbname --default-character-set=$mysql_charset | gzip > $backup_dir/$dbname-$backup_time.sql.gz` flag=`echo $?` if [ $flag == \"0\" ];then echo \"database $dbname success backup to $backup_dir/$dbname-$backup_time.sql.gz\" else echo \"database $dbname backup fail!\" fi done else echo \"ERROR:No database to backup! backup stop\" exit fi # 如果开启了删除过期备份,则进行删除操作 if [ \"$expire_backup_delete\" == \"ON\" -a \"$backup_location\" != \"\" ];then #`find $backup_location/ -type d -o -type f -ctime +$expire_days -exec rm -rf {} \\;` `find $backup_location/ -type d -mtime +$expire_days | xargs rm -rf` echo \"Expired backup data delete complete!\" fi echo \"All database backup success! Thank you!\" exitfi 注意:如果这个sh文件是在win下编辑的,需要用编辑器转换为unix格式,否则sh会执行不成功,如图: 2、修改shell脚本属性,赋予执行权限12chmod 600 /opt/mysqlBackup.shchmod +x /opt/mysqlBackup.sh 3、定时执行脚本方式一:执行crontab -e命令,创建当前用户级别的定时任务1crontab -e 输入以下内容,设置每天凌晨3:00定时自动备份100 03 * * * /opt/mysqlBackup.sh 生成的配置文件位于/var/spool/cron/root 日志记录在/var/spool/mail/root中,可查看日志记录1vi /var/spool/mail/root crontab文件概要:用户所建立的crontab文件中,每一行都代表一项任务,每行的每个字段代表一项设置,它的格式共分为六个字段,前五段是时间设定段,第六段是要执行的命令段,格式如下:minute hour day month week command 分 时 日 月 周 命令其中:minute: 表示分钟,可以是从0到59之间的任何整数。(每分钟可用*或者*/1表示)hour:表示小时,可以是从0到23之间的任何整数。(0表示0点)day:表示日期,可以是从1到31之间的任何整数。month:表示月份,可以是从1到12之间的任何整数。week:表示星期几,可以是从0到7之间的任何整数,这里的0或7代表星期日。command:要执行的命令,可以是系统命令,也可以是自己编写的脚本文件。在以上各个字段中,还可以使用以下特殊字符:星号(*):代表所有可能的值,例如month字段如果是星号,则表示在满足其它字段的制约条件后每月都执行该命令操作。逗号(,):可以用逗号隔开的值指定一个列表范围,例如,“1,2,5,7,8,9”中杠(-):可以用整数之间的中杠表示一个整数范围,例如“2-6”表示“2,3,4,5,6”正斜线(/):可以用正斜线指定时间的间隔频率,例如“0-23/2”表示每两小时执行一次。同时正斜线可以和星号一起使用,例如*/10,如果用在minute字段,表示每十分钟执行一次。 方式二:配置全局定时任务文件1vi /etc/crontab 在etc中加入如下内容,让其每天凌晨3:00自动执行任务。100 03 * * * root /opt/mysqlBackup.sh 全局定时任务配置相比于用户级别的任务配置多了一项执行用户user-name 日志记录在/var/log/cron中 4、MySQL恢复1mysql -u username -p databse < backup.sql 特别感谢 @astaxie @羽飞 @vpsrr","tags":[{"name":"软件开发","slug":"软件开发","permalink":"http://inplus.top/tags/软件开发/"},{"name":"mysql","slug":"mysql","permalink":"http://inplus.top/tags/mysql/"}]},{"title":"CentOS 7/8 JavaWeb 环境安装与配置(YUM)","date":"2017-07-18T10:20:00.000Z","path":"archives/centosjavaweb/","text":"小伙伴近日项目上线,向我询问部署相关知识。这里再重新总结一下Linux下部署环境的配置,使用VMware虚拟机使用CentOS 7.2 x64位系统,在有网络的情况下,最大程度使用YUM进行快速安装。 安装环境:CentOS7 64位 Minimal版(VMware),安装MySQL5.7,Java1.8,Tomcat8.5,Redis3.2 配置网卡使用桥接,开启网卡并设置:静态ip、网关、子网掩码、DNS12# 编辑网卡配置vi /etc/sysconfig/network-scripts/ifcfg-eno16777736 1234567891011121314151617181920TYPE=EthernetBOOTPROTO=staticIPADDR=192.168.0.200GATEWAY=192.168.0.1NETMASK=255.255.255.0DNS1=192.168.0.1DEFROUTE=yesPEERDNS=yesPEERROUTES=yesIPV4_FAILURE_FATAL=noIPV6INIT=yesIPV6_AUTOCONF=yesIPV6_DEFROUTE=yesIPV6_PEERDNS=yesIPV6_PEERROUTES=yesIPV6_FAILURE_FATAL=noNAME=eno16777736UUID=11b992a7-1630-4a26-bd62-8ce65e3e5c78DEVICE=eno16777736ONBOOT=yes 12# 重启网络服务systemctl restart network 12# 查看ipip addr 配置防火墙MySQL默认端口为3306端口,Tomcat 默认端口为8080端口,Redis默认端口为6379端口。远程访问,需要打开防火墙。CentOS 7 中默认防火墙是firewalld,默认为关闭状态。123456789101112131415161718192021# 启动Firewallsystemctl start firewalld# 设置开机自启动systemctl enable firewalld# 开放mysql3306端口firewall-cmd --permanent --add-port=3306/tcp# 开放tomcat8080端口firewall-cmd --permanent --add-port=8080/tcp# 开放redis6379端口firewall-cmd --permanent --add-port=6379/tcp# 重载防火墙配置firewall-cmd --reload# 查看所有已开放端口firewall-cmd --list-ports# 移除某端口firewall-cmd --permanent --remove-port=端口名/tcp# 若无firewall-cmd命令则先安装firewalldyum install firewalld -y 一、安装配置MySQL 1. 配置YUM源在MySQL官网中下载YUM源rpm安装包:http://dev.mysql.com/downloads/repo/yum/ 12# 下载mysql源安装包wget http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm 12# 没wget的话先安装wgetyum install wget -y 12# 安装mysql源yum localinstall mysql57-community-release-el7-11.noarch.rpm -y 2. 安装MySQL1yum install mysql-community-server -y 12# 如果是CentOS8还需要先禁用mysql模块,否则可能会提示 No match for argument: mysql-community-serveryum module disable mysql 3. 启动MySQL服务1234# 启动服务systemctl start mysqld# 查看启动状态systemctl status mysqld 4. 配置开机启动12systemctl enable mysqldsystemctl daemon-reload 5. 修改root默认密码mysql安装完成之后,在/var/log/mysqld.log文件中给root生成了一个默认密码。通过下面的方式找到root默认密码,然后登录mysql进行修改:1grep 'temporary password' /var/log/mysqld.log 123456# 登录mysqlmysql -uroot -p# 修改密码ALTER USER 'root'@'localhost' IDENTIFIED BY 'Root000!'; # 或者set password for 'root'@'localhost'=password('Root000!'); 注意:mysql5.7默认安装了密码安全检查插件(validate_password),默认密码检查策略要求密码必须包含:大小写字母、数字和特殊符号,并且长度不能少于8位。否则会提示ERROR 1819 (HY000): Your password does not satisfy the current policy requirements错误。 通过msyql环境变量可以查看密码策略的相关信息:1show variables like '%password%'; validate_password_policy:密码策略,默认为MEDIUM策略validate_password_dictionary_file:密码策略文件,策略为STRONG才需要validate_password_length:密码最少长度validate_password_mixed_case_count:大小写字符长度,至少1个validate_password_number_count :数字至少1个validate_password_special_char_count:特殊字符至少1个上述参数是默认策略MEDIUM的密码检查规则。 共有以下几种密码策略: 策略 检查规则 0 or LOW Length 1 or MEDIUM Length; numeric, lowercase/uppercase, and special characters 2 or STRONG Length; numeric, lowercase/uppercase, and special characters; dictionary file MySQL官网密码策略详细说明:http://dev.mysql.com/doc/refman/5.7/en/validate-password-options-variables.html#sysvar_validate_password_policy 修改密码策略:在/etc/my.cnf文件添加validate_password_policy配置,指定密码策略12# 选择0(LOW),1(MEDIUM),2(STRONG)其中一种,选择2需要提供密码字典文件validate_password_policy=0 如果不需要密码策略,添加my.cnf文件中添加如下配置禁用即可:1validate_password = off 重新启动mysql服务使配置生效:1systemctl restart mysqld 6. 添加远程登录用户默认只允许root帐户在本地登录,如果要在其它机器上连接mysql,必须修改root允许远程连接,或者添加一个允许远程连接的帐户,为了安全起见,我添加一个新的帐户:123456GRANT ALL PRIVILEGES ON *.* TO 'testuser'@'%' IDENTIFIED BY 'Test000!' WITH GRANT OPTION;# 如果是MySQL8上述命令会报错,因为要先创建用户再进行赋权,不能同时进行,按以下语句分开执行CREATE USER 'testuser'@'%' IDENTIFIED BY 'Test000!';GRANT ALL PRIVILEGES ON *.* TO 'testuser'@'%' WITH GRANT OPTION;# 刷新用户权限表,立即生效flush privileges; 7. 配置默认编码为utf8修改/etc/my.cnf配置文件,在[mysqld]下添加编码配置,如下所示:123[mysqld]character_set_server=utf8init_connect='SET NAMES utf8' 12# 重新启动mysql服务使配置生效systemctl restart mysqld 1show variables like '%character%'; 查看数据库默认编码如下所示:默认配置文件路径:配置文件:/etc/my.cnf日志文件:/var/log//var/log/mysqld.log服务启动脚本:/usr/lib/systemd/system/mysqld.servicesocket文件:/var/run/mysqld/mysqld.pid 二、安装JAVA 安装Tomcat 前,需要提前安装JRE环境,如已安装,此步可以跳过。在CentOS中,JRE包名是java-$(version)-openjdk在这里,我安装是1.8的openjdk版本1yum install java-1.8.0-openjdk -y ps:特别注意的是,java-1.8.0-openjdk仅包含jre,如果需要使用jdk包则应为java-1.8.0-openjdk-devel安装完成后,验证一下:1java -version 三、安装配置Tomcat首先,下载最新版的Tomcat8,下载地址 http://tomcat.apache.org/download-80.cgi 下载安装包到/tmp目录。12cd /tmpwget http://mirror.bit.edu.cn/apache/tomcat/tomcat-8/v8.5.16/bin/apache-tomcat-8.5.16.tar.gz 然后,解压安装包到/opt目录,更改目录名为tomcat:123cd /opttar -zxvf /tmp/apache-tomcat-8.5.16.tar.gzmv apache-tomcat-8.5.16 tomcat 如果使用tomcat8之前的版本,还需要配置默认编码12cd /opt/tomcat/confvi server.xml 在下面两句末尾加上URIEncoding="UTF-8"123<Connector port=\"8080\" protocol=\"HTTP/1.1\" connectionTimeout=\"20000\" redirectPort=\"8443\" URIEncoding=\"UTF-8\"/><Connector port=\"8009\" protocol=\"AJP/1.3\" redirectPort=\"8443\" URIEncoding=\"UTF-8\"/> 建立自启动服务配置完成,接下来需要建立系统服务文件。1vi /etc/systemd/system/tomcat.service 文件内容如下:123456789101112131415161718192021[Unit]Description=Apache Tomcat 8After=syslog.target network.target[Service]Type=forkingUser=rootGroup=rootEnvironment=JAVA_HOME=/usr/lib/jvm/jre-1.8.0-openjdk-1.8.0.131-3.b12.el7_3.x86_64Environment=CATALINA_PID=/opt/tomcat/temp/tomcat.pidEnvironment=CATALINA_HOME=/opt/tomcatEnvironment=CATALINA_BASE=/opt/tomcatEnvironment='CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC'Environment='JAVA_OPTS=-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom'ExecStart=/opt/tomcat/bin/startup.shExecStop=/bin/kill -15 $MAINPID[Install]WantedBy=multi-user.target 配置文件中需要注意,JAVA_HOME变量的配置,需要按实际情况而定。保存文件然后按以下命令执行服务并配置自动启动。123systemctl daemon-reloadsystemctl start tomcatsystemctl enable tomcat 然后浏览器中打开,测试是否成功。 四、安装配置Redis 1. 下载Redis首先,下载Redis,我这里用的3.2.9,下载地址 https://redis.io/download 下载安装包到/tmp目录。123cd /tmpwget http://download.redis.io/releases/redis-3.2.9.tar.gz# 源地址在国外,存在不稳定的情况。若无法连接,请用p2p工具下载后ftp上传。 然后,解压安装包到/opt目录,更改目录名为redis123cd /opttar -zxvf /tmp/redis-3.2.9.tar.gzmv redis-3.2.9 redis 2. 编译安装12345678cd /opt/redis/srcmake# 错误提示:\"gcc:命令未找到\"、\"cc: 未找到命令\"# 编译需要安装gcc,用yum安装gccyum install gcc -y# 错误提示:\"致命错误:jemalloc/jemalloc.h:没有那个文件或目录\"# 需要加上参数,不然linux下会报错make MALLOC=libc 提示Hint: It's a good idea to run 'make test' ;)编译完成 make完成之后,进行make install,默认安装路径为/usr/local/bin下1make install 123456# 如下提示则安装完成INSTALL installINSTALL installINSTALL installINSTALL installINSTALL install 3. 创建redis服务运行utils目录下的install_server.sh脚本,运行后会询问你几个问题,包括指定redis的端口号指定redis的配置文件指定redis的日志文件指定redis的数据目录文件指定redis的可执行目录文件 均默认回车即可12cd /opt/redis./utils/install_server.sh 提示Installation successful!则安装完成。完成之后,redis的服务就添加完毕了,服务名为redis_6379 4. 修改配置查看redis的配置文件/etc/redis/6379.conf 其中主要的参数:bind:绑定的ip地址port:监听端口号pidfile:pid文件名dir:数据文件目录logfile:日志文件地址requirepass:设置密码protected-mode:保护模式daemonize:守护进程123vi /etc/redis/6379.conf# vi编辑器可在命令模式下使用set nu开启行号# 使用/xx命令来查找xx。n下一个,N上一个。 注释掉ip绑定,开启远程连接1# bind 127.0.0.1 解开requirepass的注释,设置一个访问密码1requirepass xx123 然后即可使用使用redis-cli连接redis12345678# 输入密码auth xx123# set一个key value expireset test 123 100# 获取一个get keyget test# 更新生存时间expire key secondsexpire test -1 若出现异常可在配置文件中关闭protected-mode保护模式,并且把daemonize设为yes作为守护进程在后台跑。12protected-mode nodaemonize yes 最后至此,基于CentOS 7 的MySQL+Tomcat+Redis的JavaWeb环境已安装配置完毕。12345678910111213141516# 开启服务systemctl start tomcatsystemctl start mysqldsystemctl start redis_6379# 停止服务systemctl stop tomcatsystemctl stop mysqldsystemctl stop redis_6379# 重启服务systemctl restart tomcatsystemctl restart mysqldsystemctl restart redis_6379# 查看服务状态systemctl status tomcatsystemctl status mysqldsystemctl status redis_6379 最最后:基于安全管理的前提条件下,每个程序最好都单独建立系统账号和组用于自身的运行。 例如:安装Tomcat前,单独建立系统帐号和组用于运行Tomcat。首先,创建一个新的tomcat组:groupadd tomcat然后,创建一个新的tomcat用户,指定home目录 /opt/tomcat ,并将tomcat用户加入tomcat组:useradd -M -s /bin/nologin -g tomcat -d /opt/tomcat tomcat接下来,配置目录的归属:chown -R tomcat:tomcat /opt/tomcat","tags":[{"name":"软件开发","slug":"软件开发","permalink":"http://inplus.top/tags/软件开发/"},{"name":"Java","slug":"Java","permalink":"http://inplus.top/tags/Java/"}]},{"title":"终端JuiceSSH v2.1.3特别破解版","date":"2017-06-25T16:51:32.000Z","path":"archives/juicessh/","text":"JuiceSSH – 比ConnectBot更强大的:一款专为Android打造的支持SSH、LocalShell、Mosh和Telnet的终端客户端。 功能特点: 全色彩的终端/SSH 客户端 突出式的键盘上有着所有有用而又难以找到的字符 使用音量键快速调整字体大小 支持使用外接键盘 支持在 irssi,weechat,tmux 和 screen 中使用手势 社区和第三方开发的插件 正式支持 mosh 支持 Telnet 支持 Android 本地 Shell 支持暗色,亮色,80’s hacker,Molokai,Solarized 暗色 和 Solarized 暗色 等终端配色 点击链接以在浏览器中打开 在会话中复制和粘帖 保存和分享 SSH 副本到 Dropbox/Evernote/Email 和 SD 卡 支持 UTF-8 字符 通过分组来便捷的管理连接 在后台保持多个 SSH 会话的连接 通过其他 SSH 连接代理连接 打开应用便能快速访问常用的连接 支持 IPv6 支持密码和 OpenSSH 私钥(ECDSA,RSA 和 DSA) RSA 密钥生成器(支持加密) SSH 密钥转发代理 支持二次认证(比如:Google Authenticator) 独立于连接的认证管理(用户/密码/密钥)。不必在修改密码时更新每个连接,直接更新认证信息即可,任何使用该认证的连接都会使用新的密码和密钥。 支持 zlib 压缩,从而优化 SSH 会话在高延迟时的表现 快速方便的通过应用或桌面挂件连接端口转发,还可以自动打开浏览器。 集成了对 Amazon AWS / EC2 的支持,自动根据分类和安全组来同步连接和分组。 通过加密的方式安全地在多台设备之间同步 自动地备份连接和设置,并使用 AES-256 加密 通过美观的桌面挂件快速访问常用的连接,或者是某组连接(Android 3.0+)。 团队合作。与你的团队成员共享某组连接,开始一起工作而不是各自为战。 通过代码片段库来便捷的使用常用命令 安全锁机制能自动在一段时间不使用后锁定 JuiceSSH 12345更新日志:2.1.3- Fixed Performance Monitor plugin on Android N+- New Material theme for Performance Monitor plugin (thanks hwding)- Fixed a few bad Italian translations 来源:https://juicessh.comGoogle Play:https://play.google.com/store/apps/details?id=com.sonelli.juicessh 修改说明: 破解完整高级功能 精简多余语言包 arm架构包体积精简 精简部分无用菜单项 精简bash、mosh_client、telnet架构库 补全部分汉化 zipalign对齐优化 修改人员:风澈vio(转载必须注明出处) 下载地址:百度网盘 密码:1024 注意: 使用者由此程序所造成的损失修改者不承担任何责任。 最终版权归原作者所有。 请在法律允许的范围内合理使用本程序。","tags":[{"name":"App","slug":"App","permalink":"http://inplus.top/tags/App/"}]},{"title":"一次Chrome滑稽之路...","date":"2017-06-11T23:20:00.000Z","path":"archives/chromeeggs/","text":"应该有不少人知道Chrome的离线小彩蛋,当你的电脑或手机无法连接网络的时候,Chrome会有下面这段提示: 而此时如果你敲一下空格键(手机用户则是按一下触摸屏),就会激活这个彩蛋啦。小恐龙开始在广阔无垠的大地上奔跑起来~ 而游戏其实很简单,类似简易版超级马里奥,不停敲击空格或者↑键跳起来避开障碍物,按↓键可以下蹲。 如果是暂时的断网,这个小游戏用来消磨下时间已经足够。 相信很多人随随便便也都能玩上两三百分,仔细玩一下便发现了这个游戏的有趣之处。 当你每获得100分,就会有个提示音出来表扬一下。 游戏速度也会越来越快。 而当你玩到400分以后,便有会飞的翼龙出现,阻挡你的前进步伐! 这时的小恐龙将会时长使用超能力:下蹲!用来躲过飞得不太高但又无法跳过的翼龙。 当你奔跑到大概700分,天会突然暗下来,开始了黑夜中的孤独奔跑。 相信很多玩到700分以后的高手都了解以上游戏流程,在此之后随着分数变化,开始黑夜与白天的交替,我们孤独的小恐龙在仙人掌和翼龙的阻挠下,顽强奔跑在荒芜的大地上,不知疲倦地经历了无数个日日夜夜…… 接着便是恢复网络开始正常上网,或者因为体力不支游戏重新来过…… 很少有人能坚持玩到3600分, 在一个没有网络的世界,面对着黑白两色的像素块独自坐上一上午甚至一整天,这该是多么的寂寞啊…… 12345↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓/**所以我们需要做一些有意思的事情...*/↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ Chrome的这个小游戏可能是为了断网的时候提供消遣的小插曲。 实际上你不需要断网,使用chrome://network-error/-106即可以使用它,因为这是一个chrome定义的网络错误,Google工程师也会使用这种方式来测试而不是断网。可以通过chrome://network-errors来查看所有的网络错误。 仔细研究一下这个彩蛋,Ctrl+Shift+i查看网络访问资源,我们可以从网页中找到这样的图像。 究其根本,其实游戏中几乎所有的图片都裁剪于这幅图。(把游戏真正底层的东西拿出来会发现很让人失望,但是正是这些“冰冷的规则”如同我们不忍直视的内脏器官一样支持了表面的光鲜亮丽)。 我们进入调试界面来验证一下。 F12,然后选中 console 我事先做好了一张“完美”的脑补图。。。 下面我们输入命令将图片改成这个(请确保这个时候连着网以便加载图片,即使用之前不需断网的方法): 1document.getElementById(\"offline-resources-1x\").src=\"https://ooo.0o0.ooo/2017/05/30/592d2daed3309.png\" 即 于是再次玩的时候就变成了这个样子 其实我们还可以实现很多脑补的效果,例如: 我们设置15秒后执行刚才的命令,然后立刻开始游戏: 1setTimeout(()=>{document.getElementById(\"offline-resources-2x\").src=\"https://ooo.0o0.ooo/2017/05/30/592d2daed3309.png\"}, 15000) 这样大约15秒后会突然滑稽。。。 一切毫无违和感。 特别感谢@庄思源","tags":[{"name":"宇宙之大","slug":"宇宙之大","permalink":"http://inplus.top/tags/宇宙之大/"}]},{"title":"在MySQL中实现Rank高级排名函数","date":"2017-06-06T14:35:06.000Z","path":"archives/mysqlrank/","text":"MySQL中没有Rank排名函数,当我们需要查询排名时,只能使用MySQL数据库中的基本查询语句来查询普通排名。尽管如此,可不要小瞧基础而简单的查询语句,我们可以利用其来达到Rank函数一样的高级排名效果。 在这里我用一个简单例子来实现排名的查询: 首先我们先创建一个我们需要进行高级排名查询的players表, 123456789101112131415161718192021CREATE TABLE `players` ( `pid` int(2) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL, `age` int(2) NOT NULL, PRIMARY KEY (`pid`), UNIQUE KEY `name` (`name`)) ENGINE=InnoDB DEFAULT CHARSET=latin1;INSERT INTO `players` (`pid`, `name`, `age`) VALUES(1, 'Samual', 25),(2, 'Vino', 20),(3, 'John', 20),(4, 'Andy', 22),(5, 'Brian', 21),(6, 'Dew', 24),(7, 'Kris', 25),(8, 'William', 26),(9, 'George', 23),(10, 'Peter', 19),(11, 'Tom', 20),(12, 'Andre', 20); 1、在MySQL中实现Rank普通排名函数在这里,我们希望获得一个排名字段的列,以及age的升序排列。所以我们的查询语句将是:12345SELECT pid, name, age, @curRank := @curRank + 1 AS rankFROM players p, (SELECT @curRank := 0) qORDER BY age 1234567891011121314| PID | NAME | AGE | RANK ||-----|---------|-----|------|| 10 | Peter | 19 | 1 || 12 | Andre | 20 | 2 || 2 | Vino | 20 | 3 || 3 | John | 20 | 4 || 11 | Tom | 20 | 5 || 5 | Brian | 21 | 6 || 4 | Andy | 22 | 7 || 9 | George | 23 | 8 || 6 | Dew | 24 | 9 || 7 | Kris | 25 | 10 || 1 | Samual | 25 | 11 || 8 | William | 26 | 12 | 要在mysql中声明一个变量,你必须在变量名之前使用@符号。FROM子句中的(@curRank := 0)部分允许我们进行变量初始化,而不需要单独的SET命令。当然,也可以使用SET,但它会处理两个查询:1234SET @curRank := 0;SELECT pid, name, age, @curRank := @curRank + 1 AS rankFROM playersORDER BY age 2、查询以降序排列首要按age的降序排列,其次按name进行排列,只需修改查询语句加上ORDER BY和 DESC以及列名即可。12345SELECT pid, name, age, @curRank := @curRank + 1 AS rankFROM players p, (SELECT @curRank := 0) qORDER BY age DESC, name 1234567891011121314| PID | NAME | AGE | RANK ||-----|---------|-----|------|| 8 | William | 26 | 1 || 7 | Kris | 25 | 2 || 1 | Samual | 25 | 3 || 6 | Dew | 24 | 4 || 9 | George | 23 | 5 || 4 | Andy | 22 | 6 || 5 | Brian | 21 | 7 || 12 | Andre | 20 | 8 || 3 | John | 20 | 9 || 11 | Tom | 20 | 10 || 2 | Vino | 20 | 11 || 10 | Peter | 19 | 12 | 3、在MySQL中实现Rank普通并列排名函数现在,如果我们希望为并列数据的行赋予相同的排名,则意味着那些在排名比较列中具有相同值的行应在MySQL中计算排名时保持相同的排名(例如在我们的例子中的age)。为此,我们使用了一个额外的变量。12345678SELECT pid, name, age, CASE WHEN @prevRank = age THEN @curRank WHEN @prevRank := age THEN @curRank := @curRank + 1END AS rankFROM players p, (SELECT @curRank :=0, @prevRank := NULL) rORDER BY age 1234567891011121314| PID | NAME | AGE | RANK ||-----|---------|-----|------|| 10 | Peter | 19 | 1 || 12 | Andre | 20 | 2 || 2 | Vino | 20 | 2 || 3 | John | 20 | 2 || 11 | Tom | 20 | 2 || 5 | Brian | 21 | 3 || 4 | Andy | 22 | 4 || 9 | George | 23 | 5 || 6 | Dew | 24 | 6 || 7 | Kris | 25 | 7 || 1 | Samual | 25 | 7 || 8 | William | 26 | 8 | 如上所示,具有相同数据和排行的两行或多行,它们都会获得相同的排名。玩家Andre, Vino, John 和Tom都有相同的age,所以他们排名并列第二。下一个最高age的玩家(Brian)排名第3。这个查询相当于MSSQL和ORACLE 中的DENSE_RANK()函数。 4、在MySQL中实现Rank高级并列排名函数当使用RANK()函数时,如果两个或以上的行排名并列,则相同的行都会有相同的排名,但是实际排名中存在有关系的差距。123456789SELECT pid, name, age, rank FROM(SELECT pid, name, age,@curRank := IF(@prevRank = age, @curRank, @incRank) AS rank, @incRank := @incRank + 1, @prevRank := ageFROM players p, (SELECT @curRank :=0, @prevRank := NULL, @incRank := 1) r ORDER BY age) s 这是一个查询中的子查询。我们使用三个变量(@incRank,@prevRank,@curRank)来计算关系的情况下,在查询结果中我们已经补全了因为并列而导致的排名空位。我们已经封闭子查询到查询。这个查询相当于MSSQL和ORACLE中的RANK()函数。1234567891011121314| PID | NAME | AGE | RANK ||-----|---------|-----|------|| 10 | Peter | 19 | 1 || 12 | Andre | 20 | 2 || 2 | Vino | 20 | 2 || 3 | John | 20 | 2 || 11 | Tom | 20 | 2 || 5 | Brian | 21 | 6 || 4 | Andy | 22 | 7 || 9 | George | 23 | 8 || 6 | Dew | 24 | 9 || 7 | Kris | 25 | 10 || 1 | Samual | 25 | 10 || 8 | William | 26 | 12 | 在这里我们可以看到,Andre,Vino,John和Tom都有相同的age,所以他们排名并列第二。下一个最高年龄的球员(Brian)排名第6,而不是第3,因为有4个人并列排名在第2。 好的,我希望在这些例子后,能让你了解RANK()和DENSE_RANK()之间的区别,并且知道在哪里应使用哪个查询来获取MySQL中的rank函数。谢谢。 via http://fellowtuts.com/mysql/query-to-obtain-rank-function-in-mysql","tags":[{"name":"软件开发","slug":"软件开发","permalink":"http://inplus.top/tags/软件开发/"},{"name":"mysql","slug":"mysql","permalink":"http://inplus.top/tags/mysql/"}]},{"title":"Android逆向之smali语法宝典","date":"2017-05-02T23:47:09.000Z","path":"archives/android-reverse-smali/","text":"前言Android采用的是java语言进行开发,但是Android系统有自己的虚拟机Dalvik和ART,代码编译最终不是采用的java的class,而是使用的smali。我们反编译得到的代码,jar的话可能很多地方无法正确的解释出来,如果我们反编译的是smali则可以正确的理解程序的意思。因此,我们有必要熟悉smali语法。 关键字.field private isFlag:z — 定义变量.method — 方法.parameter — 方法参数.prologue — 方法开始.line 12 — 此方法位于第12行invoke-super — 调用父函数const/high16 v0, 0x7fo3 — 把0x7fo3赋值给v0invoke-direct — 调用函数return-void — 函数返回void.end method — 函数结束new-instance — 创建实例iput-object — 对象赋值iget-object — 调用对象invoke-static — 调用静态函数 数据类型java里面包含两种数据类型,基本数据类型和引用类型(包括对象),同时映射到smali也是有这两大类型。 基本数据类型 B — byte C — char D — double (64 bits) F — float I — int J — long (64 bits) S — short V — void 只能用于返回值类型 Z — boolean 对象类型 Lxxx/yyy/zzz; — object L表示这是一个对象类型xxx/yyy是该对象所在的包zzz是对象名称;标识对象名称的结束 数组类型 [XXX — array [I表示一个int型的一维数组,相当于int[]增加一个维度增加一个[,如[[I表示int[][]数组每一个维度最多255个;对象数组表示也是类似,如String数组的表示是[Ljava/lang/String 寄存器与变量java中变量都是存放在内存中的,android为了提高性能,变量都是存放在寄存器中的,寄存器为32位,可以支持任何类型,其中long和double是64为的,需要使用两个寄存器保存。寄存器采用v和p来命名v表示本地寄存器,p表示参数寄存器,关系如下如果一个方法有两个本地变量,有三个参数 v0第一个本地寄存器v1第二个本地寄存器v2 p0(this)v3 p1第一个参数v4 p2第二个参数v5 p3第三个参数 当然,如果是静态方法的话就只有5个寄存器了,不需要存this了。.registers使用这个指令指定方法中寄存器的总数.locals使用这个指定表明方法中非参寄存器的总数,放在方法的第一行。 方法和字段方法签名methodName(III)Lpackage/name/ObjectName;如果做过ndk开发的对于这样的签名应该很熟悉的,就是这样来标识一个方法的。上面methodName标识方法名,III表示三个整形参数,Lpackage/name/ObjectName;表示返回值的类型。 方法的表示Lpackage/name/ObjectName;——>methodName(III)Z即 package.name.ObjectName中的 function boolean methondName(int a, int b, int c) 类似这样子 字段的表示Lpackage/name/ObjectName;——>FieldName:Ljava/lang/String;即表示: 包名,字段名和各字段类型 方法的定义比如下面的一个方法123private static int sum(int a, int b) { return a+b;} 使用编译后是这样1234567891011121314151617.method private static sum(II)I .locals 4 #表示需要申请4个本地寄存器 .parameter .parameter #这里表示有两个参数 .prologue .line 27 move v0, p0 .local v0, a:I move v1, p1 .local v1, b:I move v2, v0 move v3, v1 add-int/2addr v2, v3 move v0, v2 .end local v0 #a:I return v0.end method 从上面可以看到函数声明使用.method开始 .end method结束,java中的关键词private,static 等都可以使用,同时使用签名来表示唯一的方法,这里是sum(II)I。 声明成员.field private name:Lpackage/name/ObjectName;比如:private TextView mTextView;表示就是.field private mTextView:Landroid/widget/TextView;private int mCount;.field private mCount:I 指令执行smali字节码是类似于汇编的,如果你有汇编基础,理解起来是非常容易的。比如:move v0, v3 #把v3寄存器的值移动到寄存器v0上.const v0, 0x1 #把值0x1赋值到寄存器v0上。invoke-static {v4, v5}, Lme/isming/myapplication/MainActivity;->sum(II)I #执行方法sum(),v4,v5的值分别作为sum的参数。 条件跳转分支“if-eq vA, vB, :cond_x” — 如果vA等于vB则跳转到:cond_x“if-ne vA, vB, :cond_x” — 如果vA不等于vB则跳转到:cond_x“if-lt vA, vB, :cond_x” — 如果vA小于vB则跳转到:cond_x“if-ge vA, vB, :cond_x” — 如果vA大于等于vB则跳转到:cond_x“if-gt vA, vB, :cond_x” — 如果vA大于vB则跳转到:cond_x“if-le vA, vB, :cond_x” — 如果vA小于等于vB则跳转到:cond_x“if-eqz vA, :cond_x” — 如果vA等于0则跳转到:cond_x“if-nez vA, :cond_x” — 如果vA不等于0则跳转到:cond_x“if-ltz vA, :cond_x” — 如果vA小于0则跳转到:cond_x“if-gez vA, :cond_x” — 如果vA大于等于0则跳转到:cond_x“if-gtz vA, :cond_x” — 如果vA大于0则跳转到:cond_x“if-lez vA, :cond_x” — 如果vA小于等于0则跳转到:cond_x 参考资料最后附上一些参考资料:http://pallergabor.uw.hu/androidblog/dalvik_opcodes.htmlhttps://code.google.com/p/smali/w/listhttp://blog.csdn.net/lpohvbe/article/details/7981386http://blog.csdn.net/lpohvbe/article/details/7983907 特别感谢@Sam","tags":[{"name":"Android","slug":"Android","permalink":"http://inplus.top/tags/Android/"},{"name":"逆向札记","slug":"逆向札记","permalink":"http://inplus.top/tags/逆向札记/"}]},{"title":"3D桌球Pool Break Pro v2.7.2汉化特别版","date":"2017-04-23T21:00:20.000Z","path":"archives/poolbreak/","text":"Pool Break是一套具有多种台球玩法,包括八球,九球,斯诺克,克朗棋和加拿大棋等十余种台球的一套游戏,其逼真的物理逻辑系数和图形渲染效果以及方便快捷的操作方式均有可圈可点之处。更值得一提的是, 其不仅可以人机对战, 且支持联网对战。 功能特点: 十余种桌球游戏合一 支持多国语言 在线跨平台多人游戏 在线聊天 有四个难度级别的电脑对手 单机多人轮流模式 逼真的桌球物理效果 多种形状球台 扎杆和偏杆 可视化的用户界面 竖屏和横屏双模式 内置帮助手册 国际惯例:介绍截图没有更新 12345678910111213141516171819202122更新日志:Version 2.7.2:• Choose from 15 different Cue Textures• Option to match opponents with identical aiming lines• Chat window fixes• Stability improvements• Fixed ball going through rail in Circular Pool gamesVersion 2.7.0:• Circular tables added for Pool and Snooker• New Game: Karambol - Carrom Billiards with no cushion requirements• Place-n-Shoot mode for pocketless billiards games• Chat dialog updated• Fixed color ball spotting rules in Snooker• Other minor improvements and stability fixesVersion 2.6.5:• Allows replay of winning shot after game over• Stability improvements and bug fixesVersion 2.6.4:• Added Leaderboards and Achievements• Fixed Spanish translation issues• Minor bug fixes 来源:http://www.kineticbytes.comGoogle Play:https://play.google.com/store/apps/details?id=com.kb.Carrom3DFull 修改说明: 破解正版验证,修复闪退 修正并补全简体中文汉化 增加了相关帮助信息和文档的汉化 精简语言并剔除相关选项 zipalign对齐优化 修改人员:风澈vio(转载必须注明出处) ※下载地址:城通网盘(进入下载列表-最下方普通低速单线程下载)※ 注意: 使用者由此程序所造成的损失修改者不承担任何责任。 最终版权归原作者所有。 请在法律允许的范围内合理使用本程序。","tags":[{"name":"App","slug":"App","permalink":"http://inplus.top/tags/App/"}]},{"title":"input[file]标签点击选择文件响应很慢的解决办法","date":"2017-03-30T09:02:40.000Z","path":"archives/inputfiletime/","text":"input[file]标签的accept属性可用于指定上传文件的MIME类型。例如,想要实现默认上传图片文件的代码,代码可如下:1<input type=\"file\" name=\"file\" class=\"element\" accept=\"image/*\"> 效果如下图所示,默认过滤掉所有非图片文件: 但是! 这段代码在Chrome和Safari等Webkit浏览器下却出现了响应滞慢的问题,可能要等 6~10s 才能弹出文件选择对话框。简直不能忍呀。 在IE和Firefox中使用accept="image/*"属性则没有发现响应延迟的问题。 于是几经尝试后,发现是accept="image/*"属性的问题,删掉它或者将*通配符修改为指定的MIME类型,就可以解决Webkit浏览器下的对话框显示滞慢的问题。 解决办法如下:1<input type=\"file\" accept=\"image/gif,image/jpeg,image/jpg,image/png\"> accept="image/*"属性会对每一个文件都遍历一次所有的"image/*"文件类型,当文件较多时,文件的检验时间较长,这可能是Webkit的底层实现的bug。 另外, accept="audio/*"和accept="video/*"属性 在 Webkit浏览器下也会有同样的响应延迟的问题。同理,通过将*通配符 修改成指定的MIME类型就可解决。 需要注意的是:当form表单含有file文件类型的话,需要将form表单的属性加上enctype="multipart/form-data" 特别感谢@子匠_Zijor","tags":[{"name":"软件开发","slug":"软件开发","permalink":"http://inplus.top/tags/软件开发/"}]},{"title":"再回首-百度高精度IP定位服务","date":"2017-03-18T22:56:40.000Z","path":"archives/baiduip/","text":"如上图,就是现在打开下面的百度高精度IP定位服务的API首页的提示。API首页:http://lbsyun.baidu.com/index.php?title=webapi/high-acc-ip ip定位历史关于IP定位,最早是通过运营商实现,每个运营商申请到的ip段,在某个范围内使用。因此早期只能是国家为单位的基础数据。对于比较大的国家,就进一步划分,比如,中国某通讯公司(不打广告),固定将某些ip分配某些机房使用,而这些机房则具备地域属性,因此就可以知道某些ip的位置是哪个省市区。在进一步,网上有种测算路由的方式进行定位,就是由大范围逐个跳转,跟踪路由。从而对比找出ip所在的小范围。 前提条件如今,网络铺设已经有个相当多的特性,比如:A.国内的某大运营商,ip资源够用,直接给用户分配公网ip。我以前就在这种网络下用动态域名工具玩过网站。B.部分运营上为了缓解ip资源不足问题,某个大范围使用代理转发方式,给到用户的是私网ip,用户最终用代理的ip池的ip访问公网。C.电话运营商,ip资源利用率过低,几乎是一个省份用一个ip池进行代理给用户的手机网络上网 延伸价值随着大数据的发展,百度做了大数据匿名收集数据,数据实时分析。因此可以将手机收集到的精准GPS数据和当前所用IP数据成对上报给后端服务器,运算过之后,就可以得出某个IP的分布范围数据。误差说明:对于上述A的情况,精确度可以达到几十米对于上述B的情况,可能得覆盖一个城市的范围对于上述C的情况,往往是一个省份的误差程度因此,对于有线宽带用户,分配了相对固定的公网IP,用户在这个线路下有放置了wifi无线路由器,wifi下有接入了手机用户,手机里运行了百度的服务,比如百度地图,或者百度地图SDK。其定位精度就可以达到几十米范围。对于这种数据,只有bat这种大头才能实现的了这个规模的数据手机,因此准确度几乎无法被超越,更大的互联网公司除外 定位分析目前百度定位提供了WIFI,基站,GPS等多种定位方式,适用于室内、室外多种定位场景,具有出色的定位性能:定位精度高(其实我是想吐槽的)、覆盖率广、网络定位请求流量小、定位速度快。众所周知,通过IP地址我们只能查到某一个市级城市的宽带服务商所在地。但是,百度高精度定位却能产生近乎30m内的定位精度,这是为什么呢? 百度高精度定位产生百度官方文档显示:2016年8月26日,高精度IP定位服务API正式上线。 百度高精度IP定位服务,其根本来源于百度匿名收集服务,它的源头则是:手机位置服务。当然,不排除百度其他应用的sdk,百度的其他应用如百度地图,也进行了这个匿名收集服务,至少百度收集这些数据并非出于泄露隐私目的,毕竟这项数据单方面来说是脱敏的,就好比是网络上一张盖住脸的裸体照片。但是,大数据发展导致我们可以用各个数据源去拼凑一个完整画像,有意无意导致一个泄露隐私的结果。 因此百度在接到投诉后,首先将高精度 IP 定位接口的配额大幅下调,其次,很快就关停了新用户开通这项服务。 在百度高精度IP定位服务刚上线的 2016 年 9 月、10月,那时候百度给的的配额还相对较高,公开申请:认证企业开发者10W 次 /天,认证个人开发者1W 次 /天,非认证用户通过手机验证1k 次 /天。 但是不确定在10月份或11月份某一天,百度直接下调到:认证企业开发者300次/天,认证个人开发者100次/天,非认证用户数据不详。 然而在12月10号前百度撤销了官方api文档,并停止了该服务的ak权限的申请,之前已经申请了的权限的ak仍可继续使用。推测原因是这项功能推出后,被太多人用来达成不良目的所导致(例如定位QQ,微信,陌陌等社交账号所在位置)。然而像类似于任天堂《Pokemon Go》这款LBS-AR游戏并没有很好地去使用这一服务。 何去何从 针对现状来看,百度的这项服务,目前推测有2个方向:1,关停(停止新接入或者整个服务对外关停)。2,整顿权限(以更严格的审核方式对外提供)更新:2017年7月起,开发者陆续收到百度终止高精度IP定位服务API的通知邮件。至此,百度高精度定位服务正式退出历史舞台。原文: 亲爱的开发者,您好! 我们很抱歉的通知您,目前您正在使用的「高精度IP定位服务API,后文简称本服务」,由于国家《网络安全法》等法律法规的要求,及出于保护用户权益和安全性的考量,我们将终止您对「本服务」的使用权限。具体终止时间为2017年7月28日。如有疑问,可发送邮件到[email protected] 咨询。 如果您在自身业务中已使用「本服务」,为避免业务受损,请在2017年7月28日前迁移到其他服务使用;如果您从未使用过「本服务」,请忽略本通告的内容。 如果您同时还使用了百度地图开放平台所提供的其他服务,请不用担心,「本服务」的使用权限终止不会影响您对其他服务的使用。 最后,再次感谢您对百度地图开放平台长期以来的信赖与支持! 百度高精度ip定位API下面提供了百度高精度ip定位的API供参考 1、申请百度账号,创建应用,获取密钥(AK)http://lbsyun.baidu.com/apiconsole/key启用服务:可以根据自己需求来钩选,这里先全选了。请求校验方式:IP白名单校验/SN检验,这里选择IP白名单校验。即在下面填上你访问机器的IP地址。如(114.114.114.114)。单击提交,获得AK 2、详细API:服务地址:http://api.map.baidu.com/highacciploc/v1 https://api.map.baidu.com/highacciploc/v1参数:qcip待定位IP 可选 如果为空则针对定位服务的IP进行定位ak开发者密钥,即前面申请的东西extensions返回结果扩展设定(可选):0:只返回基础定位结果(默认)1:返回基础定位结果+地址信息2:返回基础定位结果+周边POI信息3:返回基础定位结果+地址信息+POI信息这里我们用1coord返回坐标类型(可选):bd09百度墨卡托坐标(默认)bd09ll百度经纬度坐标gcj02国测局经纬度坐标 完整调用:在浏览器地址栏输入以下网址https://api.map.baidu.com/highacciploc/v1?qcip=220.181.38.113&ak=你申请的AK&extensions=1&coord=bd09ll 获取结果如下: 返回值说明:这里默认用的是返回json格式的数据。 特别感谢@季雨林 @openGPS","tags":[{"name":"软件开发","slug":"软件开发","permalink":"http://inplus.top/tags/软件开发/"}]},{"title":"相片处理VSCO Cam v20.1全滤镜+v3.7经典版","date":"2017-03-13T22:51:32.000Z","path":"archives/vsco/","text":"VSCO Cam – 一款依托强大滤镜功能的相片处理应用程序。 VSCO Cam来自VSCO(Visual Supply Co.的简写),在移动应用领域取得成功之前,该公司就一直从事数码照片美化工作,其为Adobe Lightroom 和苹果Aperture开发的著名色彩插件VSCO Film非常受欢迎。其iOS版也曾在苹果的App Store中排名榜首,现在VSCO Cam安卓版的推出将让更多的用户领略到这款软件的魅力。 与普通照片拍摄加后期处理的软件不同,VSCO Cam的滤镜能够将拍摄的照片呈现出最接近传统胶片的效果。VSCO Cam几乎包含了VSCO Film的全部胶片色彩风格,利用它处理过的照片照片文艺范十足。 如果说Instagram的目的是让手机拍出好看好看的照片,那VSCO Cam寻求的就是真实感,并逼真的模仿出胶片的风格和色彩效果,比如柯达Porta,逼真的再现了胶片的拍摄风格和色彩。 使用任何一款VSCO的滤镜,都能够使照片模拟出不同胶片拍出来的效果。比如,C3滤镜通过使用拥有鲜亮活泼的色彩对比和绿色色调模仿富士生胶底片的效果;LV1滤镜则能够模仿经典幻灯片的效果。 功能特点: 创作利用出众的移动预设和高级相机控制功能,拍照并编辑图像。发布图片或在您的 VSCO 个人资料中精心展出其他作品。 发现探索关注对象发表的作品、来自社区的精选作品以及来自 VSCO Originals 的独家编辑内容。 交流加入 VSCO 社区。查找并关注好友以及世界各地的用户。 国际惯例:介绍截图没有更新 123456更新日志:每次更新都是什么鬼:• 没有日志!• 我任性!• +1s• +2s 来源:http://vsco.coGoogle Play:https://play.google.com/store/apps/details?id=com.vsco.cam 修改说明: 免Root直装,解锁120余款收费滤镜 精简多余语言包 armv7a架构精简 apk包体积优化 Zipalign对齐优化 去除第三方市场检测更新 修改人员:风澈vio(转载必须注明出处) 下载地址:百度网盘 密码:1024 注意: 使用者由此程序所造成的损失修改者不承担任何责任。 最终版权归原作者所有。 请在法律允许的范围内合理使用本程序。","tags":[{"name":"App","slug":"App","permalink":"http://inplus.top/tags/App/"}]},{"title":"没有比打Emoji台球更惬意的事了(gif)","date":"2017-01-30T23:20:00.000Z","path":"archives/poolmoji/","text":"当数字艺术家jean-baptiste le divelec在工作中发现一个新的台球桌,他决定和他的一群朋友做一些有意思的事情——创造一些特殊的台球。借鉴时下无处不在的emoji表情符,他的团队手绘了15颗emoji台球,称之为“poolmoji”,并拍下gif动图,比起台球运动本身,它们则更生动可爱,十分有趣,让我们来看看吧~ 我不想死~ 好折磨啊~ 哎哟哟~ 明天见~ 别别别别别~别碰我 等等我呀~ 不准再这样了~ 啊哦~ 爆头一击~ 同志们辛苦啦~ 张小明,出列! 谁能体会单身狗的悲伤T T 终于解散了~ 你瞅啥~ 同桌你好~ 幕后制作 Winigreeni正在认真工作 Emoji 完成中… via boredpanda,designboom","tags":[{"name":"宇宙之大","slug":"宇宙之大","permalink":"http://inplus.top/tags/宇宙之大/"}]},{"title":"利用IDA简单过so签名校验","date":"2017-01-16T18:36:09.000Z","path":"archives/idasignature/","text":"核心:破解安卓NDK端native方法动态JNI反射的so文件签名校验 分析之前,关于Android的签名机制就略过啦,先简单恶补一下Android签名校验的方式,方便小白理解。 在讲签名校验的方式前,需要先明确dex文件校验和签名校验:1、将apk以压缩包的形式打开删除原签名后,再签名,安装能够正常打开,但是用IDE工具反编译(classes.dex)后再二次打包,却出现非正常情况的,如:闪退/弹出非正版提示框。可以确定是dex文件校验。2、将apk以压缩包的形式打开删除原签名再签名,安装之后打开异常的,则基本可以断定是签名检验。如果在断网的情况下同样是会出现异常,则是本地的签名检验。如果首先出现的是提示网络没有连接,则是服务器端的签名校验。 对于Android编程我们知道分为SDK编程和NDK编程,当然Android签名校验也都是通过SDK或NDK来实现的。SDK编程也就是我们通常所说的java端的即编译出来的classes.dex静态校验,NDK编程也就是C / C++端的即编译出来的*.so动态加载的校验。 总之,Java层一般通过getPackageManager().getPackageInfo.signatures来获取签名信息。NDK层一般调用Native方法/DLL/Lua脚本等通过获取Java的context/Activity对象,动态JNI反射调用getPackageInfo等来获取签名。 好了,话不多说,切入正题。 群里聊天,小伙伴找我去除某款图像处理软件的广告,介于此软件已一年未更新,且互联网上出现的修改版均无法使用。。。。那么。。开搞。。。。 apk重签名,闪退,断定有签名校验。直接拖入AndroidKiller大法,一段等待之后反编译完毕。 因为没有错误提示,那么对整个项目搜索1signatures 或1[Landroid/content/pm/Signature 或1Landroid/content/pm/PackageInfo;->signatures:[Landroid/content/pm/Signature 或1Ljava/security/Signature;->verify([B)Z 等一系列可能调用或者判断签名的方法我们基本找到四处可能为签名对比函数的验证,我们让其强制返回true。 满心欢喜的回编译,安装。。。。。结果。。依旧闪退。。。内心无数匹你懂得马奔驰而过。。。。 看到\\lib目录和\\assets\\lib目录下的.so文件,我倒是有些怀疑悬疑在.so动态文件中。 继续对整个项目搜索1loadLibrary 或1Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V 等一系列读取.so文件的方法我们得到了三个结果,前两个是图像处理的lib,第三个嘛。。。别急啊!先等等。。。 以armeabi-v7a架构为例,我们把所有lib都弄到一起,用EditPlus或者UltraEdit呀notepad++呀之类的编辑器来全局搜索signature 看看我们得到了什么~我的天哪,有戏啊! 说时迟那时快,我的IDA已经饥渴难耐。 New-Open-Ok一气呵成! 打开文本查找: 搜索signature 勾选上Find all occurences 搜索完毕,没什么说的,妥妥的在5个Function中找到 双击第一个Function跳过去 右键选择Graph view切换图形视图 通过视图,我们找到了一个关键跳转(可以通过Ctrl+鼠标滑轮来调整视图缩放) 右键选择Text view切换回文本视图 其对应的就是文本视图界面中的 F5看一下C语言代码(这样做的前提是,你的IDA Pro必须支持F5功能) 通过分析C代码我们得知这里将获取到的签名信息进行判断,由此我们得知BEQ指令就是问是不是不相等,不相等那么为真的意思。而查阅之后印证了我们的判断: BEQ指令是“相等(或为0)跳转指令”,BNE指令是“不相等(或不为0)跳转指令”,B指令是“无条件跳转指令”,CBZ 指令是“比较,为零则跳转”,CBNZ指令是“比较,为非零则跳转”。 通过工具,我们发现: BNE跳转指令对应的HEX机器码是D1,BEQ跳转指令对应的HEX机器码是D0,CBZ跳转指令对应的HEX机器码是B1,CBNZ跳转指令对应的HEX机器码是B9。 回过头来,简单的看一下指令流程,BEQ下面是exit方法,则说明不能跳转指令为签名验证失败,反向逻辑一下,把BEQ指令改为相反的BNE指令即可。 修改方式一:我们可以在HEX界面右键Edit将D0改为D1,再右键Apply changes来保存修改,需要注意的是,在IDA中的修改仅仅是为了验证我们修改的正确与否,源文件并不会改变,我们可以定位修改位置后再利用010Editor、UltraEdit等编辑器来对源文件进行修改。 验证发现BEQ已经修改为BNE 修改方式二:当然,强大的IDA怎么可能没有修改后保存的功能呢。我们可以使用Edit->Patch Program菜单来方便的进行修改保存。(需要注意的是,Patch Program菜单是GUI版本的IDA的一项隐藏功能,用户需要编辑idagui.cfg配置文件才能激活该菜单, 编辑IDA配置文件cfg目录下的idagui.cfg,修改DISPLAY_PATCH_SUBMENU=YES,重启IDA即可) 首先我们在IDA View 中显示十六进制机器码, Options -> General -> Disassembly -> Number of opcode bytes = 8 然后Edit->Patch Program->Change byte 将D0改为D1,OK 然后Edit->Patch Program->Apple patches to input file OK即可 同理,我们找到其他方法中的跳转点来进行反向逻辑,保存so文件,覆盖原文件,回编译,安装。完美运行~ 具体去广告过程不是本次重点所以就不再过多陈述,另外说一点sdk23以上的权限请求问题,当过完签名校验并去除广告后,当要读取图库照片来进行处理时,原本应该进行文件存储的权限请求,但是此时却FC了,当我手动给予权限后才正常。想想就苦恼,让人安装后边还得手动给权限。。。。 不行,我们得解决了它。我们知道如果APP运行在Android 6.0或以上版本的手机,并且target sdk>=23,那么在使用一些相对敏感的权限时,需要征求用户的许可。比如读写sdcard,摄像,联系人信息等。 这是Android 6.0,在原有的AndroidManifest.xml声明权限的基础上,新增了运行时权限动态检测。不过为了兼容性,Android为targetSdkVersion小于23的应用默认授予了所申请的所有权限,所以如果你以前的APP设置的targetSdkVersion低于23,也能正常使用。等于或者大于23,则必须 request permission,否则会崩溃闪退。 当我们用apktool反编译后破坏了complierSdkversion的值,我们可以在apktool.yml中的sdkInfo中添加complierSdkversion: '23',或者干脆我们索性将targetSdkVersion设置为22,默认给它权限就好了。(complierSdkversion的值和targetSdkVersion的值一定要统一,不然会出错) 修改apktool.yml文件完美解决~ 步骤回顾:1、反编译apk2、利用关键词查找签名调用3、IDA静态调试分析4、了解arm指令详情作用5、修改逻辑跳转绕过签名校验 总结:本文主要介绍破解安卓NDK端native方法动态JNI反射so文件签名校验的方法。","tags":[{"name":"Android","slug":"Android","permalink":"http://inplus.top/tags/Android/"},{"name":"逆向札记","slug":"逆向札记","permalink":"http://inplus.top/tags/逆向札记/"}]},{"title":"图片处理Pixlr Express v3.0.3独家去广告破解版","date":"2017-01-14T22:58:20.000Z","path":"archives/pixlr/","text":"Pixlr Express – 一款适合每个人的照片编辑器:不论您是从未编辑过照片的新人,还是一名专业人士,Pixlr 均可提供您需要的所有工具和特效。 Pixlr Express图片处理是Autodesk推出的一款免费安卓图片处理软件,内置600多种特效及滤镜,包含了优秀免费修图软体常见的特效滤镜套用、曝光对比调整、相框与特殊光线外挂等等,但又更进一步的,加入了像是去除红眼、去除特定颜色、去除噪点或锐利化、加上白光、移轴镜等等功能,而且每种功能、每个特效都提供了细部调整,让一般用户也能简单把特效变得更专业。 功能特点: 通过各种布局、背景和间距选项,创建照片拼贴。 借助“自动修复”,轻松单击一下即可平衡颜色。 使用“双重曝光”逐层放置多张照片并将其混合在一起,以获得独特的外观。 对图像进行样式化,使其看起来像是铅笔画、水墨草图、海报,等等。 使用简单的工具去除污点和红眼或者对牙齿进行美白,使您的自拍照看起来很漂亮。 使用“局部彩色”专注于某一颜色,或使用“焦点模糊”添加效果。 从一系列特效包中进行选择,为图像添加所需的外观和感觉。 利用叠加调整照片感受效果 – 增强色调、降低色调或增加梦幻般的提亮。 使用字幕为照片设置遮罩效果,或者用多种字体的文本叠加图像。 使用右侧边框完成编辑过程 – 选取适合您的样式。 利用我们不断增长的其他特效、叠加和边框包目录,保持新鲜感。 使用“收藏夹”按钮跟踪您收藏的特效和叠加。 在编辑后快速、灵活地调整图像大小。 通过社交媒体或电子邮件,直接与朋友分享您的照片。 123456789更新日志:v3.0.3- Better Android 6.0 support: ripple, doze & runtime permission check- Bug fixesv3.0.2- Improved the performance of the double exposure and eraser tools.- Fixed a crash with collage when re-selecting images.- We also squashed a few bugs in this release. 来源:http://pixlr.comGoogle Play:https://play.google.com/store/apps/details?id=com.pixlr.express 修改说明: 破解NDK动态JNI反射签名校验。 解锁专业版,去除广告。 禁用mixpanel隐私统计。 精简语言包,剔除无用设置项。 zipalign对齐优化、apk包体积优化。 修改人员:风澈vio(转载必须注明出处) 下载地址:百度网盘 密码:1024 注意: 使用者由此程序所造成的损失修改者不承担任何责任。 最终版权归原作者所有。 请在法律允许的范围内合理使用本程序。","tags":[{"name":"App","slug":"App","permalink":"http://inplus.top/tags/App/"}]},{"title":"克隆相机Clone Camera v2.2/v2.3精简破解版","date":"2016-12-15T22:29:20.000Z","path":"archives/clonecamera/","text":"Clone Camera – 一款方便快捷克隆物体制作炫酷照片的应用。 Clone Camera是一款趣味照相应用,通过这款应用,我们可以将照片中的人或物体复制,在同个场景中创造最多四个相同的影像。而使用者不需要懂得复杂的P图技巧,只需要简单的几步,就可以制作出富有创意的摄影作品。 功能特点: 无比震撼的克隆照片 增强型自拍功能 众多滤镜可供选择 帮助你首次尝试的入门指南 支持高质量照片 1234567更新日志:Version 2.2:· Added Special tutorials· Support Chinese· Support more devices.· Minor bug fixes. 来源:http://www.peta-vision.comGoogle Play:https://play.google.com/store/apps/details?id=com.petavision.clonecameraplaystore 修改说明: 精简多余代码文件和资源文件 破解完整功能,激活全部图文教程 去除广告,剔除无用信息 去除MiGameCenterSDKService 补全汉化信息 修复部分闪退 优化算法,精简体积 zipalign对齐优化 修改人员:风澈vio(转载必须注明出处) 下载地址:百度网盘 密码:1024 注意: 使用者由此程序所造成的损失修改者不承担任何责任。 最终版权归原作者所有。 请在法律允许的范围内合理使用本程序。","tags":[{"name":"App","slug":"App","permalink":"http://inplus.top/tags/App/"}]},{"title":"使用渐进式 JPEG 来提升用户体验","date":"2016-12-01T01:56:40.000Z","path":"archives/optimizejpeg/","text":"网络上那些色色的照片都是.jpg格式的(“色色”指的是色彩斑斓的意思 /手动抠鼻/)。不知诸位有没有注意到,这些.jpg格式的图片在呈现的时候,有两种方式,一种是自上而下扫描式的,还有一种就是先是全部的模糊图片,然后逐渐清晰(就像GIF格式的交错显示)。 JPEG文件有两种保存方式,分别是Baseline JPEG(基准式)和Progressive JPEG(渐进式)。两种格式有相同尺寸以及图像数据,它们的扩展名也是相同的,唯一的区别是二者显示的方式不同。Baseline JPEG 这种类型的JPEG文件存储方式是按从上到下的扫描方式,把每一行顺序的保存在JPEG文件中。打开这个文件显示它的内容时,数据将按照存储时的顺序从上到下一行一行的被显示出来,直到所有的数据都被读完,就完成了整张图片的显示。如果文件较大或者网络下载速度较慢,那么就会看到图片被一行行加载的效果,这种格式的JPEG没有什么优点,因此,一般都推荐使用Progressive JPEG。 Progressive JPEG 和Baseline JPEG一遍扫描不同,Progressive JPEG文件包含多次扫描,这些扫描顺寻的存储在JPEG文件中。打开文件过程中,会先显示整个图片的模糊轮廓,随着扫描次数的增加,图片变得越来越清晰。这种格式的主要优点是在网络较慢的情况下,可以看到图片的轮廓知道正在加载的图片大概是什么。在一些网站打开较大图片时,你就会注意到这种技术。 #####让我们来对比一下: 渐进式图片带来的好处是可以让用户在没有下载完图片就可以看到最终图像的大致轮廓,一定程度上可以提升用户体验。(瀑布流的网站建议还是使用基准式的) 另外渐进式的图片的大小并不会和基本的图片大小相差很多,有时候可能会比基本图片更小。渐进式的图片的缺点就是吃用户的CPU和内存,不过对于现在的电脑来说这点图片的计算并不算什么。 下载呈现速度 一个名叫Ann Robson的人,最近对各个浏览器下渐进式图片呈现做了测试。下图为FireFox浏览器下呈现速度的对比图: 当大图轮廓加载OK的时候,小图最后一个乳猪还没有出世面;而基准式乳猪图还没有开始加载!显然,罗伯森是想告诉我们,渐进式JPEG下载更快。 下表为其在各个浏览器下测试的结果: 结论很简单,Chrome + Firefox + IE9浏览器下,渐进式图片加载更快,而且是快很多,至于其他浏览器,与基准式图片的加载一致,至少不会拖后腿。 Scott Gilbertson对渐进式图片有其他的补充:1.你永不知道基准式图片内容,除非他完全加载出来。2.渐进式图片一开始大小框架就定好,不会像基准式图片一样,由于尺寸未设定而造成回流——提高的渲染性能。3.渐进式图片也有不足,就是吃CPU吃内存。ps: png图片也是可以渐进式呈现的 内容就是这些,权衡使用在你手。一般而言,大尺寸图片建议使用渐进式JPEG。 #####那么怎么将图片保存为或者转化为Progressive JPEG呢?方法如下: 1、PhotoShop在photoshop中有“存储为web所用格式”,打开后选择“连续”就是渐进式JPEG。 2、Linux检测是否为progressive jpeg: identify -verbose filename.jpg | grep Interlace(如果输出 None 说明不是progressive jpeg;如果输出 Plane 说明是 progressive jpeg。)将basic jpeg转换成progressive jpeg:> convert infile.jpg -interlace Plane outfile.jpg 3、PHP使用imageinterlace和imagejpeg函数我们可以轻松解决转换问题。123456<?php $im = imagecreatefromjpeg('pic.jpg'); imageinterlace($im, 1); imagejpeg($im, './php_interlaced.jpg', 100); imagedestroy($im);?> 4、Python12345678910import PILfrom exceptions import IOErrorimg = PIL.Image.open(\"c:\\\\users\\\\biaodianfu\\\\pictures\\\\in.jpg\")destination = \"c:\\\\users\\\\biaodianfu\\\\pictures\\\\test.jpeg\"try: img.save(destination, \"JPEG\", quality=80, optimize=True, progressive=True)except IOError: PIL.ImageFile.MAXBLOCK = img.size[0] * img.size[1] img.save(destination, \"JPEG\", quality=80, optimize=True, progressive=True) 5、jpegtranjpegtran -copy none -progressive <inputfile> <outputfile> 6、C#12345678using (Image source = Image.FromFile(@"D:\\temp\\test2.jpg")) { ImageCodecInfo codec = ImageCodecInfo.GetImageEncoders().First(c => c.MimeType == "image/jpeg"); EncoderParameters parameters = new EncoderParameters(3); parameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L); parameters.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.ScanMethod, (int)EncoderValue.ScanMethodInterlaced); parameters.Param[2] = new EncoderParameter(System.Drawing.Imaging.Encoder.RenderMethod, (int)EncoderValue.RenderProgressive); source.Save(@"D:\\temp\\saved.jpg", codec, parameters);} 特别感谢@标点符 @张鑫旭","tags":[{"name":"软件开发","slug":"软件开发","permalink":"http://inplus.top/tags/软件开发/"}]},{"title":"后期对焦AfterFocus Pro v2.1.0独家汉化破解版","date":"2016-11-15T01:29:20.000Z","path":"archives/afterfocus/","text":"AfterFocus Pro – 一款可将照片后期调教出背景虚化、焦点景物突出的单反效果,还可进行光圈控制、使用滤镜等一系列操作的Android应用。 通过AfterFocus Pro,你可以通过简单地选择对焦区域创建DSLR风格的背景虚化的照片。此外,多种滤镜效果为您创造最自然,逼真的照片。更精确地选择一个对焦领域,可以实现更加自然和专业的照片。只需标记你想要对焦的地方,AfterFocus Pro将自动精确识别对焦区域中复杂形状的物体。这种自动功能可以让你在智能手机的小屏幕上更快捷方便的修片。另外,AfterFocus Pro的背景虚化效果使相片背景的边缘和焦点区域之间呈现更逼真的外观。 通过滤镜效果,您将享受拍摄和照片编辑,并在社交平台轻松分享。功能特点: 智能选择对焦区域在对焦区域和背景区域内简单地画一些线条,然后AfterFocus Pro会自动识别对焦区域。也可以手动涂抹选择对焦区域。 背景虚化效果你可以创建各种风格的光圈,就像数码单反相机最现实的虚化效果。需要注意的是,对于某些运动的物体,也可使用运动模糊和放大的虚化效果。 滤镜效果AfterFocus Pro提供从基本效果到像专业的大师拍摄的效果。此外,您还可以突出使用背景虚化效果的背景聚光灯。 易于分享您可以通过电子邮件和社交平台方便快捷分享。 1234567891011121314更新日志:Version 2.1.0*1. Crash fix*2. Adds brush-size tool in manual focusingVersion 2.0.3*1. Can save image in original size*2. Adds Zoom blur*3. Keeps image quality after saving for the large image*4. Focus selection tool Improvements*5. Overall UI improvementsVersion 1.7.2*1. Fix slow responsiveness for small screen device*2. Fix crash when app brings to foreground from background 来源:http://appm1.com/afterfocusGoogle Play:https://play.google.com/store/apps/details?id=com.motionone.afterfocus_pro 修改说明: 破解Google授权验证、NDK签名逻辑验证 精简语言 汉化为简体中文 arm架构精简 Zipalign对齐优化 修改人员:风澈vio(转载必须注明出处) ※城通网盘(进入下载列表-最下方普通低速单线程下载)※ 注意: 使用者由此程序所造成的损失修改者不承担任何责任。 最终版权归原作者所有。 破解版仅供学习研究使用,严禁用于商业用途,请在下载后24小时内删除。 请在法律允许的范围内合理使用本程序。","tags":[{"name":"App","slug":"App","permalink":"http://inplus.top/tags/App/"}]},{"title":"Mifare Classic Tool(MCT)2.1.0汉化特别版","date":"2016-10-19T17:29:20.000Z","path":"archives/mifareclassictool/","text":"Mifare Classic Tool (MCT) – 一款用来读取、写入、分析Mifare Classic RFID卡片的Android NFC应用。 功能特点: 读取Mifare Classic卡片 编辑并保存卡片的数据 写入Mifare Classic卡片 复制Mifare Classic卡片(从一张卡片写入数据文件到一张新卡;不包括第一区块) 字典暴力破解 格式化标签至出厂状态 写特殊的Mifare Classic卡片制造商块 创建、编辑、保存和共享密钥文件(字典) 编码解码Mifare Classic价值块 编码解码Mifare Classic的访问条件 比较转储(比对工具) 显示卡片属性信息 高亮显示卡片十六进制数据 显示卡片数据为7-Bit US-ASCII码 以表来显示Mifare Classic访问条件 显示Mifare Classic值块为整数 应用内(离线)帮助和其它信息 它是个开源项目(GPLv3) 12345678910111213141516更新日志:Version 2.1.0: * Set custom sector count (read/write MIFARE Classic 2k). * Check BCC before writing. * Added BCC calculator tool. * Added more well known keys to the extended key file. (Remove the old and restart MCT to get the new key file.) * Added Chinese translation. * Changed \"Mifare\" to \"MIFARE\" to comply with NXP's registered trademark. * Added multiple devices to the list of incompatible devices. * Some minor bug fixes.Version 2.0.7: * Bugfix: Request permissions on Android 6.x devices to read/write the external storage. Thanks to Mislav Jurinić. 源码:https://github.com/ikarus23/MifareClassicTool来源:http://www.proxmark.org/forum/viewtopic.php?id=1535Google Play:https://play.google.com/store/apps/details?id=de.syss.MifareClassicTool 修改说明: 修正官方汉化 精简语言 独家汉化帮助文档 zipalign对齐优化 修改人员:风澈vio(转载必须注明出处) 下载地址:百度网盘 密码:1024 注意: 使用者由此程序所造成的损失修改者不承担任何责任。 最终版权归原作者所有。 请在法律允许的范围内合理使用本程序。","tags":[{"name":"App","slug":"App","permalink":"http://inplus.top/tags/App/"}]},{"title":"多说评论下篇之个性化评论框","date":"2016-10-07T15:27:17.000Z","path":"archives/duoshuothree/","text":"前言 上面两篇我们详细介绍了多说评论自定义CSS头像和显示UA信息和博主。但是仍然感觉评论框十分不协调,并且有些杂乱,接下来我们就要谈论我们的多说评论框下篇之个性化评论框,话不多说,切入正题~ 多说自定义CSS 扩展阅读多说docs:http://dev.duoshuo.com/docs/4ff1cfd0397309552c000017 1、 评论框左右边距如果你的评论框左右边距过小(评论框太宽),输入下列代码调整宽度,直到页面上评论框宽度显示合适:方式一:1#ds-thread {padding:24px;} 方式二:1#ds-thread {margin:24px;} 如果你的评论框太窄,可能是宽度被设定了不合适的值,输入下列代码让宽度自动拉伸:1#ds-thread {width:auto;} 2、评论框背景色多说评论会采用主题的背景色作为整体评论框的背景,这样可能导致评论本身不是很显眼。你可以输入下列代码来更改整体评论框的背景颜色:方式一:1#ds-thread {background: #ffffff;} 方式二:1#ds-thread #ds-reset .ds-textarea-wrapper { background: rgba(255, 255, 255, .5);} 这个评论背景的边角默认是直角,如果想改成圆角,请输入下列代码(仅在firefox,chrome及高版本ie浏览器下有效,ie6,7,8将仍然为直角显示):1#ds-thread{ border-radius: 5px;} 注意:其中的#ffffff可以被替换为你希望的颜色,以便于评论文字相适应。 3、高亮字体的颜色高亮字体包括“n条评论”,“n条微博”,评论者名字的颜色,想修改它的显示颜色(在大多数情况下默认是红色),输入下列代码:1#ds-thread #ds-reset .ds-highlight{color: #ffffff !important;} 4、定义评论框内字体和颜色1#ds-thread #ds-reset .ds-textarea-wrapper textarea, #ds-thread #ds-reset .ds-textarea-wrapper .ds-hidden-text {font-family: ‘微软雅黑’ ‘Microsoft Yahei’!important;font-size:12px;letter-spacing:1px;} 这个好像是定义评论框内输入的文字字体的,嗯,好像是。 想修改评论正文的字体颜色,请输入下列代码:1#ds-thread #ds-reset .ds-comment-body p {color: #ffffff;} 当您在修改一部分上面未示例的标签样式时,遇到无效的情况,请尝试增加:!important 5、评论框背景图片url换成你自己想要的图片地址就行了,最好使用绝对路径。方式一:123.ds-textarea-wrapper.ds-rounded-top{background: #ffffff url(你想设置的图片地址) no-repeat right bottom !important;} 方式二:123#ds-thread #ds-reset .ds-textarea-wrapper textarea {background:url(你的图片地址) center no-repeat;} 方式三:123#ds-thread #ds-reset .ds-textarea-wrapper textarea {background: url(\"你的图片地址\") bottom right no-repeat;} 6、将评论框底部的分享到微博QQ空间什么的隐藏起来1.ds-sync{display:none !important;} 7、隐藏评论框底部渐变背景1#ds-reset .ds-gradient-bg{background:none !important;} 话说渐变色什么的虽然立体感较强但是和主题整体风格不融洽,隐藏之,这样底部就是透明的了。 8、定义发布按钮字体,以及渐变色背景1#ds-thread #ds-reset .ds-post-button{font-family: ‘微软雅黑’‘Microsoft Yahei’!important;font-weight: bold;font-size:12px;background:none !important;color:#49976b !important;} 9、隐藏评论右上方 最热 最新排序按钮1#ds-thread #ds-reset .ds-sort {display:none;} 10、隐藏评论左上方 评论总数背景色及边框1#ds-thread #ds-reset li.ds-tab a.ds-current{background:none;border:none;} 11、隐藏底部多说版权很多朋友在找这个代码。不过不建议用。毕竟显示版权信息还是比较好。方式一:1#ds-thread #ds-reset .ds-powered-by{display:none;} 方式二:1#ds-thread .ds-powered-by {display: none;} 12、定义各种文字高亮颜色,以及浮动窗口的高亮颜色,配合模板颜色把以下色值统一设置即可。123456789101112/*定义高亮字体颜色*/#ds-reset .ds-highlight{color:#49976b !important;}/*定义评论框内其他高亮颜色*/#ds-thread #ds-reset #ds-bubble a{color: #49976b !important;}/*定义评论框内其他高亮颜色*/#ds-thread #ds-reset #ds-bubble {color: #49976b !important;}/*定义评论框内其他高亮颜色*/#ds-reset #ds-ctx .ds-ctx-entry .ds-ctx-head a{color: #49976b !important;}/*定义评论框内其他高亮颜色*/#ds-thread #ds-reset a.ds-comment-context:hover{color: #49976b !important;}/*定义评论框内其他高亮颜色*/#ds-thread #ds-reset a.ds-comment-context{color: #49976b !important;} 13、喜欢按钮样式:透明度,背景,边框等样式调整。12345678910111213.ds-meta { opacity: .5; }.ds-meta:hover { opacity: 1; }#ds-thread #ds-reset a.ds-like-thread-button { background-image: none; background-color: #fee2d3; border: none; text-shadow: none; font-family: inherit; } 14、社交账号登陆透明度123456#ds-thread #ds-reset .ds-login-buttons { opacity: .5;}#ds-thread #ds-reset .ds-login-buttons:hover { opacity: 1; } 15、评论、文本框字体:默认字体偏小,稍作调整。12345#ds-thread #ds-reset .ds-comment-body p, #ds-thread #ds-reset .ds-textarea-wrapper textarea { font-size: 1.15em; color: #717171; font-family: inherit; } 16、用户名等超链接颜色123#ds-thread #ds-reset .ds-highlight { color: #ef7c6c !important;} 17、未登录用户名字颜色:颜色与其他登陆用户保持一致123#ds-thread #ds-reset .ds-user-name { color: #ef7c6c !important;} 18、工具栏背景123#ds-reset .ds-gradient-bg { background: rgba(255, 255, 255, .5);} 19、“发布”按钮背景:去掉背景图,修改底色,去掉文字阴影。12345#ds-thread #ds-reset .ds-post-button { background-image: none; background: rgba(136, 172, 219, .2); text-shadow: none;} 20、评论列表背景123456#ds-thread #ds-reset li.ds-post { background: rgba(255, 255, 255, .2);}#ds-thread #ds-reset li.ds-post:hover { background-color: rgba(255, 255, 255, .6) !important;} 21、评论数标签123#ds-thread #ds-reset li.ds-tab a.ds-current { background: rgba(255, 255, 255, .2);} 都是一些现成的CSS代码,直接复制就可以用了。当然里面的颜色或者是其他属性什么的你们自己修改就可以了。照样可以实现你想要的效果。 手动获取css标签信息当然,这些个性化信息并不能全覆盖我们自己想要达到的效果,那么在具体使用中,我们怎样知道多说的某一个按钮,某一条线,使用的是哪一个css标签呢?(像#ds-thread #ds-reset .ds-highlight),下面提供一个在google chrome下查看的简单办法: 在页面元素上方点击【鼠标右键】,选择【审查元素】 将鼠标悬浮在相应元素的代码上方,页面中也会显示出选中效果。点击代码之后,右侧子窗口会显示相应标签。 没错,如果你想要控制喜欢按钮的颜色,只需在多说的自定义css里,添加并调整color的颜色值即可 123#ds-thread #ds-reset a.ds-like-thread-button span { color: #F00;} 特别感谢:@沈超飞 @MOxFIVE","tags":[{"name":"Hexo","slug":"Hexo","permalink":"http://inplus.top/tags/Hexo/"}]},{"title":"多说评论中篇之显示UA信息和博主","date":"2016-10-05T15:27:17.000Z","path":"archives/duoshuotwo/","text":"前言 上篇我们详细介绍了多说评论自定义CSS头像。为了彰显极(zhuang)客(bi)范儿,单单炫酷的头像动画可是不够的。接下来我们就要谈论我们的多说评论框中篇之显示UA(User Agent)信息和博主,话不多说,切入正题~ 多说添加UA(User Agent)等个性化信息本地化embed.js1、下载embed.js多说官方 - http://static.duoshuo.com/embed.js 2、上传embed.js我的做法上传到GitHub,其它类似七牛或者云主机的方法都可以http://viosay.github.io/assets/js/embed.js 3、修改多说调用地址在Hexo的主题中的duoshuo.ejs文件中修改调用地址,其它平台以此类推,我自己的做法1ds.src = '/assets/js/embed.js'; 修改embed.js1、获取多说ID方法一:在文章下方登录后评论点击头像可获取多说ID方法二:访问多说后台,http://duoshuo.com/settings/ ,点击你的用户名,地址栏中会出现如如下的ID地址http://duoshuo.com/profile/6223597840313090818/ 2、添加个性化信息到embed.js文件在embed.js的最上面添加以下代码:(注意修改e.user_id多说ID,可以自定义ssk前端显示昵称) 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136//移动客户端判断开始function checkMobile() { var isiPad = navigator.userAgent.match(/iPad/i) != null; if (isiPad) { return false; } var isMobile = navigator.userAgent.match(/iphone|android|phone|mobile|wap|netfront|x11|java|opera mobi|opera mini|ucweb|windows ce|symbian|symbianos|series|webos|sony|blackberry|dopod|nokia|samsung|palmsource|xda|pieplus|meizu|midp|cldc|motorola|foma|docomo|up.browser|up.link|blazer|helio|hosin|huawei|novarra|coolpad|webos|techfaith|palmsource|alcatel|amoi|ktouch|nexian|ericsson|philips|sagem|wellcom|bunjalloo|maui|smartphone|iemobile|spice|bird|zte-|longcos|pantech|gionee|portalmmm|jig browser|hiptop|benq|haier|^lct|320x320|240x320|176x220/i) != null; if (isMobile) { return true; } return false;}//移动客户端判断结束//管理员判断开始function sskadmin(e) { var ssk = ''; if (e.user_id == 6223597840313090818) { if (checkMobile()) { ssk = '<span class=\"ua\"><span class=\"sskadmin\">☆博主☆</span></span><br><br>'; } else { ssk = '<span class=\"ua\"><span class=\"sskadmin\">☆博主☆</span></span>'; } } else { if (checkMobile()) { ssk = '<br><br>'; } } return ssk;}//管理员判断结束//显UA开始function ua(e) { var r = new Array; var outputer = ''; if (r = e.match(/FireFox\\/([^\\s]+)/ig)) { var r1 = r[0].split(\"/\"); outputer = '<span class=\"ua_firefox\"><i class=\"fa fa-globe\"></i> Mozilla FireFox' + ' ' + r1[1] } else if (r = e.match(/Maxthon([\\d]*)\\/([^\\s]+)/ig)) { var r1 = r[0].split(\"/\"); outputer = '<span class=\"ua_maxthon\"><i class=\"fa fa-globe\"></i> Maxthon' + ' ' + r1[1] } else if (r = e.match(/BIDUBrowser([\\d]*)\\/([^\\s]+)/ig)) { var r1 = r[0].split(\"/\"); outputer = '<span class=\"ua_ucweb\"><i class=\"fa fa-globe\"></i> 百度浏览器' + ' ' + r1[1] } else if (r = e.match(/UBrowser([\\d]*)\\/([^\\s]+)/ig)) { var r1 = r[0].split(\"/\"); outputer = '<span class=\"ua_ucweb\"><i class=\"fa fa-globe\"></i> UCBrowser' + ' ' + r1[1] } else if (r = e.match(/UCBrowser([\\d]*)\\/([^\\s]+)/ig)) { var r1 = r[0].split(\"/\"); outputer = '<span class=\"ua_ucweb\"><i class=\"fa fa-globe\"></i> UCBrowser' + ' ' + r1[1] } else if (r = e.match(/MetaSr/ig)) { outputer = '<span class=\"ua_sogou\"><i class=\"fa fa-globe\"></i> 搜狗浏览器' } else if (r = e.match(/2345Explorer/ig)) { outputer = '<span class=\"ua_2345explorer\"><i class=\"fa fa-globe\"></i> 2345王牌浏览器' } else if (r = e.match(/2345chrome/ig)) { outputer = '<span class=\"ua_2345chrome\"><i class=\"fa fa-globe\"></i> 2345加速浏览器' } else if (r = e.match(/LBBROWSER/ig)) { outputer = '<span class=\"ua_lbbrowser\"><i class=\"fa fa-globe\"></i> 猎豹安全浏览器' } else if (r = e.match(/MicroMessenger\\/([^\\s]+)/ig)) { var r1 = r[0].split(\"/\"); outputer = '<span class=\"ua_qq\"><i class=\"fa fa-weixin\"></i> 微信' + ' ' + r1[1] /*.split('/')[0]*/ } else if (r = e.match(/QQBrowser\\/([^\\s]+)/ig)) { var r1 = r[0].split(\"/\"); outputer = '<span class=\"ua_qq\"><i class=\"fa fa-globe\"></i> QQ浏览器' + ' ' + r1[1] /*.split('/')[0]*/ } else if (r = e.match(/QQ\\/([^\\s]+)/ig)) { var r1 = r[0].split(\"/\"); outputer = '<span class=\"ua_qq\"><i class=\"fa fa-globe\"></i> QQ浏览器' + ' ' + r1[1] /*.split('/')[0]*/ } else if (r = e.match(/MiuiBrowser\\/([^\\s]+)/ig)) { var r1 = r[0].split(\"/\"); outputer = '<span class=\"ua_mi\"><i class=\"fa fa-globe\"></i> Miui浏览器' + ' ' + r1[1] /*.split('/')[0]*/ } else if (r = e.match(/Chrome([\\d]*)\\/([^\\s]+)/ig)) { var r1 = r[0].split(\"/\"); outputer = '<span class=\"ua_chrome\"><i class=\"fa fa-globe\"></i> Chrome' + ' ' + r1[1] /*.split('.')[0]*/ } else if (r = e.match(/safari\\/([^\\s]+)/ig)) { var r1 = r[0].split(\"/\"); outputer = '<span class=\"ua_apple\"><i class=\"fa fa-globe\"></i> Apple Safari' + ' ' + r1[1] } else if (r = e.match(/Opera[\\s|\\/]([^\\s]+)/ig)) { var r1 = r[0].split(\"/\"); outputer = '<span class=\"ua_opera\"><i class=\"fa fa-globe\"></i> Opera' + ' ' + r1[1] } else if (r = e.match(/Trident\\/7.0/gi)) { outputer = '<span class=\"ua_ie\"><i class=\"fa fa-globe\"></i> Internet Explorer 11' } else if (r = e.match(/MSIE\\s([^\\s|;]+)/gi)) { outputer = '<span class=\"ua_ie\"><i class=\"fa fa-globe\"></i> Internet Explorer' + ' ' + r[0] /*.replace('MSIE', '').split('.')[0]*/ } else { outputer = '<span class=\"ua_other\"><i class=\"fa fa-globe\"></i> 其它浏览器' } if (checkMobile()) { Mobile = '<br><br>'; } else { Mobile = ''; } return outputer + \"</span>\" + Mobile;}function os(e) { var os = ''; if (e.match(/win/ig)) { if (e.match(/nt 5.1/ig)) { os = '<span class=\"os_xp\"><i class=\"fa fa-desktop\"></i> Windows XP' } else if (e.match(/nt 6.1/ig)) { os = '<span class=\"os_7\"><i class=\"fa fa-desktop\"></i> Windows 7' } else if (e.match(/nt 6.2/ig)) { os = '<span class=\"os_8\"><i class=\"fa fa-desktop\"></i> Windows 8' } else if (e.match(/nt 6.3/ig)) { os = '<span class=\"os_8_1\"><i class=\"fa fa-desktop\"></i> Windows 8.1' } else if (e.match(/nt 10.0/ig)) { os = '<span class=\"os_8_1\"><i class=\"fa fa-desktop\"></i> Windows 10' } else if (e.match(/nt 6.0/ig)) { os = '<span class=\"os_vista\"><i class=\"fa fa-desktop\"></i> Windows Vista' } else if (e.match(/nt 5/ig)) { os = '<span class=\"os_2000\"><i class=\"fa fa-desktop\"></i> Windows 2000' } else { os = '<span class=\"os_windows\"><i class=\"fa fa-desktop\"></i> Windows' } } else if (e.match(/android/ig)) { os = '<span class=\"os_android\"><i class=\"fa fa-android\"></i> Android' } else if (e.match(/ubuntu/ig)) { os = '<span class=\"os_ubuntu\"><i class=\"fa fa-desktop\"></i> Ubuntu' } else if (e.match(/linux/ig)) { os = '<span class=\"os_linux\"><i class=\"fa fa-linux\"></i> Linux' } else if (e.match(/mac/ig)) { os = '<span class=\"os_mac\"><i class=\"fa fa-desktop\"></i> Mac OS X' } else if (e.match(/unix/ig)) { os = '<span class=\"os_unix\"><i class=\"fa fa-desktop\"></i> Unix' } else if (e.match(/symbian/ig)) { os = '<span class=\"os_nokia\"><i class=\"fa fa-mobile\"></i> Nokia SymbianOS' } else { os = '<span class=\"os_other\"><i class=\"fa fa-desktop\"></i> 其它操作系统' } return os + \"</span>\";}//显UA结束 3、增加调用添加完以上代码后,在编辑器中搜索:1data-qqt-account=\"'+(r.qqt_account||\"\")+'\">'+u(r.name)+\"</span>\"), 在后面添加:1t+=\"<span class=\\\"ua\\\">\" + sskadmin(s.author) + \"</span><span class=\\\"ua\\\">\" + ua(s.agent) +\"</span><span class=\\\"ua\\\">\"+ os(s.agent) + \"</span>\", (如果搜索不到的话就减小点搜索范围,如:data-qqt-account="'+) 多说后台自定义CSS请参考上篇方法加入多说自定义CSS123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220/*多说UA开始*/ span.this_ua { background-color: #ccc!important; border-radius: 4px; padding: 0 5px!important; margin: 0 1px!important; border: 1px solid #BBB!important; color: #fff; /*text-transform: Capitalize!important; float: right!important; line-height: 18px!important;*/ }.this_ua.platform.Windows { background-color: #39b3d7!important; border-color: #46b8da!important;}.this_ua.platform.Linux { background-color: #3A3A3A!important; border-color: #1F1F1F!important;}.this_ua.platform.Ubuntu { background-color: #DD4814!important; border-color: #DD4814!important;}.this_ua.platform.Mac { background-color: #666666!important; border-color: #666666!important;}.this_ua.platform.Android { background-color: #98C13D!important; border-color: #98C13D!important;}.this_ua.platform.iOS { background-color: #666666!important; border-color: #666666!important;}.this_ua.browser.Chrome { background-color: #EE6252!important; border-color: #EE6252!important;}.this_ua.browser.Chromium { background-color: #EE6252!important; border-color: #EE6252!important;}.this_ua.browser.Firefox { background-color: #f0ad4e!important; border-color: #eea236!important;}.this_ua.browser.IE { background-color: #428bca!important; border-color: #357ebd!important;}.this_ua.browser.Edge { background-color: #428bca!important; border-color: #357ebd!important;}.this_ua.browser.Opera { background-color: #d9534f!important; border-color: #d43f3a!important;}.this_ua.browser.Maxthon { background-color: #7373B9!important; border-color: #7373B9!important;}.this_ua.browser.Safari { background-color: #666666!important; border-color: #666666!important;}.this_ua.sskadmin { background-color: #00a67c!important; border-color: #00a67c!important;}/*UA End*/ /*Head Start*/ #ds-thread #ds-reset ul.ds-comments-tabs li.ds-tab a.ds-current { border: 0px; color: #6D6D6B; text-shadow: none; background: #F3F3F3;}#ds-thread #ds-reset .ds-highlight { font-family: Microsoft YaHei, \"Helvetica Neue\", Helvetica, Arial, Sans-serif; ;font-size: 100%; color: #6D6D6B !important;}#ds-thread #ds-reset ul.ds-comments-tabs li.ds-tab a.ds-current:hover { color: #696a52; background: #F2F2F2;}#ds-thread #ds-reset a.ds-highlight:hover { color: #696a52 !important;}#ds-thread { padding-left: 15px;}#ds-thread #ds-reset li.ds-post,#ds-thread #ds-reset #ds-hot-posts { overflow: visible;}#ds-thread #ds-reset .ds-post-self { padding: 10px 0 10px 10px;}#ds-thread #ds-reset li.ds-post,#ds-thread #ds-reset .ds-post-self { border: 0 !important;}#ds-reset .ds-avatar, #ds-thread #ds-reset ul.ds-children .ds-avatar { top: 15px; left: -20px; padding: 5px; width: 36px; height: 36px; box-shadow: -1px 0 1px rgba(0,0,0,.15) inset; border-radius: 46px; background: #FAFAFA;}#ds-thread .ds-avatar a { display: inline-block; padding: 1px; width: 32px; height: 32px; border: 1px solid #b9baa6; border-radius: 50%; background-color: #fff !important;}#ds-thread .ds-avatar a:hover { }#ds-thread .ds-avatar > img { margin: 2px 0 0 2px;}#ds-thread #ds-reset .ds-replybox { box-shadow: none;}#ds-thread #ds-reset ul.ds-children .ds-replybox.ds-inline-replybox a.ds-avatar,#ds-reset .ds-replybox.ds-inline-replybox a.ds-avatar { left: 0; top: 0; padding: 0; width: 32px !important; height: 32px !important; background: none; box-shadow: none;}#ds-reset .ds-replybox.ds-inline-replybox a.ds-avatar img { width: 32px !important; height: 32px !important; border-radius: 50%;}#ds-reset .ds-replybox a.ds-avatar,#ds-reset .ds-replybox .ds-avatar img { padding: 0; width: 32px !important; height: 32px !important; border-radius: 5px;}#ds-reset .ds-avatar img { width: 32px !important; height: 32px !important; border-radius: 32px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.22); -webkit-transition: .8s all ease-in-out; -moz-transition: .4s all ease-in-out; -o-transition: .4s all ease-in-out; -ms-transition: .4s all ease-in-out; transition: .4s all ease-in-out;}.ds-post-self:hover .ds-avatar img { -webkit-transform: rotateX(360deg); -moz-transform: rotate(360deg); -o-transform: rotate(360deg); -ms-transform: rotate(360deg); transform: rotate(360deg);}#ds-thread #ds-reset .ds-comment-body { -webkit-transition-delay: initial; -webkit-transition-duration: 0.4s; -webkit-transition-property: all; -webkit-transition-timing-function: initial; background: #F7F7F7; padding: 15px 15px 15px 47px; border-radius: 5px; box-shadow: #B8B9B9 0 1px 3px; border: white 1px solid;}#ds-thread #ds-reset ul.ds-children .ds-comment-body { padding-left: 15px;}#ds-thread #ds-reset .ds-comment-body p { color: #787968;}#ds-thread #ds-reset .ds-comments { border-bottom: 0px;}#ds-thread #ds-reset .ds-powered-by { display: none;}#ds-thread #ds-reset .ds-comments a.ds-user-name { font-weight: normal; color: #3D3D3D !important;}#ds-thread #ds-reset .ds-comments a.ds-user-name:hover { color: #D32 !important;}#ds-thread #ds-reset #ds-bubble { display: none !important;}#ds-thread #ds-reset #ds-hot-posts { border: 0;}#ds-reset #ds-hot-posts .ds-gradient-bg { background: none;}#ds-thread #ds-reset .ds-comment-body:hover { background-color: #F1F1F1; -webkit-transition-delay: initial; -webkit-transition-duration: 0.4s; -webkit-transition-property: all; -webkit-transition-timing-function: initial;}/*多说UA结束*/ 至此,在多说评论框中添加ua显示与博主标示步骤就全部做完了 更多评论框添加的UA前加上小图标http://ssk.91txh.com/209评论框添加 站长回复 标记http://ssk.91txh.com/207多说不本地化embed.js评论显示UAhttp://easun.org/blog/archives/make_duoshuo_show_ua.html多说UA插件http://gerald.top/code/duoshuo-uaua-parser-jshttps://github.com/faisalman/ua-parser-js 特别感谢:@wsgzao @萝莉社 @我的那些事-搜索客","tags":[{"name":"Hexo","slug":"Hexo","permalink":"http://inplus.top/tags/Hexo/"}]},{"title":"多说评论上篇之自定义CSS头像","date":"2016-10-01T15:27:17.000Z","path":"archives/duoshuoone/","text":"前言 多说是一款社会化评论系统,它改变了网站与用户之间,用户与用户之间的互动方式。当然Disqus在大家心目中可能更加具有影响力,而多说“接地气的本地化评论托管服务”则让人眼前一亮。 在WordPress和GitHub+Hexo搭建的静态Blog我们常常使用多说、畅言等评论系统,但是官方的配色和布局往往和我们的网站不太融合,所以我们要对其进行适当的美化。 接下来我们就要谈论我们的多说评论框上篇之自定义CSS头像,话不多说,切入正题~ 多说自定义CSS以下是整理出来的十种头像特效,各种效果都以GIF动态图呈现,可以很直观的看到效果。毕竟是图片,实际效果当然会更好的多。代码在最下面 效果一 效果二 效果三 效果四 效果五 效果六 效果七 效果八 效果九 效果十 效果十一 附录:CSS代码 代码在下面(请用非IE浏览器看),设置步骤超级简单,登录多说后台->设置->基本设置->自定义CSS,将代码粘贴自定义CSS 里,刷新即可看到效果。ps:代码都是共通的,不局限于多说,应用在别的效果上也是可以的。 头像效果一123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142#ds-reset .ds-avatar img,#ds-reset .ds-avatar img:hover{ -webkit-animation-fill-mode: both; -moz-animation-fill-mode: both; -ms-animation-fill-mode: both; -o-animation-fill-mode: both; animation-fill-mode: both; -webkit-animation-duration: 0s; -moz-animation-duration: 0s; -ms-animation-duration: 0s; -o-animation-duration: 0s; animation-duration: 0s; -webkit-animation-duration: 1s; -moz-animation-duration: 1s; -ms-animation-duration: 1s; -o-animation-duration: 1s; animation-duration: 1s; } @-webkit-keyframes rotateInDownLeft { 0% { -webkit-transform-origin: left bottom; -webkit-transform: rotate(-90deg); opacity: 0; } 100% { -webkit-transform-origin: left bottom; -webkit-transform: rotate(0); opacity: 1; } } @-moz-keyframes rotateInDownLeft { 0% { -moz-transform-origin: left bottom; -moz-transform: rotate(-90deg); opacity: 0; } 100% { -moz-transform-origin: left bottom; -moz-transform: rotate(0); opacity: 1; } } @-o-keyframes rotateInDownLeft { 0% { -o-transform-origin: left bottom; -o-transform: rotate(-90deg); opacity: 0; } 100% { -o-transform-origin: left bottom; -o-transform: rotate(0); opacity: 1; } } @keyframes rotateInDownLeft { 0% { transform-origin: left bottom; transform: rotate(-90deg); opacity: 0; } 100% { transform-origin: left bottom; transform: rotate(0); opacity: 1; } } #ds-reset .ds-avatar img{ -webkit-animation-name: rotateInDownLeft; -moz-animation-name: rotateInDownLeft; -o-animation-name: rotateInDownLeft; animation-name: rotateInDownLeft; } #ds-reset .ds-avatar img:hover{ -webkit-animation-name: rotateOutDownLeft; -moz-animation-name: rotateOutDownLeft; -o-animation-name: rotateOutDownLeft; animation-name: rotateOutDownLeft; } @-webkit-keyframes rotateOutDownLeft { 0% { -webkit-transform-origin: left bottom; -webkit-transform: rotate(0); opacity: 1; } 100% { -webkit-transform-origin: left bottom; -webkit-transform: rotate(90deg); opacity: 0; } } @-moz-keyframes rotateOutDownLeft { 0% { -moz-transform-origin: left bottom; -moz-transform: rotate(0); opacity: 1; } 100% { -moz-transform-origin: left bottom; -moz-transform: rotate(90deg); opacity: 0; } } @-o-keyframes rotateOutDownLeft { 0% { -o-transform-origin: left bottom; -o-transform: rotate(0); opacity: 1; } 100% { -o-transform-origin: left bottom; -o-transform: rotate(90deg); opacity: 0; } } @keyframes rotateOutDownLeft { 0% { transform-origin: left bottom; transform: rotate(0); opacity: 1; } 100% { transform-origin: left bottom; transform: rotate(90deg); opacity: 0; } } 头像效果二123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190#ds-reset .ds-avatar img,#ds-reset .ds-avatar img:hover{ -webkit-animation-fill-mode: both; -moz-animation-fill-mode: both; -ms-animation-fill-mode: both; -o-animation-fill-mode: both; animation-fill-mode: both; -webkit-animation-duration: 0s; -moz-animation-duration: 0s; -ms-animation-duration: 0s; -o-animation-duration: 0s; animation-duration: 0s; -webkit-animation-duration: 0.7s; -moz-animation-duration: 0.7s; -ms-animation-duration: 0.7s; -o-animation-duration: 0.7s; animation-duration: 0.7s; } @-webkit-keyframes bounceIn { 0% { opacity: 0; -webkit-transform: scale(.3); } 50% { opacity: 1; -webkit-transform: scale(1.05); } 70% { -webkit-transform: scale(.9); } 100% { -webkit-transform: scale(1); } } @-moz-keyframes bounceIn { 0% { opacity: 0; -moz-transform: scale(.3); } 50% { opacity: 1; -moz-transform: scale(1.05); } 70% { -moz-transform: scale(.9); } 100% { -moz-transform: scale(1); } } @-o-keyframes bounceIn { 0% { opacity: 0; -o-transform: scale(.3); } 50% { opacity: 1; -o-transform: scale(1.05); } 70% { -o-transform: scale(.9); } 100% { -o-transform: scale(1); } } @keyframes bounceIn { 0% { opacity: 0; transform: scale(.3); } 50% { opacity: 1; transform: scale(1.05); } 70% { transform: scale(.9); } 100% { transform: scale(1); } } #ds-reset .ds-avatar img { -webkit-animation-name: bounceIn; -moz-animation-name: bounceIn; -o-animation-name: bounceIn; animation-name: bounceIn; } @-webkit-keyframes bounceOut { 0% { -webkit-transform: scale(1); } 25% { -webkit-transform: scale(.95); } 50% { opacity: 1; -webkit-transform: scale(1.1); } 100% { opacity: 0; -webkit-transform: scale(.3); } } @-moz-keyframes bounceOut { 0% { -moz-transform: scale(1); } 25% { -moz-transform: scale(.95); } 50% { opacity: 1; -moz-transform: scale(1.1); } 100% { opacity: 0; -moz-transform: scale(.3); } } @-o-keyframes bounceOut { 0% { -o-transform: scale(1); } 25% { -o-transform: scale(.95); } 50% { opacity: 1; -o-transform: scale(1.1); } 100% { opacity: 0; -o-transform: scale(.3); } } @keyframes bounceOut { 0% { transform: scale(1); } 25% { transform: scale(.95); } 50% { opacity: 1; transform: scale(1.1); } 100% { opacity: 0; transform: scale(.3); } } #ds-reset .ds-avatar img:hover{ -webkit-animation-name: bounceOut; -moz-animation-name: bounceOut; -o-animation-name: bounceOut; animation-name: bounceOut; } 头像效果三123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139#ds-reset .ds-avatar img,#ds-reset .ds-avatar img:hover{ -webkit-animation-fill-mode: both; -moz-animation-fill-mode: both; -ms-animation-fill-mode: both; -o-animation-fill-mode: both; animation-fill-mode: both; -webkit-animation-duration: 0s; -moz-animation-duration: 0s; -ms-animation-duration: 0s; -o-animation-duration: 0s; animation-duration: 0s; -webkit-animation-duration: 0.7s; -moz-animation-duration: 0.7s; -ms-animation-duration: 0.7s; -o-animation-duration: 0.7s; animation-duration: 0.7s; } @-webkit-keyframes rotateIn { 0% { -webkit-transform-origin: center center; -webkit-transform: rotate(-150deg); opacity: 0; } 100% { -webkit-transform-origin: center center; -webkit-transform: rotate(0); opacity: 1; } } @-moz-keyframes rotateIn { 0% { -moz-transform-origin: center center; -moz-transform: rotate(-150deg); opacity: 0; } 100% { -moz-transform-origin: center center; -moz-transform: rotate(0); opacity: 1; } } @-o-keyframes rotateIn { 0% { -o-transform-origin: center center; -o-transform: rotate(-150deg); opacity: 0; } 100% { -o-transform-origin: center center; -o-transform: rotate(0); opacity: 1; } } @keyframes rotateIn { 0% { transform-origin: center center; transform: rotate(-150deg); opacity: 0; } 100% { transform-origin: center center; transform: rotate(0); opacity: 1; } } #ds-reset .ds-avatar img{ -webkit-animation-name: rotateIn; -moz-animation-name: rotateIn; -o-animation-name: rotateIn; animation-name: rotateIn; } @-webkit-keyframes rotateOut { 0% { -webkit-transform-origin: center center; -webkit-transform: rotate(0); opacity: 1; } 100% { -webkit-transform-origin: center center; -webkit-transform: rotate(150deg); opacity: 0; } } @-moz-keyframes rotateOut { 0% { -moz-transform-origin: center center; -moz-transform: rotate(0); opacity: 1; } 100% { -moz-transform-origin: center center; -moz-transform: rotate(150deg); opacity: 0; } } @-o-keyframes rotateOut { 0% { -o-transform-origin: center center; -o-transform: rotate(0); opacity: 1; } 100% { -o-transform-origin: center center; -o-transform: rotate(150deg); opacity: 0; } } @keyframes rotateOut { 0% { transform-origin: center center; transform: rotate(0); opacity: 1; } 100% { transform-origin: center center; transform: rotate(150deg); opacity: 0; } } #ds-reset .ds-avatar img:hover{ -webkit-animation-name: rotateOut; -moz-animation-name: rotateOut; -o-animation-name: rotateOut; animation-name: rotateOut; } 头像效果四123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100#ds-reset .ds-avatar img,#ds-reset .ds-avatar img:hover{ -webkit-animation-fill-mode: both; -moz-animation-fill-mode: both; -ms-animation-fill-mode: both; -o-animation-fill-mode: both; animation-fill-mode: both; -webkit-animation-duration: 0s; -moz-animation-duration: 0s; -ms-animation-duration: 0s; -o-animation-duration: 0s; animation-duration: 0s; -webkit-animation-duration: 0.7s; -moz-animation-duration: 0.7s; -ms-animation-duration: 0.7s; -o-animation-duration: 0.7s; animation-duration: 0.7s; } @-webkit-keyframes rollIn { 0% { opacity: 0; -webkit-transform: translateX(-100%) rotate(-120deg); } 100% { opacity: 1; -webkit-transform: translateX(0px) rotate(0deg); } } @-moz-keyframes rollIn { 0% { opacity: 0; -moz-transform: translateX(-100%) rotate(-120deg); } 100% { opacity: 1; -moz-transform: translateX(0px) rotate(0deg); } } @-o-keyframes rollIn { 0% { opacity: 0; -o-transform: translateX(-100%) rotate(-120deg); } 100% { opacity: 1; -o-transform: translateX(0px) rotate(0deg); } } @keyframes rollIn { 0% { opacity: 0; transform: translateX(-100%) rotate(-120deg); } 100% { opacity: 1; transform: translateX(0px) rotate(0deg); } } #ds-reset .ds-avatar img{ -webkit-animation-name: rollIn; -moz-animation-name: rollIn; -o-animation-name: rollIn; animation-name: rollIn; } @-webkit-keyframes rollOut { 0% { opacity: 1; -webkit-transform: translateX(0px) rotate(0deg); } 100% { opacity: 0; -webkit-transform: translateX(100%) rotate(120deg); } } @-moz-keyframes rollOut { 0% { opacity: 1; -moz-transform: translateX(0px) rotate(0deg); } 100% { opacity: 0; -moz-transform: translateX(100%) rotate(120deg); } } @-o-keyframes rollOut { 0% { opacity: 1; -o-transform: translateX(0px) rotate(0deg); } 100% { opacity: 0; -o-transform: translateX(100%) rotate(120deg); } } @keyframes rollOut { 0% { opacity: 1; transform: translateX(0px) rotate(0deg); } 100% { opacity: 0; transform: translateX(100%) rotate(120deg); } } #ds-reset .ds-avatar img:hover{ -webkit-animation-name: rollOut; -moz-animation-name: rollOut; -o-animation-name: rollOut; animation-name: rollOut; } 头像效果五12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061#ds-reset .ds-avatar img,#ds-reset .ds-avatar img:hover{ -webkit-animation-fill-mode: both; -moz-animation-fill-mode: both; -ms-animation-fill-mode: both; -o-animation-fill-mode: both; animation-fill-mode: both; -webkit-animation-duration: 0s; -moz-animation-duration: 0s; -ms-animation-duration: 0s; -o-animation-duration: 0s; animation-duration: 0s; -webkit-animation-duration: 0.7s; -moz-animation-duration: 0.7s; -ms-animation-duration: 0.7s; -o-animation-duration: 0.7s; animation-duration: 0.7s; } @-webkit-keyframes swing { 20%, 40%, 60%, 80%, 100% { -webkit-transform-origin: top center; } 20% { -webkit-transform: rotate(15deg); } 40% { -webkit-transform: rotate(-10deg); } 60% { -webkit-transform: rotate(5deg); } 80% { -webkit-transform: rotate(-5deg); } 100% { -webkit-transform: rotate(0deg); } } @-moz-keyframes swing { 20% { -moz-transform: rotate(15deg); } 40% { -moz-transform: rotate(-10deg); } 60% { -moz-transform: rotate(5deg); } 80% { -moz-transform: rotate(-5deg); } 100% { -moz-transform: rotate(0deg); } } @-o-keyframes swing { 20% { -o-transform: rotate(15deg); } 40% { -o-transform: rotate(-10deg); } 60% { -o-transform: rotate(5deg); } 80% { -o-transform: rotate(-5deg); } 100% { -o-transform: rotate(0deg); } } @keyframes swing { 20% { transform: rotate(15deg); } 40% { transform: rotate(-10deg); } 60% { transform: rotate(5deg); } 80% { transform: rotate(-5deg); } 100% { transform: rotate(0deg); } } #ds-reset .ds-avatar img:hover{ -webkit-transform-origin: top center; -moz-transform-origin: top center; -o-transform-origin: top center; transform-origin: top center; -webkit-animation-name: swing; -moz-animation-name: swing; -o-animation-name: swing; animation-name: swing; } 头像效果六123456789101112131415161718192021222324252627282930313233343536373839404142434445#ds-reset .ds-avatar img,#ds-reset .ds-avatar img:hover{ -webkit-animation-fill-mode: both; -moz-animation-fill-mode: both; -ms-animation-fill-mode: both; -o-animation-fill-mode: both; animation-fill-mode: both; -webkit-animation-duration: 0s; -moz-animation-duration: 0s; -ms-animation-duration: 0s; -o-animation-duration: 0s; animation-duration: 0s; -webkit-animation-duration: 0.7s; -moz-animation-duration: 0.7s; -ms-animation-duration: 0.7s; -o-animation-duration: 0.7s; animation-duration: 0.7s; } @-webkit-keyframes pulse { 0% { -webkit-transform: scale(1); } 50% { -webkit-transform: scale(1.1); } 100% { -webkit-transform: scale(1); } } @-moz-keyframes pulse { 0% { -moz-transform: scale(1); } 50% { -moz-transform: scale(1.1); } 100% { -moz-transform: scale(1); } } @-o-keyframes pulse { 0% { -o-transform: scale(1); } 50% { -o-transform: scale(1.1); } 100% { -o-transform: scale(1); } } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.1); } 100% { transform: scale(1); } } #ds-reset .ds-avatar img:hover { -webkit-animation-name: pulse; -moz-animation-name: pulse; -o-animation-name: pulse; animation-name: pulse; } 头像效果七12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364#ds-reset .ds-avatar img,#ds-reset .ds-avatar img:hover{ -webkit-animation-fill-mode: both; -moz-animation-fill-mode: both; -ms-animation-fill-mode: both; -o-animation-fill-mode: both; animation-fill-mode: both; -webkit-animation-duration: 0s; -moz-animation-duration: 0s; -ms-animation-duration: 0s; -o-animation-duration: 0s; animation-duration: 0s; -webkit-animation-duration: 0.7s; -moz-animation-duration: 0.7s; -ms-animation-duration: 0.7s; -o-animation-duration: 0.7s; animation-duration: 0.7s; } @-webkit-keyframes wobble { 0% { -webkit-transform: translateX(0%); } 15% { -webkit-transform: translateX(-25%) rotate(-5deg); } 30% { -webkit-transform: translateX(20%) rotate(3deg); } 45% { -webkit-transform: translateX(-15%) rotate(-3deg); } 60% { -webkit-transform: translateX(10%) rotate(2deg); } 75% { -webkit-transform: translateX(-5%) rotate(-1deg); } 100% { -webkit-transform: translateX(0%); } } @-moz-keyframes wobble { 0% { -moz-transform: translateX(0%); } 15% { -moz-transform: translateX(-25%) rotate(-5deg); } 30% { -moz-transform: translateX(20%) rotate(3deg); } 45% { -moz-transform: translateX(-15%) rotate(-3deg); } 60% { -moz-transform: translateX(10%) rotate(2deg); } 75% { -moz-transform: translateX(-5%) rotate(-1deg); } 100% { -moz-transform: translateX(0%); } } @-o-keyframes wobble { 0% { -o-transform: translateX(0%); } 15% { -o-transform: translateX(-25%) rotate(-5deg); } 30% { -o-transform: translateX(20%) rotate(3deg); } 45% { -o-transform: translateX(-15%) rotate(-3deg); } 60% { -o-transform: translateX(10%) rotate(2deg); } 75% { -o-transform: translateX(-5%) rotate(-1deg); } 100% { -o-transform: translateX(0%); } } @keyframes wobble { 0% { transform: translateX(0%); } 15% { transform: translateX(-25%) rotate(-5deg); } 30% { transform: translateX(20%) rotate(3deg); } 45% { transform: translateX(-15%) rotate(-3deg); } 60% { transform: translateX(10%) rotate(2deg); } 75% { transform: translateX(-5%) rotate(-1deg); } 100% { transform: translateX(0%); } } #ds-reset .ds-avatar img:hover{ -webkit-animation-name: wobble; -moz-animation-name: wobble; -o-animation-name: wobble; animation-name: wobble; } 头像效果八12345678910111213141516171819#ds-reset .ds-avatar img{ width:54px;height:54px; /*设置图像的长和宽,这里要根据自己的评论框情况更改*/ border-radius: 27px;/*设置图像圆角效果,在这里我直接设置了超过width/2的像素,即为圆形了*/ -webkit-border-radius: 27px;/*圆角效果:兼容webkit浏览器*/ -moz-border-radius:27px; box-shadow: inset 0 -1px 0 #3333sf;/*设置图像阴影效果*/ -webkit-box-shadow: inset 0 -1px 0 #3333sf; -webkit-transition: 0.4s; -webkit-transition: -webkit-transform 0.4s ease-out; transition: transform 0.4s ease-out;/*变化时间设置为0.4秒(变化动作即为下面的图像旋转360读)*/ -moz-transition: -moz-transform 0.4s ease-out; } #ds-reset .ds-avatar img:hover{/*设置鼠标悬浮在头像时的CSS样式*/ box-shadow: 0 0 10px #fff; rgba(255,255,255,.6), inset 0 0 20px rgba(255,255,255,1); -webkit-box-shadow: 0 0 10px #fff; rgba(255,255,255,.6), inset 0 0 20px rgba(255,255,255,1); transform: rotateZ(360deg);/*图像旋转360度*/ -webkit-transform: rotateZ(360deg); -moz-transform: rotateZ(360deg); } 头像效果九12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758#ds-reset .ds-avatar img:hover { -webkit-animation-fill-mode: both; -moz-animation-fill-mode: both; -ms-animation-fill-mode: both; -o-animation-fill-mode: both; animation-fill-mode: both; -webkit-animation-duration: 0s; -moz-animation-duration: 0s; -ms-animation-duration: 0s; -o-animation-duration: 0s; animation-duration: 0s; -webkit-animation-duration: 1s; -moz-animation-duration: 1s; -ms-animation-duration: 1s; -o-animation-duration: 1s; animation-duration: 1s; -webkit-transform-style: preserve-3d; -moz-transform-style: preserve-3d; -o-transform-style: preserve-3d; transform-style: preserve-3d; -webkit-backface-visibility: visible !important; -webkit-animation-name: flip; -moz-backface-visibility: visible !important; -moz-animation-name: flip; -o-backface-visibility: visible !important; -o-animation-name: flip; backface-visibility: visible !important; animation-name: flip; } @-webkit-keyframes flip { 0% {-webkit-transform: perspective(400px) rotateY(0);-webkit-animation-timing-function: ease-out;} 40% {-webkit-transform: perspective(400px) translateZ(150px) rotateY(170deg);-webkit-animation-timing-function: ease-out;} 50% {-webkit-transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1);-webkit-animation-timing-function: ease-in;} 80% {-webkit-transform: perspective(400px) rotateY(360deg) scale(.95);-webkit-animation-timing-function: ease-in;} 100% {-webkit-transform: perspective(400px) scale(1);-webkit-animation-timing-function: ease-in;} } @-moz-keyframes flip { 0% {-moz-transform: perspective(400px) rotateY(0);-moz-animation-timing-function: ease-out;} 40% {-moz-transform: perspective(400px) translateZ(150px) rotateY(170deg);-moz-animation-timing-function: ease-out;} 50% {-moz-transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1);-moz-animation-timing-function: ease-in;} 80% {-moz-transform: perspective(400px) rotateY(360deg) scale(.95);-moz-animation-timing-function: ease-in;} 100% {-moz-transform: perspective(400px) scale(1);-moz-animation-timing-function: ease-in;} } @-o-keyframes flip { 0% {-o-transform: perspective(400px) rotateY(0);-o-animation-timing-function: ease-out;} 40% {-o-transform: perspective(400px) translateZ(150px) rotateY(170deg);-o-animation-timing-function: ease-out;} 50% {-o-transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1);-o-animation-timing-function: ease-in;} 80% {-o-transform: perspective(400px) rotateY(360deg) scale(.95); -o-animation-timing-function: ease-in;} 100% {-o-transform: perspective(400px) scale(1);-o-animation-timing-function: ease-in;} } @keyframes flip { 0% {transform: perspective(400px) rotateY(0);animation-timing-function: ease-out;} 40% {transform: perspective(400px) translateZ(150px) rotateY(170deg);animation-timing-function: ease-out;} 50% {transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1);animation-timing-function: ease-in;} 80% {transform: perspective(400px) rotateY(360deg) scale(.95);animation-timing-function: ease-in;} 100% {transform: perspective(400px) scale(1);animation-timing-function: ease-in;} } 头像效果十123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146/*Head Start*/ #ds-thread #ds-reset ul.ds-comments-tabs li.ds-tab a.ds-current { border: 0px; color: #6D6D6B; text-shadow: none; background: #F3F3F3;}#ds-thread #ds-reset .ds-highlight { font-family: Microsoft YaHei, \"Helvetica Neue\", Helvetica, Arial, Sans-serif; ;font-size: 100%; color: #6D6D6B !important;}#ds-thread #ds-reset ul.ds-comments-tabs li.ds-tab a.ds-current:hover { color: #696a52; background: #F2F2F2;}#ds-thread #ds-reset a.ds-highlight:hover { color: #696a52 !important;}#ds-thread { padding-left: 15px;}#ds-thread #ds-reset li.ds-post,#ds-thread #ds-reset #ds-hot-posts { overflow: visible;}#ds-thread #ds-reset .ds-post-self { padding: 10px 0 10px 10px;}#ds-thread #ds-reset li.ds-post,#ds-thread #ds-reset .ds-post-self { border: 0 !important;}#ds-reset .ds-avatar, #ds-thread #ds-reset ul.ds-children .ds-avatar { top: 15px; left: -20px; padding: 5px; width: 36px; height: 36px; box-shadow: -1px 0 1px rgba(0,0,0,.15) inset; border-radius: 46px; background: #FAFAFA;}#ds-thread .ds-avatar a { display: inline-block; padding: 1px; width: 32px; height: 32px; border: 1px solid #b9baa6; border-radius: 50%; background-color: #fff !important;}#ds-thread .ds-avatar a:hover { }#ds-thread .ds-avatar > img { margin: 2px 0 0 2px;}#ds-thread #ds-reset .ds-replybox { box-shadow: none;}#ds-thread #ds-reset ul.ds-children .ds-replybox.ds-inline-replybox a.ds-avatar,#ds-reset .ds-replybox.ds-inline-replybox a.ds-avatar { left: 0; top: 0; padding: 0; width: 32px !important; height: 32px !important; background: none; box-shadow: none;}#ds-reset .ds-replybox.ds-inline-replybox a.ds-avatar img { width: 32px !important; height: 32px !important; border-radius: 50%;}#ds-reset .ds-replybox a.ds-avatar,#ds-reset .ds-replybox .ds-avatar img { padding: 0; width: 32px !important; height: 32px !important; border-radius: 5px;}#ds-reset .ds-avatar img { width: 32px !important; height: 32px !important; border-radius: 32px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.22); -webkit-transition: .8s all ease-in-out; -moz-transition: .4s all ease-in-out; -o-transition: .4s all ease-in-out; -ms-transition: .4s all ease-in-out; transition: .4s all ease-in-out;}.ds-post-self:hover .ds-avatar img { -webkit-transform: rotateX(360deg); -moz-transform: rotate(360deg); -o-transform: rotate(360deg); -ms-transform: rotate(360deg); transform: rotate(360deg);}#ds-thread #ds-reset .ds-comment-body { -webkit-transition-delay: initial; -webkit-transition-duration: 0.4s; -webkit-transition-property: all; -webkit-transition-timing-function: initial; background: #F7F7F7; padding: 15px 15px 15px 47px; border-radius: 5px; box-shadow: #B8B9B9 0 1px 3px; border: white 1px solid;}#ds-thread #ds-reset ul.ds-children .ds-comment-body { padding-left: 15px;}#ds-thread #ds-reset .ds-comment-body p { color: #787968;}#ds-thread #ds-reset .ds-comments { border-bottom: 0px;}#ds-thread #ds-reset .ds-powered-by { display: none;}#ds-thread #ds-reset .ds-comments a.ds-user-name { font-weight: normal; color: #3D3D3D !important;}#ds-thread #ds-reset .ds-comments a.ds-user-name:hover { color: #D32 !important;}#ds-thread #ds-reset #ds-bubble { display: none !important;}#ds-thread #ds-reset #ds-hot-posts { border: 0;}#ds-reset #ds-hot-posts .ds-gradient-bg { background: none;}#ds-thread #ds-reset .ds-comment-body:hover { background-color: #F1F1F1; -webkit-transition-delay: initial; -webkit-transition-duration: 0.4s; -webkit-transition-property: all; -webkit-transition-timing-function: initial;}/*Head End*/ 头像效果十一123456789101112131415161718192021222324252627282930313233/*头像样式*/#ds-reset .ds-avatar { background:none !important; box-shadow:none !important;}#ds-reset .ds-avatar img , #ds-thread #ds-reset ul.ds-children .ds-avatar img { width:50px !important; height: 50px !important; -webkit-transition: .9s; -moz-transition: .9s; -o-transition: .9s; -ms-transition: .9s; padding: 2px; border: 1px solid #ddd; background: #fff;}/*鼠标悬停旋转头像*/.ds-post:hover .ds-avatar img { transform:rotate(360deg); -webkit-transform:rotate(360deg); -moz-transform:rotate(360deg); -o-transform:rotate(360deg); -ms-transform:rotate(360deg); border-radius:30px !important;}#ds-reset .ds-avatar img:hover { transform:rotate(360deg); -webkit-transform:rotate(360deg); -moz-transform:rotate(360deg); -o-transform:rotate(360deg); -ms-transform:rotate(360deg); border-radius:30px !important;} 特别感谢:@V说 @wsgzao","tags":[{"name":"Hexo","slug":"Hexo","permalink":"http://inplus.top/tags/Hexo/"}]},{"title":"记一次安卓Unity3d游戏的逆向分析","date":"2016-09-20T23:27:09.000Z","path":"archives/crackunity3d/","text":"使用到的工具 ApkToolBox.NET ReflectorReflexil(.NET程序编辑器) 怎么判定它是Unity游戏呢一般的路径格式是这样的assets\\bin\\Data\\Managed[如果是个Unity游戏却找不到dll文件那么骚年放弃吧。。。] 一般情况下都是修改上图的这个dll文件[如果想要搜索的东西不在这个dll文件可借用UltraEdit、EditPlus、Notepad++等常用编辑工具辅助搜索来判断对哪个dll文件进行修改 以Jam City这款游戏为例来作以下分析: 内购破解部分就不讲了,因为下面将要修改的比内购的要来的痛快用ApkToolBox反编译之后找到dll文件就是上图的那个文件用.NET Reflector打开[.NET Reflector工具的基本使用方法请自行百度]在手机上试玩了下这个游戏 篮板和抢断的路线根本就不明确嘛。。。 金币-Coin、等级-Level 那么着重修改这两个值吧 按下F3搜索,切换到方法搜索搜到的内容这么多 改哪个呢 头疼啊! 等等!unity3d提供的有存档类啊!这是一大重要的切入点O(∩_∩)O~ unity3d提供了一个用于本地持久化保存与读取的类——PlayerPrefs。其工作原理非常简单,以键值对的形式将数据保存在文件中,然后程序可以根据这个名称取出上次保存的数值。PlayerPrefs类支持3种数据类型的保存和读取,浮点型,整形,和字符串型。 游戏本地存档的主要方式无外乎xml文件和数据库存储两种,我们安装运行该游戏并简单的通过买物品和升级改变金币和等级的数值。 然后通过R.E.管理器进入/data/data/com.batteryacid.jamcity/shared_prefs/果然我们发现了命名包含playerprefs的xml存档文件 查看该文件,如下图,我们发现了与游戏中数值对应的两个 字符串-整型 键值对条目:金币Currency和等级CurrentLevel 我们回到.NET Reflector 切换到类搜索,搜索PlayerPrefs得到下图结果,双击进入位于Assembly-CSharp集中的PlayerPrefsx类 双击进入GetInt(String,Int32)整型方法,Tools —- reflexil v1.6 开启reflexil工具 然后在第一行“Create new…”新建字符串类型(OpCade代码为ldstr),最后“Insert before select”插入到第一行前 在第二行新建整型(OpCade代码为ldc.i4) 在第三行新建方法(OpCade代码为call),并在PlayerPrefsx类中选择GetInt(System.String,System.Int32)方法 这样,我们就将Currency强制设置为66666668了回到dll文件名这里,右键鼠标移到Reflexil v1.6保存dll 保存之后,F5刷新一下,如下图,代码中显示的是强制设置为了66666668 同理,我们也将等级CurrentLevel也强制设置为20 保存dll文件用IDE编译出来apk 看看效果 好了,初始金币和等级都修改成功 步骤回顾:1、反编译apk2、利用.NET Reflector反编译dll3、通过Unity3d的PlayerPrefs方法了解其写入读取过程4、通过查找存档xml文件找到相应控制条件5、在dll中找到相应位置修改代码段 总结:本文主要介绍安卓unity3d游戏的本地数据的修改方法。","tags":[{"name":"Android","slug":"Android","permalink":"http://inplus.top/tags/Android/"},{"name":"逆向札记","slug":"逆向札记","permalink":"http://inplus.top/tags/逆向札记/"}]},{"title":"win8.1,win10开机出现致命错误C0000034解决方法","date":"2016-07-11T10:20:00.000Z","path":"archives/windows-bluescreen/","text":"当您的电脑出现致命错误C0000034 正在更新操作54,共5073(000000000000000.cdf-ms)时,一般都是因为您系统在更新或修补漏洞时因为某种原因而中断,再次开机就会出现这类状况。 接下来就提供一种完美解决的方法: 1. 开机按F9/F8进入高级选项(如图所示),点击疑难解答。 2. 点击高级选项 3. 点击高级选项里的命令提示符 4. 在命令提示符中输入:notepad.exe(可以打开记事本) 5. 打开记事本后依次点击:文件>>打开>>修改(文件类型改为“所有文件”) 6. 找到C:\\Windows\\WinSxS\\pending.xml文件(如果您隐藏文件后缀则显示为pending)。然后先进行备份,以免操作失误造成损失!!切记!!! 7. 打开pending.xml文件之后为方便查看点击记事本>>格式>>自动换行。用ctrl+F查找checkpoint。选中小编图中标示的代码,删除。然后保存。重启电脑搞定! 注意:pending.xml文件一定要备份,不能保证此方法适用所有电脑,三思!","tags":[{"name":"windows","slug":"windows","permalink":"http://inplus.top/tags/windows/"}]},{"title":"eclipse首次使用基本设置","date":"2016-06-23T10:20:00.000Z","path":"archives/eclipsefirstsetting/","text":"最近,一些刚开始学习Java的朋友使用eclipse遇到了一些编码导致的问题向我询问,那就总结一下首次安装eclipse后我们大体应该设置哪些基本东西吧~大神们呐就不用看啦。 一、修改工作空间默认编码 在菜单导航栏上 Window–>Preferences 打开”首选项”对话框 左侧导航树导航到 General–>Workspace 二、修改文件类型的默认编码有时候我们需要某种类型的文件,如:.jsp、.java等 在菜单导航栏上 Window–>Preferences 打开”首选项”对话框 左侧导航树导航到 General–>Content Types 右边找到要修改的文件的类型,我这边以Java Source源文件为例 在下面的Default encoding,输入框中输入UTF-8->Update->OK 同上,把一般我们用到的CSS样式文件、HTML页面文件、Properties配置文件、Java源文件、Javascript脚本文件、JSP页面文件、XML配置文件等常用文件的默认编码均改为UTF-8 三、修改默认字体大小默认的字体实在是小的可怜,为了养眼(护眼- . -)我们需要适当的调整字体大小 在菜单导航栏上 Window–>Preferences 打开”首选项”对话框 左侧导航树导航到 General–>Appearance–>Colors and Fonts 看到右边字体一列有很多的选项,我们只需要修改Basic里面的 Basic–>Text Font–>Edit这里我把字体改为12 四、调整控制台缓冲区大小 显示更多日志输出 在菜单导航栏上 Window–>Preferences 打开”首选项”对话框 左侧导航树导航到 Run/Debug–>Console 调整Console buffer size(characters)为1000000 五、适当关闭validation语法校验 优化启动速度 在菜单导航栏上 Window–>Preferences 打开”首选项”对话框 左侧导航树导航到 Validation 将Manual(手动)保持不动,将Build里面只留下Classpath Dependency Validator,其他的全部去掉。 以后如果需要对文件进行校验检查的时候,在需要校验的文件上点击右键,点击Validate进行检查。 六、设置tab键为4个空格,统一格式 在菜单导航栏上 Window–>Preferences 打开”首选项”对话框 左侧导航树导航到 General–>Editors–>Text Editors 选中右侧的 Insert space for tabs 在菜单导航栏上 Window–>Preferences 打开”首选项”对话框 左侧导航树导航到 java–>code style- ->formatter 点击右侧的edit,选择左侧 tab policy 的值为 spaces only,并确保下方的空格个数为4 确定,应用保存即可,若出现应用Apply按钮为灰色的情况,需要回到上一步,点击new按钮,根据当前的样式重新生成一个新的样式并保存,名字可以随便起,新建以后重复上一步骤,编辑该样式即可。 七、修改背景颜色为护眼豆沙绿据说长时间使用可以缓解眼疲劳哦(吐槽:开什么玩笑,远离编程才能缓解眼疲劳好吗) 在菜单导航栏上 Window–>Preferences 打开”首选项”对话框 左侧导航树导航到 General–>Editors–>Text Editors 点击右侧下方 Appearance color options 中的B ackground color 取消掉右侧 System Default 的勾选,点击 Color 后的色块将出现颜色选择面板 点击展开规定自定义颜色,本例使用的背景色是喜大普奔的豆沙绿,比较柔和,设置为:色调:85。饱和度:123。亮度:205 即可,添加到自定义颜色并在自定义颜色中选中确定保存即可。 除此之外我们还可以设置非代码区的背景颜色(win7环境) 桌面右键个性化–>窗口颜色 高级外观设置–>项目–>窗口–>颜色 八、修改搜狗输入法设置,防止 ctrl+shift+f 热键冲突 在我们使用eclipse的时候通常使用 ctrl+shift+f 快捷键来快速代码格式化,是否有时候发现命名并没有更改默认的快捷键设置,而使用快捷键无法格式化代码却在菜单中点击可以呢,其实这是windows上一些其他程序的热键冲突导致的,像搜狗输入法就会优先占用 ctrl+shift+f 快捷键为切换简繁输入法的功能,那么我们就需要取消或者变更搜狗输入法的这个快捷键喽~ 搜狗输入法右键–>工具箱–>属性设置–>按键 取消右侧系统功能快捷键中简繁切换的勾选 好了,大功告成,就先介绍到这里吧。","tags":[{"name":"软件开发","slug":"软件开发","permalink":"http://inplus.top/tags/软件开发/"}]},{"title":"使用GitHub和Hexo搭建免费静态Blog","date":"2016-04-22T15:27:17.000Z","path":"archives/hexo/","text":"前言习惯自己写Blog的朋友一定不会陌生Wordpress,或许也曾在新浪博客和QQ空间留过脚印,但静心认真思考一下,似乎我们又总是向往更加简单自由的写作方式。GitHub给我们提供了一个无限的空间,我们需要珍惜使用,而Hexo的出现从某种意义上来说代替了Jekyll,让我们可以更专注于写作本身。 喜欢写Blog的人,会经历三个阶段。第一阶段,刚接触Blog,觉得很新鲜,试着选择一个免费空间来写。第二阶段,发现免费空间限制太多,就自己购买域名和空间,搭建独立博客。第三阶段,觉得独立博客的管理太麻烦,最好在保留控制权的前提下,让别人来管,自己只负责写文章。 大多数Blog作者,都停留在第一和第二阶段,因为第三阶段不太容易到达:你很难找到俯首听命、愿意为你管理服务器的人。 但是六年前,情况出现变化,一些程序员开始在GitHub网站上搭建blog。他们既拥有绝对管理权,又享受GitHub带来的便利—-不管何时何地,只要向主机提交commit,就能发布新文章。更妙的是,这一切还是免费的,GitHub提供无限流量,世界各地都有理想的访问速度。 今天,我就来示范如何在GitHub上搭建Blog,你可以从中掌握GitHub的Pages功能,以及Hexo软件的基本用法。更重要的是,你会体会到一种建立网站的全新思路。 概要GitHub Pages 是什么?如果你对编程有所了解,就一定听说过GitHub。它号称程序员的Facebook,有着极高的人气,许多重要的项目都托管在上面。简单说,它是一个具有版本管理功能的代码仓库,每个项目都有一个主页,列出项目的源文件。 但是对于一个新手来说,看到一大堆源码,只会让人头晕脑涨,不知何处入手。他希望看到的是,一个简明易懂的网页,说明每一步应该怎么做。因此,GitHub就设计了Pages功能,允许用户自定义项目首页,用来替代默认的源码列表。 所以,GitHub Pages可以被认为是用户编写的、托管在GitHub 上的静态网页。 GitHub 提供模板,允许站内生成网页,但也允许用户自己编写网页,然后上传。有意思的是,这种上传并不是单纯的上传,而是会经过Hexo或Jekyll等程序的再处理。 什么是Hexo?Hexo 是一个快速、简洁且高效的基于Node.js的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。作者是来自台湾的@tommy351。 A fast, simple & powerful blog framework, powered by Node.js. 类似于jekyll、Octopress、Wordpress,我们可以用Hexo创建自己的博客,托管到github、Heroku或Coding上,绑定自己的域名,用markdown写文章。本博客即使用hexo创建并托管在github上。 为什么要用hexo 不可思议的快速 ─ 只要一眨眼静态文件即生成完成支持 Markdown仅需一道指令即可部署到 GitHub Pages 和 Heroku已移植 Octopress 插件高扩展性、自订性兼容于 Windows, Mac & Linux 易用。不仅部署简单,平时使用中仅需要hexo new hexo generate hexo server hexo deploy四个命令。不像Jekyll需要很多繁琐的git命令。 轻。文件少、小,易理解,方便自定义。 用户多。虽然赶不上Jekyll和Octopress,但遇到什么问题都能搜索到答案,或者找到同样使用hexo的用户进行参考和咨询。 谁能使用hexo这是一个免费开源的博客程序,任何人都可以使用和修改。但是不同于wordpress,hexo由于需要使用Github,Git,Markdown,Node.js这样的工具,好多插件、widget都需要自己安装、设置。所以适合那些有一定计算机基础,喜欢折腾的人。但是,不要恐惧,只要跟着本教程走,就能很方便地让自己的博客”飞起来”。 怎样搭建hexo博客正题来了,请认真往下看吧。 准备工作注意 本文主要针对Windows平台和Hexo 3.x 安装GIT下载 Git 并执行即可完成安装。So Easy 安装Node.JS在 Windows 环境下安装Node.js非常简单,仅须下载Node.JS并执行即可完成安装。So Easy 安装Hexo在任意位置右键,选择Git Bash Here12345npm install -g hexo-cli#如果命令无法运行,可以尝试更换taobao的npm源npm config set registry https://registry.npm.taobao.org#或者安装使用cnpmnpm install -g cnpm --registry=https://registry.npm.taobao.org Hexo初始化配置创建hexo文件夹安装完成后,根据自己喜好建立目录(如D:\\hexo),在该文件夹下右键–Git Bash Here。执行以下命令1hexo init 安装依赖包1npm install 该命令会将hexo所需文件自动下载到hexo文件夹下。12345678910#新建完成后,指定文件夹的目录如下.├── _config.yml├── package.json├── scaffolds├── scripts├── source| ├── _drafts| └── _posts└── themes 安装Hexo插件(可省略)12345678910111213npm install hexo-generator-feed --savenpm install hexo-generator-sitemap --savenpm install hexo-generator-baidu-sitemap --savenpm install hexo-generator-json-content --savenpm install hexo-deployer-git --savenpm install hexo-generator-index --savenpm install hexo-generator-archive --savenpm install hexo-generator-category --savenpm install hexo-generator-tag --savenpm install hexo-server --savenpm install hexo-deployer-heroku --savenpm install hexo-deployer-rsync --savenpm install hexo-deployer-openshift --save 查看本地运行效果现在我们已经搭建起本地的Hexo博客了,继续执行以下命令(在D:\\Hexo),成功后即可登录localhost:4000查看效果,运行显示了相关页面,说明当前网站已经在本地建立。12hexo generatehexo server 好了,至此,本地博客已经搭建起来了,只是本地哦,别人看不到的。下面,我们要部署到Github。 配置GitHub注册Github账号已有账号可以跳过,没有的,请登录GitHub进行注册,很简单,这里就不介绍了。 创建repository在自己Github主页右下角,创建New repository。比如我的Github账号是viosay,那么我应该创建的repository名字应该是viosay.github.io。首次创建耐心等待10分钟左右审核,之后即可访问静态主页如http://viosay.github.io 配置部署编辑_config.yml(在D:\\hexo下)。你在配置时,要把下面的viosay都换成你的账号名。1234deploy: type: git repository: https://github.com/viosay/viosay.gith防和谐ub.io.git branch: master 注意:type:空格git。都要使用空格,否则会出错。 配置本机的ssh key通过ssh keys就可以将本地的项目与Github关联起来 检查本机ssh key1cd ~/.ssh 提示:没使用过Git就会显示:No such file or directory 生成新的ssh keys123$ ssh-keygen -t rsa -C \"邮件地址@youremail.com\"Generating public/private rsa key pair.Enter file in which to save the key (/Users/your_user_directory/.ssh/id_rsa):<回车> 注意:-C为大写的C接下来会让你输入密码12Enter passphrase (empty for no passphrase):<输入加密串>Enter same passphrase again:<再次输入加密串> 注意:输入密码时是不会显示密码的,依次输入就好了如果显示为下界面,就说明设置ssh key成功了 添加ssh key到Github 搜索本机上的id_rsa.pub文件。或在C:\\Users\\用户名\\.ssh路径下找到该文件,以记事本打开,复制其中的内容。 进入自己的Github,右上角齿轮setting—左边列表SSH keys—Add SSH key。将内容复制到文本框(不用取title名字)。注意:这时Github会给你的邮箱发送一封邮件,打开邮件确认下就好了。 测试通信1ssh -T [email protected] 如果是以下反馈123The authenticity of host 'github.com (207.97.227.239)' can't be established.RSA key fingerprint is 16:27:ac:a5:76:28:防和谐2d:36:63:1b:56:4d:eb:df:a6:48.Are you sure you want to continue connecting (yes/no)? 输入yes1Hi yourusername! You've successfully authenticated, but GitHub does not provide shell access. 这时候说明能够通过SSH链接到你的Github了,接下来完善一下你的个人信息。Git会根据用户的名字和邮箱来记录提交。GitHub也是用这些信息来做权限的处理,输入下面的代码进行个人信息的设置,把名称和邮箱替换成你自己的,名字必须是你的真名,而不是GitHub的昵称。12git config --global user.name \"Tim\" #用户名git config --global user.email \"[email protected]\" #填写自己的邮箱 使用Hexo克隆主题自己使用的是Yilia主题,比较喜欢,以这款主题为例。 克隆主题1git clone https://github.com/litten/hexo-theme-yilia.git themes/yilia 配置修改hexo根目录下的_config.yml:1theme: yilia 更新12cd themes/yiliagit pull 本地查看12hexo ghexo s 浏览器输入localhost:4000,查看主题是否成功。 部署上传123hexo cleanhexo ghexo d 会让你输入用户名和密码,依次输入就好。 部分Hexo主题推荐 选择主题建议遵循KISS原则 Hexo Themes - http://hexo.io/themes/Themes · hexojs/hexo Wiki - https://github.com/hexojs/hexo/wiki/Themes Yilia - http://litten.github.io/2014/08/31/hexo-theme-yilia/Jacman - http://wsgzao.github.io/post/hexo-jacman/NexT - http://theme-next.iissnan.com/ 绑定域名和DNS设置设置CNAME 打开Github–空间Repository的根目录下–点击“+”creat a new file–命名为CNAME,文本框中输入自己需要绑定的域名如inplus.top。 点击右下角的【Download ZIP】,下载项目,解压压缩包,将其中的CNAME文件复制到hexo根目录下。12hexo ghexo d DNS设置注册登录DNSPod,先添加域名,然后添加记录,设置如下 主机记录 记录类型 线路类型 记录值 MX优先级 TTL @ CNAME 默认 viosay.github.io. - 10 www CNAME 默认 viosay.github.io. - 10 域名推荐 GoDaddy makes registering Domain Names fast, simple, and affordable.【推荐理由】两个字“靠谱”,支持支付宝,附优惠码链接http://www.godaddy.comhttp://www.gdcodecoupon.com - 万网【推荐理由】被阿里收入麾下,实力和价格都不错https://wanwang.aliyun.com DNS推荐 致力于为您提供最稳定、最安全的域名解析服务【推荐理由】依然是两个字“靠谱”,被腾讯收入麾下以后扔不忘初心,感谢他们一直以来对于公益的坚持https://www.dnspod.cn 开始写文章1hexo new \"postName\" 或路径D:\\hexo\\source\\_posts下新建文件postName.md就可以了文章内容和格式如下:123456789---title: 标题date: YYYY-MM-DD hh:mm:sstags: 标签 #多标签时以[tag1,tag2]格式填写categories: 类别 #多类别时以[category1,category2]格式填写---主页可显摘要<!-- more --> #阅读全文分隔符展开余下全文 正文内容使用Markdown语法进行书写 图床推荐 七牛云【推荐理由】体系完善,操作简便易懂测试用户每月1G流量,实名后每月10G,小站够用。需要注意的是未备案网站无法使用CDN,存在盗图和恶意刷流量的可能,而且七牛是先使用后付费,自己领悟吧。http://www.qiniu.com - Simple Free Image Hosting【推荐理由】免费,强大,无限制,用了都说好缺点:后期无法对上传的图片进行管理https://sm.ms说明:https://www.v2ex.com/t/182703 其他相关常见问题 修改配置文件时注意YAML语法,参数冒号:后一定要留空格 中文乱码请修改文件编码格式为UTF-8 Error代码:「warning: LF will be replaced by CRLF」在hexo deploy时,有时会出现这个提示信息warning: LF will be replaced by CRLF,虽然看起来挺乱糟糟的,但不影响使用,可以忽略不计。若想不提示,可以使用如下方法: 切换到博客的根目录,执行如下命令:git config --global core.autocrlf false 删除掉该目录下的.git文件夹(可能是隐藏的),命令:rm -rf .git 重新git init。 再deploy试试吧,清新脱俗了。 Error代码:hexo deploy 没反应好多网友遇到过这个问题,目前来看,主要问题出在config.yml的deploy配置上。注意缩进,同时注意冒号后面要有一个空格。Error代码:hexo update -g 升级错误,hexo命令失效我升级时遇到了这个问题,原因不详。这种情况下,可执行npm install hexo-cli -g重新安装一遍Hexo,效果跟升级一样。Error代码:hexo指令无法执行可能是升级方法不对,导致hexo generate指令也无法执行,后来索性重装了git和node,重新安装hexo,generate和server指令都能执行了,但是出现了“Deployer not found: github”。Error代码:Deployer not found: git更改_config.yml主配置文件为utf-8编码时导致的异常。执行npm install hexo-deployer-git --save然后重新deploy即可。 各版本所做更新修正,请参考这里。 如何迁移至Hexohttp://hexo.io/zh-cn/docs/migration.html Hexo命令12345678910hexo init <folder> #初始化一个网站目录 我是直接cd到目标目录执行hexo init的hexo new \"postName\" #新建文章,或者source\\_posts手动编辑hexo new page \"pageName\" #新建页面 默认链接为:主页地址/pageName/hexo clean #清除缓存文件db.json和已生成的静态文件publichexo generate #生成public静态文件至public目录hexo server #本地发布预览效果 http://localhost:4000 ('ctrl + c'关闭server)hexo deploy #将.deploy目录部署到GitHubhexo --debug #在终端中显示调试信息并记录到 `debug.log`hexo help #查看帮助hexo version #查看Hexo的版本 Hexo简写命令1234hexo n \"postName\" #新建文章,或者source\\_posts手动编辑hexo g #生成public静态文件至public目录hexo s #本地发布预览效果 http://localhost:4000 ('ctrl + c'关闭server)hexo d #将.deploy目录部署到GitHub Hexo复合命令1234hexo d -g #生成并部署上传hexo s -g #生成并本地发布预览hexo clean && hexo d -g #清空缓存然后生成并部署上传hexo clean && hexo s -g #清空缓存然后生成并本地发布预览 本文部分说明来自互联网特别感谢 @wsgzao @阮一峰 @TimFei @Litten @陈素封 @zippera @不如","tags":[{"name":"软件开发","slug":"软件开发","permalink":"http://inplus.top/tags/软件开发/"},{"name":"Hexo","slug":"Hexo","permalink":"http://inplus.top/tags/Hexo/"}]},{"title":"Markdown语法综述","date":"2016-03-10T15:27:17.000Z","path":"archives/markdown/","text":"Markdown 是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者,撰稿者广泛使用。看到这里请不要被「标记」、「语言」所迷惑,Markdown 的语法十分简单。常用的标记符号也不超过十个,这种相对于更为复杂的HTML 标记语言来说,Markdown 可谓是十分轻量的,其流行程度已经得到了GitHub和Stack Overflow的广泛支持,学习成本也不需要太多,作为普通人我们也可以轻松上手,结合Hexo我们可以十分优(zhuang)雅(bi)的分享知识,传递快乐。 认识Markdown 在此之前,需要了解的是。Markdown不支持任何格式,所谓的加粗和斜体,只是两种强调语法,最终是显示为何种格式都是合理的。所以,尽管Markdown的语法非常简单,但是Markdown的目的并不是要取代 HTML,甚至也没有要和它相近,Markdown的语法种类很少,只对应 HTML标记的一小部分。Markdown的构想并不是要使得 HTML 文档更容易书写。在我看来,HTML 已经很容易写了。Markdown 的理念是,能让文档更容易读、写和随意改。HTML 是一种发布的格式,Markdown 是一种书写的格式。就这样,Markdown 的格式语法只涵盖纯文本可以涵盖的范围。样式和结构分离,算是Markdown的设计思想之一,而这也是现在 HTML 的发展方向,况且结构布局本来就是CSS控制的。 在刚才的导语里提到,Markdown是一种用来写作的轻量级「标记语言」,它用简洁的语法代替排版,而不像一般我们用的文字处理软件Word或Pages有大量的排版、字体设置。它使我们专心于码字,用「标记」语法,来代替常见的排版格式。例如此文从内容到格式,甚至插图,键盘就可以通通搞定了。目前来看,支持 Markdown 语法的编辑器有很多,包括很多网站(例如简书)也支持了 Markdown 的文字录入。Markdown 从写作到完成,导出格式随心所欲,你可以导出 HTML 格式的文件用来网站发布,也可以十分方便的导出 PDF 格式,这种格式写出的简历更能得到 HR 的好感。甚至可以利用CloudApp这种云服务工具直接上传至网页用来分享你的文章,全球最大的轻博客平台 Tumblr,也支持使用Mou这类Markdown工具进行编辑并直接上传。 Markdown 官方文档 创始人 John Gruber 的 Markdown 语法说明 Markdown语法说明中文完整版 Markdown语法说明中文简要版 使用 Markdown 的优点专注你的文字内容而不是排版样式。轻松的导出 HTML、PDF 和本身的 .md 文件。纯文本内容,兼容所有的文本编辑器与字处理软件。可读,直观。适合所有人的写作语言。 Markdown 语法的简要规则1、标题标题是每篇文章都需要也是最常用的格式,在 Markdown 中,如果一段文字被定义为标题,只要在这段文字前加1-6个#号即可。同理、你还可以增加二级标题、三级标题、四级标题、五级标题和六级标题,总共六级,只需要增加#即可,标题字号相应降低。例如:123456# 一级标题## 二级标题### 三级标题#### 四级标题##### 五级标题###### 六级标题 注意:建议在#和标题之间保留一个字符的空格,这是最标准的Markdown 语法。 2、列表列表分为无序列表和有序列表,在 Markdown中,列表的显示只需要在文字前加上星号*、减号-或是加号+即可变为无序列表,有序列表则直接在文字前加1. 2. 3.等即可。例如:1234567891011* 文本A* 文本B* 文本C或- 文本A- 文本B- 文本C或+ 文本A+ 文本B+ 文本C 1231. 文本12. 文本23. 文本3 注意:符号和文字之间要加上一个字符的空格。 3、引用在我们写作的时候经常需要引用他人的文字,这个时候引用这个格式就很有必要了。在 Markdown 中,你只需要在你希望引用的文字前面加上右角括号>就好了。例如:123> 幸得识卿桃花面,从此阡陌多暖春。下文 注意:>和引用文本之间要保留一个字符的空格,引用与下文之间保留一行空行。 4、链接与图片链接和图片也是丰富文章必不可少的因素。使用[显示文本](链接地址)这样的语法即可插入链接,使用![](图片链接地址)这样的语法即可插入图片。例如:1[寻沫小栈](http://viosay.github.io) 1![我的头像](http://viosay.github.io/assets/img/head.jpg) 注意:插入图片的语法和链接的语法很像,只是前面多了一个!。 另:Markdown支持以比较简短的自动链接形式来处理网址和电子邮件信箱,只要是用尖括号<和>包起来,Markdown 就会自动把它转成链接。一般网址的链接文字就和链接地址一样。例如:1<http://example.com/> 5、粗体与斜体Markdown的粗体和斜体也非常简单,用两个星号**或两个下划线__包裹一段文本就是粗体的语法,用一个星号*或一个下划线_包裹一段文本就是斜体的语法。例如:1**这里是粗体** 1*这里是斜体* 6、分割线与删除线分割线的语法只需要另起一行,连续输入三个减号---、下划线___、星号***即可。删除线的语法只需用两个波浪号~~包裹一段文本即可。例如:12345---或___或*** 1~~本段文字被删除线拦截~~ 注意:对于分割线,行内不得有任何其他字符。 7、代码句和代码块如果你是个程序猿,需要在文章里优雅的引用代码框,在 Markdown 下实现也非常简单。需要引用代码时,如果引用的代码语句只有一段,不分行,可以用一个重音符`将代码语句包裹起来。如果引用的语句为多行的代码块,可以将三个重音符```置于这段代码的首行和末行来包裹代码块。例如:1`hello word代码句` 注意:在代码块中使用tab键即可进行缩进。 8、表格相对于那些简单的语法,Markdown表格则较为繁琐和累人。例如:12345| Tables | Are | Cool || ------------- |:-------------:| -----:|| col 3 is | right-aligned | $1600 || col 2 is | centered | $12 || zebra stripes | are neat | $1 | Markdown 编辑器推荐在线编辑器: Cmd Markdown 编辑阅读器 https://www.zybuluo.com作业部落出品,是一款不错的工具和博客平台兼顾的产品。全平台且提供web版。 简书 http://www.jianshu.com/writer一个很不错的博客平台,每几秒钟便会自动存入一个备份。可以直接从本地拖入照片生成链接,一直在不断优化。作为一个博客平台,需要注册账号后方能进行写作。 Editor.MDhttps://pandao.github.io/editor.md开源。 MaHua http://mahua.jser.me界面有些丑陋。 小书匠编辑器 http://soft.xiaoshujiang.com全平台覆盖并且有web版。 dillinger http://dillinger.io漂亮强大,支持md, html, pdf 文件导出。支持dropbox, onedrive,google drive, github. 来自国外,可能不够稳定。 Marxico http://marxi.co中文:马克飞象 http://maxiang.info因为印象笔记不支持Markdown,而这款可以直接把文本存到印象笔记的编辑器对于重度印象笔记用户是个不错的选择。付费软件,可以免费试用。 Windows 平台: MarkdownPad http://markdownpad.com一款全功能的编辑器,被很多人称赞为windows 平台最好用的markdown编辑器。 MarkPad http://code52.org/DownmarkerWPF Smark http://git.oschina.net/elerao/Smark开源软件 MdCharm http://www.mdcharm.com/功能完备,长相一般,隐藏菜单栏后也算简约。有Windows 和Linux版本。目前已开源,不再更新。 Linux 平台:ReText http://sourceforge.net/p/retext/home/ReText Mac 平台: Mou http://mouapp.com似乎提到 Mac 和 MD,接下来的词一定是Mou,因为他们是一个姓吗。 Typora http://typora.io有出Windows 和Linux版本的计划。 MacDown http://macdown.uranusjr.com开源免费 Byword http://bywordapp.com支持OS X, iOS 售价78元。 iA Writer https://ia.net/writer/ios支持OS X , iOS 及Android,未优化中文显示,知乎此问题中很多人认为 Byword比 iA 好 。售价68,pro版本128元。 Ulysses http://www.ulyssesapp.com支持OS X , iPad, 少数派有一篇专门的文章介绍,售价 283元。 Typed http://realmacsoftware.com/typed少数派有关于的测评 ,售价128元。 浏览器插件:MaDe(Chrome)https://chrome.google.com/webstore/detail/oknndfeeopgpibecfjljjfanledpbkog) 高级应用:Sublime Text 2 + MarkdownEditing / 教程","tags":[{"name":"软件开发","slug":"软件开发","permalink":"http://inplus.top/tags/软件开发/"},{"name":"Hexo","slug":"Hexo","permalink":"http://inplus.top/tags/Hexo/"}]},{"title":"小镜头大视角:摄影师用iPhone拍摄乐高人偶的生活","date":"2016-01-04T14:51:10.000Z","path":"archives/legotwo/","text":"『摄影师』Andrew Whyte:带着乐高小人去旅行 乐高玩具在全世界都拥有著无数粉丝,与之相关的《The Lego Movie》也是横扫世界各地的电影票房。当然,乐高玩具人人会玩,可要是想以这些小方块创作出壹些艺术作品的话可就不是那么容易了。如果你找不到什么灵感的话,那不如来看看摄影师 Andrew Whyte 利用乐高玩偶创造的「Legography」系列作品吧。 Andrew Whyte 擅长利用长曝光等方式创作变化多端的微观风格摄影作品。在「Legography」系列作品中,他通过技术手段巧妙地将玩偶所处的微观环境以拟人化的形态呈现在大家眼前。玩偶好似壹个现实世界中的真实身影,在不同的场景中展开各种离奇的故事。 想要了解更多有关「Legography」作品的朋友可以访问 Andrew Whyte 的官方网站。 手机镜头的视角与相机大不相同,为了达到目标,作者尝试了19次才把相机玩具扔到了正确地位置。 iPhone 4s在低光照的情况下画质不佳,即使这样,这张黄昏时的照片还是可以接受的 很多时候乐高摄影需要趴在地上完成,作者因此也成为了其他游客的拍摄对象 作者收集了许多腿、躯干、帽子的零件,能帮助小人偶进行换装 天气不好的时候拍摄仍没有停止,作者还为小人偶加了件雨衣 有时为了拍摄与野生动物相关的照片,作者遭遇了器械的损坏,甚至还受了伤 拍摄于朴茨茅斯,英国唯一的岛屿城市。 由于人偶的表情不能变化,所以大部分的照片都避开了正面,这是唯一的一张人偶自拍照 SlowShutter实现了作者对于长曝光app的期望,其对焦与曝光锁在黑暗中相当有用 天气一般时,往往尝试了各种滤镜后也不能获得满意的效果。但有时等到第二天早上,就能拍到不需要后期的满意照片 英国摄影师Andrew Whyte专长于戏剧灯光艺术与对于夜空的长时间曝光,但他最近的一些工作相当引人注目——他为一位一英寸高的小小摄影师拍摄了一组照片。Whyte花了超过一年的时间拍摄了这组称为“乐高摄影师”的系列作品,其中的主角是一个手拿黑色相机的乐高积木人偶。这个小人偶和Whyte一起旅行,一起看日出,一起在伦敦游览。 考虑到便携性,这组乐高摄影是由iPhone完成的,从最初的4s到现在的5s。Whyte使用一款称为645 Pro的应用来获得更多的手动拍摄选项,然后使用Snapseed特效进行后期后上传到乐高摄影的Facebook页面。“作为对于手机摄影的探索,这个项目相当具有启发性,我知道了我能够在几乎任何地方都能用手机拍出高水准的作品。”Whyte说道。另外他还有一些其他的长曝光摄影作品。 英国摄影师Andrew Whyte是一位擅长在弱光环境下创作的职业摄影师。他认为弱光环境下的摄影可以让“光线”和“时间”这两种最具魅力的元素交织在一起。但是在他的整个摄影职业当中,有一个非常重要的摄影项目却并非专注于弱光环境的拍摄,而是一个以乐高玩具小人为主人公的系列作品——《Legography》。 作品中的玩具小人扮演了摄影师的角色,“他”用自己的相机去看世界,而我们也从照片中看到了“他”看到的世界,从作品中你甚至可以读出“他”的性格:执着、专注、勇敢,对摄影有一种热烈的追求,你也能从“他”观看世界的角度中感受到“他”的情绪:思念、好奇、陶醉、孤独…… 类似于这样以玩具或者公仔作为摄影兴趣中心的作品相信大家也看过不少。这样的作品很容易具有故事性,也就很容易让我们进入画面,获得情景设置所要传达的感受。 值得一提的是,这个系列的作品均为手机拍摄,并用手机软件修图制作完成。 乐高不一定是小朋友们钟爱的玩具,很多大人也对乐高情有独钟。摄影师Andrew Whyte作为一名“乐高控”,走到哪都要带着他的“Legographer”,于是便有了这一系列照片。 Andrew Whyte来自英国,“Legographer”大部分照片拍摄于英格兰南部的著名海滨城市朴茨茅斯。这一系列照片均出自iPhone 4s,拍摄软件为645 Pro Mark II,并经过Snapseed后期处理。这样的拍摄组合另很多人意外,其实Andrew有意想挑战一下手机的弱光拍摄效果,同时也可以达到在实战中提升自己拍摄水平的目的。毫无疑问,他的目的达到了。 英国摄影师Andrew Whyte用镜头记录乐高人偶的英国游记,透过“Mini摄影师”的角度重新看世界! 凭着一点玩心和创意,英国摄影师Andrew Whyte突发奇想,以乐高 (Lego) 小人为主角记录下了他眼中的英伦风光。这位身材小小的“摄影师”相当敬业,克服千难万险拍摄了落日、彩虹等一系列美丽风景。一起来看看吧! 其实,Andrew Whyte不仅为我们带来了一组创意十足的旅行摄影图集,还十分贴心地整理出拍摄这类照片运用的方法和一些注意事项,接下来是“带着乐高小人去旅行”教学篇! 给大家介绍了摄影师Andrew Whyte拍摄的“带着乐高小人去旅行”系列照片,这组照片给人眼前一亮的感觉。其实摄影师不但介绍了这些照片的拍摄背景和器材使用情况,更加难能可贵的是,还为大家总结出了5点拍摄类似专题的注意事项,希望大家看后能有所收获: 寻找一个有趣的故事:任何一个拍摄活动都有主题,这是大家首先要确定的事情。接下来就可以围绕这个主题开始拍摄,可以尝试不同的手法,控制好大场景中的人物比例、小范围的景深问题等。 低角度:有时候我们习惯了同一高度拍摄,却忘了低角度可能有令人意想不到的效果。就像这组照片,很多时候都是贴着水平线拍摄,这样的角度给人新鲜的感觉,把视角低下来没准就能看到另一个世界。 运用技巧弥补:手机拍摄有很大的局限性,但是运用一些小技巧完全可以弥补。例如手机在弱光环境下表现不尽如人意,可以运用手电等照明装置给主体打光;在阴雨天路面积水会反光,这时可以利用影子来遮挡,这样就可以解决光比大的问题了。 反复确定对焦点:刚刚提到了手机拍摄的局限性,所以在拍摄时需要反复确定对焦点,这样才能保证对焦准确。 善于使用App:这组照片使用了645 Pro Mark II和Snapseed,这两个软件搭配使用效果很好。但不意味着大家也要使用,只要运用自己习惯的App,在拍摄是最大限度的发挥其功效,就能拍出满意的照片。","tags":[{"name":"宇宙之大","slug":"宇宙之大","permalink":"http://inplus.top/tags/宇宙之大/"}]},{"title":"英夫妇带\"乐高玩具人偶\"全球旅行,另类情侣照获热捧。","date":"2016-01-01T14:32:05.000Z","path":"archives/legoone/","text":"英格兰夫妇克雷格·麦克卡特尼(Craig McCartney)与林德赛·哈格蒂(Lindsey Haggerty)正进行“乐高全球旅行”,他们携带着以自己为蓝本、用乐高玩具拼成的情侣假人进行全球旅行,为“乐高情侣”拍摄的另类情侣照网上受热捧。 麦克卡特尼与哈格蒂正在环球自助游,除了携带背包、地图、照相机外,他们还用乐高玩具拼成人偶,每到一地就用人偶拍照,并将这些另类情侣照传到网上,引发网络风潮。 麦克卡特尼与哈格蒂已经去过法国、葡萄牙、西班牙、丹麦、老挝、越南、马来西亚、泰国,目前正在澳大利亚拍照。他们的Facebook帐号已经有数千名“粉丝”。 麦克卡特尼说:“在我考虑送女友30岁生日礼物时,我看到了乐高相机。这给我了很多灵感,因为我们喜欢多地旅游。而当我们到达新的城市时,哈格蒂总是拍照留念,而我则拿着地图和背包。” 麦克卡特尼还说:“我做了两个乐高小人儿代表我们两人,乐高哈格蒂身上带着相机,乐高麦克卡特尼则背着包拿着地图,这是我们在巴黎庆祝哈格蒂30岁生日时,我送她的第一份礼物。你可能惊异于我们花费多长时间拍摄到如此恰到好处的照片,因为即使最轻微的风都能将小人儿刮倒,为此我们总是需要找好适当的高度,以固定好它们。”","tags":[{"name":"宇宙之大","slug":"宇宙之大","permalink":"http://inplus.top/tags/宇宙之大/"}]},{"title":"tomcat+java的web程序持续占cpu问题调试","date":"2015-12-23T14:17:44.000Z","path":"archives/highcpu/","text":"[线上应用故障排查之:高CPU占用]一个应用占用CPU很高,除了确实是计算密集型应用之外,通常原因都是出现了死循环。以我们最近出现的一个实际故障为例,介绍怎么定位和解决这类问题。现象:在tomcat中部署java的web应用程序,过一段时间后出现tomcat的java进程持续占用cpu高达100%,导致web程序访问受阻。可能原因分析:可能程序确实在进行数据计算;或程序进入死循环。解决方法: 根据top命令,查看占用cpu的进程PID,发现PID为2738的Java进程占用CPU高达99.9%,出现故障。 通过ps aux | grep PID或ps -ef | grep PID命令,定位具体的进程主体,如是否是tomcat启动的java进程出现了问题。但是,怎么定位到具体线程或者代码呢?首先显示线程列表: 用ps -mp PID -o THREAD,tid,time命令打印出该进程下的线程占用cpu情况找到了耗时最高的线程2804,占用CPU时间快三个半小时了! 其次用printf "%x\\n" TID命令将需要的线程ID转换为16进制格式: 最后用jstack PID |grep tid -A 30命令打印线程的堆栈信息: 找到出现问题的代码了! 现在来分析下具体的代码即可: 找到出现问题的代码,并分析具体函数中是否有可能出现死循环的代码段。通常问题出现在while, for之类的循环代码片段。 AlarmSendListener.run(AlarmSendListener.java:98)SnmpTrapThreads.run(SnmpTrapThreads.java:66)ProduceAlarmEvent.run(ProduceAlarmEvent.java:50) 最后,总结下排查CPU故障的方法和技巧有哪些:1、top命令:Linux命令。可以查看实时的CPU使用情况。也可以查看最近一段时间的CPU使用情况。2、PS命令:Linux命令。强大的进程状态监控命令。可以查看进程以及进程中线程的当前CPU使用情况。属于当前状态的采样数据。3、jstack:Java提供的命令。可以查看某个进程的当前线程栈运行情况。根据这个命令的输出可以定位某个进程的所有线程的当前运行状态、运行代码,以及是否死锁等等。4、pstack:Linux命令。可以查看某个进程的当前线程栈运行情况。 特别感谢@hankchen","tags":[{"name":"软件开发","slug":"软件开发","permalink":"http://inplus.top/tags/软件开发/"},{"name":"Java","slug":"Java","permalink":"http://inplus.top/tags/Java/"}]},{"title":"化学geek是怎么玩坏表情包的:翻滚吧,苯宝宝!","date":"2015-12-08T12:51:33.000Z","path":"archives/benzenebaby/","text":"最近在网上,大家可能会看到一系列“苯宝宝”的表情,简单说就是用苯环和相关化合物来取谐音做表情,像这样: 虽然对化学有点感情,不过Po主对这个表情还是不满意,化学狗的脑洞并没有得到充分展现嘛……而且说实话也不大好看。 于是!我开拓了一下脑洞,自己画了一组表情包和大家共赏(:з」∠) 你们如果有什么好的脑洞,也欢迎发给我233 总之,下面的内容可能会很冷,请准备好热水袋…… 嗯别装醇了,你就是一个酚,还是最简单的酚。(顺便,苯酚还是生产阿司匹林的重要原料~ 说起来,“多虑”的话,难道不应该是多氯联苯吗—— 苯宝宝多氯加强版:联苯也多氯了! 多氯联苯是一系列化合物的统称,它们也是需要警惕的环境污染物 三硝基甲苯,也就是TNT啦 嗯如果苯加氢到饱和,也就是环己烷了……不少涂改液的溶剂是甲基环己烷,你可能还记得它的气味 砜是一种含硫化合物,如果少一个氧的话就是亚砜,不少实验室可能会用到二甲亚砜这种东西。 嗯,正辛酸呢…… 下面还有几个后续脑洞: 萘铌~有点像是象形火星文= = 两个苯环并在一起就是萘 这个是蒽重如山…… 三个苯环并一排就是蒽环(:з」∠) 总之今天的脑洞就到这儿了……欢迎大家一起交流冷梗(:з」∠) 以下是评论精选:苯宝宝炸了! 看穿一切的六甲基四氢化萘 毫无违和感—— 最后附送一个英语世界里的“苯宝宝”梗: diene是二烯的意思,而且读起来也像是dying,于是也就被画成了小人儿蹬腿的样子~","tags":[{"name":"宇宙之大","slug":"宇宙之大","permalink":"http://inplus.top/tags/宇宙之大/"}]},{"title":"几种VCS(版本控制系统)的特点和异同","date":"2015-12-05T09:56:40.000Z","path":"archives/vcs/","text":"版本控制系统(version control system),是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。版本控制系统不仅可以应用于软件源代码的文本文件,而且可以对任何类型的文件进行版本控制。用的比较多的如svn,git等。 为了让不同系统上的开发者能够协同工作,集中化的版本控制系统应运而生(CVCS)。这类系统都有一个单一的集中管理的服务器,保存所有文件的修订版本。而协同工作的人们都通过客户端连接到这台服务器,获取最新的文件或者提交更新。集中化的版本控制系统,最显而易见的缺点是中央服务器的单点故障问题。如果宕机,那么就会出现谁都无法提交更新的情况,那么也就无法协同工作;如果磁盘发生故障,而备份又不够即时,那么就有丢失数据的风险,最坏的情况是丢失整个项目的历史更改记录。因此,分布式版本控制系统问世了(DVCS)。 在分布式版本控制系统中,客户端不仅仅是只提取最新版本的文件快照,而是把代码仓库完整的镜像下来。所以每一次提取的操作,都是对代码仓库的完整备份,因此也就不必担心协同工作用的服务器发生故障。 Git和其他版本控制系统的主要差别在于:Git只关心文件数据的整体是否发生了变化,而多数的其他系统则只关心文件内容的具体差异,它们在每个版本中记录着各个文件的具体差异。在Git中的绝大多数操作都只需要访问本地文件和资源,不需要联网。这是因为Git在本地磁盘上就保留着所有当前项目的历史更新,所以处理起来速度飞快,这是使用空间换时间的处理方式。使用Git,即使在没有网络或VPN的情况下,你同样可以非常愉快的频繁提交更新,等到有了网络的时候再提交到远程的仓库。 CVS : Git : Mercurial : Subversion 的异同特征是否原子提交CVS: 没有. CVS提交不是原子的Git: 是的. 提交都是原子的Mercurial: 是的Subversion: 提交都是原子的 文件和目录是否可以移动或重命名CVS: 不是. 重命名不支持. 如果手动进行, 可能会损坏历史记录Git: 支持重命名, 这是很实用的目的. git甚至能检测到重命名之后文件的改变. 尽管如此, 基于特殊的存储结构, 重命名不会被显示的记录, git能够推导出来(在实际使用中很容易做到)Mercurial: 是的, 重命名是支持的Subversion: 是的. 支持重命名 在移动或重命名之后智能合并CVS: 不能. 重命名都不支持, 就不必说智能了Git: 不支持. 细节在Git FAQ里: “Git有一个重命名的命令git mv, 但是这仅仅是为了便利. 效果和移掉某个文件, 增加另外一个文件没有任何区别”Mercurial: 是的. 重命名之后智能合并是支持的. Mercurtial文档说:“如果我修改一个文件,而你重新命名了这个文件, 然后我们合并我们的变更, 那么我所做的修改就会被更新到根据旧文件名字而产生的新文件里(这可能就是你所期望的‘最简单的动作’, 但是不是所有版本控制系统都支持)Subversion: 不支持. “svn help me“中提到“注意: 这个子命令相当于拷贝和删除.“并且可能有个bug 文件和目录拷贝CVS: 不能. 拷贝不支持Git: 不能. 拷贝不支持Mercurtial: 是的. 支持拷贝Subversion: 是的. 并且拷贝非常容易(O(1)). 包括产生分支 远程存储仓库的备份CVS: 间接的. 可以使用John Polstra写的CVSupGit: 是的. 是git的内部特征Mercurial: 是的Subversion: 间接的. 可以使用Chia-liang Kao的SVN::Mirror插件(好像是台湾人)或Shlomi Fish的SVN-Pusher工具 是否传递变更到父仓库CVS: 不会Git: 是的(Linux内核开发过程经常使用这个特征)Mercurtial: 是的Subversion: 是的, 使用要么是Chia-Ling Kao的SVN::Mirror脚本或者Shlomi Fish的svn-push工具 仓库权限CVS: 很有限. “pre-commit hook scripts“能够被用来实现各种权限控制系统Git: 请看和Git一起附带的contrib/hooks/update-paranoid. 看和svnperms类似的path_rules的代码Mercutial: 是的. 它能够锁住仓库, 子目录或者使用hooks后的文件Subversion: 是的. 基于HTTP权限的WebDAV-based模块能够支持基于目录级的仓库 变更集CVS: 不是. 变更是基于文件的Git: 是的. 是支持的, 创建他们很容易Mercurial: 是的. 变更集是支持的Subversion: 部分支持. 对于一次提交会隐式创建一个变更集 跟踪线性的文件历史CVS: 是的. cvs annotateGit: 是的.(git blame)Mercurial: 是的(hg annotate)Subversion: 是的(svn blame) 能够只在仓库的单目录下作用CVS: 是的Git: 不是. 尽管如此, 提交多少能被限制, 请看“Repository Permissions”Mercurial: 能够基于某树的某个子集进行提交. 也有局部检出的能力Subversion: 是的 跟踪未提交的变化CVS: 是的. 通过cvs diffGit: 是的. 另外, 分支在git里非常智能, 在某些工作流里能够被当成是另外一个未提交代码的存储库. 请看“git stash“命令Mercurial: 是的. 使用hg diffSubversion: 是的. 使用svn diff 基于单个文件的提交信息CVS: 不是. 提交信息是基于单次变化的Git: 是的. 提交信息基于变更集Mercurial: 不是Subversion: 不是. 没有这个特征 文档CVS: 非常棒. 有很多在线的tutorials和资源, 在线的书籍. 命令行客户端也支持一个在线的帮助系统Git: 良好. 短的帮助比较简洁难懂. man页很有分量, 但容易误解. 有很多tutorialMercurial: 很好. 有基于公司的书籍和wiki. 每个命令都集成了帮助Subversion: 很好. 有一些在线的书籍和一些在线的tutorials和资源. 并且书籍是以docbook/xml写的所以很容易变换成其他格式. 命令行同样提供了在线的帮助系统 配置是否轻松CVS: 好. 是个事实上的标准. 基于每个系统都有并且很容易配置Git: 好. 在现有平台上二进制可用. 需要C编译器和Perl. 在windows上需要cygwin. 并有一些Unix特征Mercurial: 非常好. 几乎所有平台都有二进制包. 从源码编译需要python2.3以上, 并且需要C编译器Subversion: Subversion服务器需要安装在apache2模块里(如果有人希望HTTP作为底层协议的话)或使用它自身的服务器. 客户端需要Subversion特征的逻辑还有WebDAV库(针对HTTP). 安装组件很直接, 但是需要一些额外的工作(假定subversion在某些平台没有二进制包可用) 命令集CVS: 包含了3个经常用到的命令的简单的命令集(cvs commit, cvs update和cvs checkout)和其它一些Git: 命令集很丰富, 并且和CVS不兼容Mercurial: 尝试模仿CVS交互方式, 但是偏离了基于不同的设计的意图Subversion: 类CVS的命令集, 能够很容易被CVS用户使用 网络支持CVS: 好. cvs在不同的场合使用不同的协议. 协议能够通过ssh链接的加密隧道进行Git: 非常棒. 能够使用本地的git协议, 但也能在rsync, ssh, HTTP和HTTPS上使用Mercurial: 非常棒. 使用HTTP或ssh. 远程访问会非常安全, 在只读网络里不需要上锁Subversion: 非常好. Subversion服务器支持WebDAV+DeltaV(基于HTTP或HTTPS)作为底层协议, 或者它自身的协议同样能在ssh链接通道里使用. 可移植性CVS: 好. 客户端能在UNIX, Windows和Mac OS上使用. 服务器端能在UNIX, 附有UNIX模拟层的Windows上使用Git: 客户端运行在大多数的UNIX系统上, 但没有MS-Windows本地程序. 基于cygwin的系统看起来也能使用Mercurial: 非常棒. 运行在基于所有能运行python的平台.仓库是兼容性的基于CPU结构和字节序的Subversion: 非常好. 客户端和服务器端都能在UNIX, Windows和Mac OS X上运行 web接口CVS: 是的. CVSweb, ViewVC, Chora和wwCVSGit: 是的. Gitweb包含在发布包中Mercurial: 是的. Web接口是内置组件Subversion: 是的. ViewVC, SVN::Web, WebSVN, ViewSVN, mod_svn_view, Chora, Trac, SVN::RaWeb::Light, SVN Browser, Insurrection和perl_svn.另外, Subversion的apache服务也提供了一个基础的web接口 图形用户界面CVS: 非常好. 有很多图形界面可以用: WinCVS, Cervisia(对于KDE), TortoiseCVS(Windows浏览器插件)Git: Gitk包含在发行版中. Qqit和Git-gui工具也可使用Mercurial: 通过hgit扩展查看历史; 检入扩展(hgct)使得提交很容易. 一些第三方的IDEs和GUI工具(如eric3, meld)有一些集成的Mercurial支持Subversion: 非常好. 有很多GUIs可用: RapidSVN(跨平台), TortoiseSVN(Windows浏览器插件), Jsvn(java), 等. 大多数都还在开发中","tags":[{"name":"软件开发","slug":"软件开发","permalink":"http://inplus.top/tags/软件开发/"}]},{"title":"信条","date":"2015-12-04T15:35:06.000Z","path":"archives/motto/","text":"我可以划船不用桨,我可以扬帆没有风向,因为我这一生,全靠浪。","tags":[{"name":"随笔","slug":"随笔","permalink":"http://inplus.top/tags/随笔/"}]},{"title":"檀香悸","date":"2012-07-09T15:35:06.000Z","path":"archives/santalwait/","text":"是不是天意,无依无据,凭空捏造千里,拉长了梦的天梯。幻与实失之交臂,冷冻了原本凄凉的空气。 颤栗断断续续,檀香季一如往昔,缓缓转动的留声机,承载着多少美丽的回忆。偶尔打断的杂音,和愁思一起,扰乱着现实的风景,一切恍然虚拟。 泛黄而又粗糙的过去,停留在被人践踏过了的黄绿色的草地。树下秋千荡着别离,能否在别离处相聚。冰冷石凳上的孤寂,余有失意的惨淡叹息。对不起,打扰一句:似乎有人还在等你。 【Out of sight , in imagination】 – 风澈 – 2012年夏","tags":[{"name":"随笔","slug":"随笔","permalink":"http://inplus.top/tags/随笔/"}]},{"title":"梦中作","date":"2012-05-17T15:35:06.000Z","path":"archives/dreampoem/","text":"在梦中,身旁有位清洁工…… 怜琴为簧直,爱棋因局方。琴键黑白明,棋子润有光。宇间触阶凉,白芷微味芳。星河洒墨痕,花语断篇章。攥握青翠瑭,孑影红叶旁。觅寻枯叶蝶,醉倒温柔乡。 缥缈烟花影,畅透寒冰晶。尘埃落蓦静,啄饮莫前定。春来花自青,秋至叶飘零。一切似无意,心苦历经营。风花冠世间,谈笑生街边。雨润青石巷,苔生灰瓦檐。细雨扯偏调,碎语伴呢喃。夜半话语短,今昔寥无言。 柳絮丝如缕,明月谁共与。流水随心去,落花不相弃。轻轻风荷举,缓缓芙蓉靡。叹君惜罗预,须臾不可离。 一生一梦里,一琴一首曲。一日换一季,一世等一聚。 ‘’’ 唉,倦意催人眠,眨眼间,又是一天。 – 风澈 – 2012年春夏之交","tags":[{"name":"随笔","slug":"随笔","permalink":"http://inplus.top/tags/随笔/"}]}]