centos7.2 64bit
nginx version: nginx/1.12.2
sqlite 3.7.17-8.el7

使用 docker 搭建生产环境

安装nginx

yum -y update
yum install epel-release
yum install nginx

systemctl start nginx
systemctl enable nginx
systemctl status nginx

the configuration file /etc/nginx/nginx.conf

配置防火墙

firewall-cmd --zone=public --permanent --add-service=http
firewall-cmd --zone=public --permanent --add-service=https
firewall-cmd --reload

测试

http://SERVER_DOMAIN_NAME_OR_IP

配置文件和路径

默认web服务路径/etc/nginx
主配置文件 /etc/nginx/nginx.conf
虚拟主机配置文件可以添加到 /etc/nginx/conf.d
默认文档 /usr/share/nginx/html

sqlite3

sudo yum install sqlite-devel
sqlite3 -version

php5

配置yum源

sudo yum install epel-release
sudo rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm

查看可安装的包

sudo yum list --enablerepo=remi --enablerepo=remi-php56 | grep php
sudo yum install yum-utils

可以随机存取元素(支持索引值直接存取,用[]操作符或at()方法)

原理

双端队列的数据被表示为一个分段数组,容器中的元素分段存放在一个个大小固定的数组中,此外容器还需要维护一个存放这些数组首地址的索引数组,如下图所示。

20190515_171539.png

由于分段数组的大小是固定的,并且它们的首地址被连续存放在索引数组中,因此可以对其进行随机访问,但效率比vector低很多
向两端加入新元素时,如果这一端的分段数组未满,则可以直接加入,如果这一端的分段数组已满,只需创建新的分段数组,并把该分段数组的地址加入到索引数组中即可。无论哪种情况都不需要对已有元素进行移动,因此在双端队列的两端加入新的元素都具有较高的效率。

当删除双端队列容器两端的元素时,由于不需要发生元素的移动,效率也是非常高的。

双端队列中间插入元素时,需要将插入点到某一端之间的所有元素向容器的这一端移动,因此向中间插入元素的效率较低,而且往往插入位置越靠近中间,效率越低。删除队列中元素时,情况也类似,由于被删除元素到某一端之间的所有元素都要向中间移动,删除的位置越靠近中间,效率越低。

注意:
在除了首尾两端的其他地方插入和删除元素,都将会导致指向deque元素的任何pointers、references、iterators失效。不过,deque的内存重分配优于vector。因为其内部结构显示不需要复制所有元素。

queue

clear

使用swap,这种是最高效的,定义clear,保持STL容器的标准。

void clear( std::queue<int> &q )
{
std::queue<int> empty;
std::swap( q, empty );
}

queue<int>().swap(q);

queue<Json::Value> empty;
swap(empty, m_curInfo.listCmd);
swap(empty, m_curInfo.listCmdFrontend);

推荐阅读。

这本涉及行为金融学的书终于感觉到有收获了,还要再看几遍。

20190515_055101.png

常用接口

插入

可以设置 data 然后根据选中的 data 来判断是哪个。

auto item = m_ctrl_tree.InsertItem(L"几何常数");
m_ctrl_tree.InsertItem(L"测量工步");
m_ctrl_tree.InsertItem(L"预处理");

SetItemImage

BOOL SetItemImage(
HTREEITEM hItem,
int nImage,
int nSelectedImage);

Notify

NM_CLICK

ON_NOTIFY(NM_CLICK, 4, &CFolderView::OnNMClickTree)

void OnNMClickTree(NMHDR *pNMHDR, LRESULT *pResult);

void CFolderView::OnNMClickTree(NMHDR *pNMHDR, LRESULT *pResult)
{
g_pwndMain->m_spWndFileList->ActivateFrame();
*pResult = 0;
}

typedef struct tagNMHDR
{
HWND hwndFrom;
UINT_PTR idFrom;
UINT code;
} NMHDR;

TVN_SELCHANGING

ON_NOTIFY(TVN_SELCHANGING, 4, &CFolderView::OnTvnSelchangingFolder)

afx_msg void OnTvnSelchangingFolder(NMHDR *pNMHDR, LRESULT *pResult);

void CFolderView::OnTvnSelchangingFolder(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
}

TVN_SELCHANGED

ON_NOTIFY(TVN_SELCHANGED, 4, &CFolderView::OnTvnSelchangedFolder)

void OnTvnSelchangedFolder(NMHDR *pNMHDR, LRESULT *pResult);

void CFolderView::OnTvnSelchangedFolder(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
HTREEITEM hItem = pNMTreeView->itemNew.hItem;
if (hItem == 0)
{
return;
}
if (hItem != m_curDbRootItem)
{
m_wndTree.SetItemImage(hItem, 1, 1);
}
if (pNMTreeView->itemOld.hItem != m_curDbRootItem)
{
m_wndTree.SetItemImage(pNMTreeView->itemOld.hItem, 2, 2);
}
m_wndTree.Expand(pNMTreeView->itemNew.hItem, TVE_EXPAND);

*pResult = 0;
}

常用接口

插入

可以设置 data 然后根据选中的 data 来判断是哪个。

auto item = m_ctrl_tree.InsertItem(L"几何常数");
m_ctrl_tree.InsertItem(L"测量工步");
m_ctrl_tree.InsertItem(L"预处理");

SetItemImage

BOOL SetItemImage(
HTREEITEM hItem,
int nImage,
int nSelectedImage);

Notify

NM_CLICK

ON_NOTIFY(NM_CLICK, 4, &CFolderView::OnNMClickTree)

void OnNMClickTree(NMHDR *pNMHDR, LRESULT *pResult);

void CFolderView::OnNMClickTree(NMHDR *pNMHDR, LRESULT *pResult)
{
g_pwndMain->m_spWndFileList->ActivateFrame();
*pResult = 0;
}

typedef struct tagNMHDR
{
HWND hwndFrom;
UINT_PTR idFrom;
UINT code;
} NMHDR;

TVN_SELCHANGING

ON_NOTIFY(TVN_SELCHANGING, 4, &CFolderView::OnTvnSelchangingFolder)

afx_msg void OnTvnSelchangingFolder(NMHDR *pNMHDR, LRESULT *pResult);

void CFolderView::OnTvnSelchangingFolder(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
}

TVN_SELCHANGED

ON_NOTIFY(TVN_SELCHANGED, 4, &CFolderView::OnTvnSelchangedFolder)

void OnTvnSelchangedFolder(NMHDR *pNMHDR, LRESULT *pResult);

void CFolderView::OnTvnSelchangedFolder(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
HTREEITEM hItem = pNMTreeView->itemNew.hItem;
if (hItem == 0)
{
return;
}
if (hItem != m_curDbRootItem)
{
m_wndTree.SetItemImage(hItem, 1, 1);
}
if (pNMTreeView->itemOld.hItem != m_curDbRootItem)
{
m_wndTree.SetItemImage(pNMTreeView->itemOld.hItem, 2, 2);
}
m_wndTree.Expand(pNMTreeView->itemNew.hItem, TVE_EXPAND);

*pResult = 0;
}

utf8

注意跳过开头 3 个字节的 BOM

with codecs.open(filePath, 'r+', 'utf-8') as f:
content = f.read()
f.seek(3, 0)
f.write(statisticStr + content)

delete

os.remove() removes a file.
os.rmdir() removes an empty directory.
shutil.rmtree() deletes a directory and all its contents.
阅读全文 »

/*
// 包含minidump.h
// 然后在最开始的地方调用如下函数即可,会在应用目录下生成crash.dat文件

//设置异常处理回调函数
RunCrashHandler();

== == == == == == == == == == ==
minidump.h
*/

#pragma once

#include <windows.h>
#include <imagehlp.h>
#include <tchar.h>
#include <stdlib.h>
#pragma comment(lib, "dbghelp.lib")



inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName)
{
if (pModuleName == 0)
{
return FALSE;
}

WCHAR szFileName[_MAX_FNAME] = L"";
_wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);
if (wcsicmp(szFileName, L"ntdll") == 0)
return TRUE;

return FALSE;
}

inline BOOL CALLBACK MiniDumpCallback(PVOID pParam,
const PMINIDUMP_CALLBACK_INPUT pInput,
PMINIDUMP_CALLBACK_OUTPUT pOutput)
{
if (pInput == 0 || pOutput == 0)
return FALSE;

switch (pInput->CallbackType)
{
case ModuleCallback:
if (pOutput->ModuleWriteFlags & ModuleWriteDataSeg)

if (!IsDataSectionNeeded(pInput->Module.FullPath))

pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);

case IncludeModuleCallback:
case IncludeThreadCallback:
case ThreadCallback:
case ThreadExCallback:
return TRUE;

default:;
}

return FALSE;
}

//创建Dump文件
inline void CreateMiniDump(EXCEPTION_POINTERS* pep, LPCTSTR strFileName)
{
HANDLE hFile = CreateFile(strFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
{
MINIDUMP_EXCEPTION_INFORMATION mdei;
mdei.ThreadId = GetCurrentThreadId();
mdei.ExceptionPointers = pep;
mdei.ClientPointers = FALSE;
MINIDUMP_CALLBACK_INFORMATION mci;
mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;
mci.CallbackParam = 0;
MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)0x0000ffff;
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &mdei, NULL, &mci);

CloseHandle(hFile);
}
}

LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
{
return NULL;
}

BOOL PreventSetUnhandledExceptionFilter()
{
HMODULE hKernel32 = LoadLibraryA(("kernel32.dll"));
if (hKernel32 == NULL)
return FALSE;


void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter");
if (pOrgEntry == NULL)
return FALSE;


unsigned char newJump[100];
DWORD dwOrgEntryAddr = (DWORD)pOrgEntry;
dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far


void *pNewFunc = &MyDummySetUnhandledExceptionFilter;
DWORD dwNewEntryAddr = (DWORD)pNewFunc;
DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;


newJump[0] = 0xE9; // JMP absolute
memcpy(&newJump[1], &dwRelativeAddr, sizeof(pNewFunc));
SIZE_T bytesWritten;
BOOL bRet = WriteProcessMemory(GetCurrentProcess(), pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten);
return bRet;
}


LONG WINAPI UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS *pException)
{
TCHAR szMbsFile[MAX_PATH] = { 0 };
::GetModuleFileName(NULL, szMbsFile, MAX_PATH);
TCHAR* pFind = _tcsrchr(szMbsFile, '\\');
if (pFind)
{
*(pFind + 1) = 0;
_tcscat(szMbsFile, _T("crash.dat"));
CreateMiniDump(pException, szMbsFile);
}


// TODO: MiniDumpWriteDump
FatalAppExit(-1, _T("Fatal Error"));
return EXCEPTION_CONTINUE_SEARCH;
}

//运行异常处理
void RunCrashHandler()
{
SetUnhandledExceptionFilter(UnhandledExceptionFilterEx);
PreventSetUnhandledExceptionFilter();
}

compile with vs2015

website

use CMake generate vs2015 project
设置源码路径和 VS2015 工程生成路径,点击 Config,选择 [Visual Studio 14 2015],配置成功后,会在配置区域生成配置选项,这里可以根据实际情况选择是否使用 ATL 以及是否使用沙盒等
编译 libcef_dll_wrapper,编译成功后,会在 [工程目录]\libcef_dll_wrapper\Debug\ (如果是 Release 版,则是[工程目录]\libcef_dll_wrapper\Release\)下找到编译后的 libcef_dll_wrapper.lib

work with mysql

连接数据库

<?php
//phpinfo();
// 5.0 之前的接口,已废弃
//mysql_connect("192.168.153.139:3306","root","1qaz") or die("dd");
//mysql_select_db("demo") or die("connect db failed.");
//mysql_query("SET NAMES 'utf8mb4'") or die (mysql_error());
//mysql_query("SET CHARACTER SET utf8mb4")or die (mysql_error());
//mysql_query("SET CHARACTER_SET_RESULT = utf8mb4")or die (mysql_error());

// 5.0 之后使用新接口
$mysqli = new mysqli("192.168.153.139:3306", "root", "1qaz", "demo");

/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}

/* change character set to utf8mb4 */
if (!$mysqli->set_charset("utf8mb4")) {
printf("Error loading character set utf8mb4: %s\n", $mysqli->error);
} else {
printf("Current character set: %s\n", $mysqli->character_set_name());
}

remote development

phpstorm 2019.1.1
添加 remote host
tool - deploymnet - configuration
选择 sftp 设置用户名密码,路径就可以了,
mappings 选项也要配置一下
开发方便直接放在了容器路径下 /var/www/html