openssl coding得到过期时间

#include <stdio.h>
#include <string.h>

#include <openssl/rand.h>
#include <openssl/asn1t.h>
#include <openssl/pem.h>
#include <openssl/bio.h>

#include "lws-pub.h"
#include "lws-sha1-base64.h"


static char* ECDSACertPEM = "-----BEGIN CERTIFICATE-----\n"
"MIIGxzCCBa+gAwIBAgIIc54uwAnLX20wDQYJKoZIhvcNAQELBQAwgbQxCzAJBgNV\n"
"...\n"
"...\n"
"MXYXS/YRsQ1FZrOK0RL3Ts624N4QZnfIxLspqiRo6wlCvUutLRe1QieqVfjm7SYp\n"
"r7rWE+e3ef9C+es=\n"
"-----END CERTIFICATE-----\n";

int main()
{
    uint8_t * p = NULL;
    lws_filepos_t flen = 0;

    BIO* bio_buf = BIO_new(BIO_s_mem());
    BIO_write(bio_buf, ECDSACertPEM, strlen(ECDSACertPEM));
    X509 * cert = PEM_read_bio_X509(bio_buf, NULL, NULL, NULL);
    const ASN1_TIME *tm = X509_get0_notAfter(cert);
    printf("date: %s \r\n", tm->data);

    BIO_free(bio_buf);
    X509_free(cert);

    struct tm tm1;
    ASN1_TIME_to_tm(tm, &tm1);
    
    printf("date: %d-%d-%d \r\n", 1900+tm1.tm_year, 1+tm1.tm_mon, tm1.tm_mday);

    getchar();
    return 0;
}

 

学习boost预编译–FOR循环

BOOST_PP_SEQ_FOR_EACH
最复杂就是这个BOOST_PP_SEQ_FOR_EACH
BOOST_PP_SEQ_FOR_EACH(macro,data,seq)表示对seq里一个元素,执行MACRO(n,data,e),其中e为元素,data为附加数据,n为循环次数+1.
首先BOOST_PP_SEQ_FOR_EACH会做一些检查,略过.
然后开始用BOOST_PP_SEQ_FOR_EACH_DETAILHECK_EXEC执行,然后调用BOOST_PP_FOR
FOR可能会被嵌套调用,BOOST_PP_FOR用BOOST_PP_AUTO_REC探测一个最小的序号.
如BOOST_PP_FOR_1
#define BOOST_PP_SEQ_FOR_EACH_DETAILHECK_EXEC(macro,data,seq) BOOST_PP_FOR((macro,data,seq,BOOST_PP_SEQ_SIZE(seq)),BOOST_PP_SEQ_FOR_EACH_P,BOOST_PP_SEQ_FOR_EACH_O,BOOST_PP_SEQ_FOR_EACH_M)
然后到BOOST_PP_FOR_1(s,p,o,m)//s为seq p,o,m为上面的BOOST_PP_SEQ_FOR_EACH_X
BOOST_PP_SEQ_FOR_EACH_P(r,x)=BOOST_PP_TUPLE_ELEM(4,3,x)//表示从tuple x中取出索引为3的元素,就是最后一个.
BOOST_PP_SEQ_FOR_EACH_O(r,x)=BOOST_PP_SEQ_FOR_EACH_O_I x=BOOST_PP_SEQ_FOR_EACH_O_I_DEC(macro,data,seq,BOOST_PP_DEC(sz))
BOOST_PP_DEC返回sz-1,作为循环终止条件,而这个sz通过之前我们说过的BOOST_PP_SEQ_SIZE传入的.
BOOST_PP_SEQ_FOR_EACH_O_I_DEC又会调用BOOST_PP_IF(sz,BOOST_PP_SEQ_FOR_EACH_O_I_TAIL,BOOST_PP_SEQ_FOR_EACH_O_I_NIL)
BOOST_PP_IF就是一个条件宏,当sz大于0返回前者,否则返回后者.
BOOST_PP_SEQ_FOR_EACH_M(r,x)=BOOST_PP_SEQ_FOR_EACH_M_IM(r,BOOST_PP_TUPLE_REM_4 x)
而BOOST_PP_TUPLE_REM_4的作用是去掉x的括号,如(a,b,c)→a,b,c
而BOOST_PP_SEQ_FOR_EACH_M_IM→BOOST_PP_SEQ_FOR_EACH_M_I
BOOST_PP_SEQ_FOR_EACH_M_I(r,macro,data,seq,sz) macro(r,data,BOOST_PP_SEQ_HEAD(seq))
BOOST_PP_SEQ_HEAD为取出seq中第一个元素.
这里可以看出之前打开的括号里的内容为macro,data,seq,sz.
归纳一下:
p取出未元素,后面可以p总是调用(macro,data,seq,sz),也就是说p取sz大小,而sz在循环中要dec的,所以p为取循环变量.
o将sz值减一然后判断
m执行传入的macro
可以看出靠着三者就可以完成一轮循环了.
介绍完成这些函数再来看FOR
BOOST_PP_FOR_1(s,p,o,m)=BOOST_PP_FOR_1(BOOST_PP_BOOL(p(2,s)),s,p,o,m)
注意此时s=(macro,data,seq,sz),p=BOOST_PP_SEQ_FOR_EACH_P,BOOST_PP_BOOL(p(2,s))表示把s中最后一个就是sz取bool值.
BOOST_PP_FOR_1_C(c,s,p,o,m)=BOOST_PP_IIF(c,m,BOOST_PP_TUPLE_EAT_2)(2,s) BOOST_PP_IIF(c,BOOST_PP_FOR_2,BOOST_PP_TUPLE_EAT_4)(BOOST_PP_EXPR_IIF(c,o)(2,s),p,o,m)
BOOST_PP_IIF(c,m,BOOST_PP_TUPLE_EAT_2)(2,s)//若c非0则为m(2,s),否则BOOST_PP_TUPLE_EAT_2(2,s),吃掉后面的文本.
此执行结果在最前,不会干扰后面迭代.
BOOST_PP_IIF(c,BOOST_PP_FOR_2,BOOST_PP_TUPLE_EAT_4)//)若c非0则为BOOST_PP_FOR_2进入第二次循环,否则吃掉后面文本.
BOOST_PP_EXPR_IIF(c,o)(2,s),p,o,m
BOOST_PP_EXPR_IIF为c非0则返回o,否则返回空.
这里我们看非0的情况,→o(2,s)→BOOST_PP_SEQ_FOR_EACH_O_I s→BOOST_PP_SEQ_FOR_EACH_O_I(macro,data,seq,sz)→BOOST_PP_SEQ_FOR_EACH_O_I_DEC(macro,data,seq,BOOST_PP_DEC(sz))→(macro,data,BOOST_PP_IF(sz,BOOST_PP_SEQ_FOR_EACH_O_I_TAIL,BOOST_PP_SEQ_FOR_EACH_O_I_NIL)(seq),sz)→(macro,data,BOOST_PP_SEQ_FOR_EACH_O_I_TAIL(seq),sz)→(macro,data,seqTail,sz)
BOOST_PP_SEQ_FOR_EACH_O_I_TAIL为取seq除了Head之后的部分,这里已经运行过m一次了.
最后为BOOST_PP_FOR_2((macro,data,seqTail,sz),p,o,m)
此宏和BOOST_PP_FOR_1唯一的区别为p(2,s)变成p(3,s),3为传入macro的循环变量.
再来看c=0的情况.

指向类成员函数的指针

我们首先复习一下”指向函数的指针”如何使用?

[cpp] view plain copy

  void print()
  {
  }

  void (*pfun)(); //声明一个指向函数的指针,函数的参数是 void,函数的返回值是 void
  pfun = print; //赋值一个指向函数的指针
  (*pfun)(); //使用一个指向函数的指针

:) 比较简单,不是吗?为什么*pfun需要用()扩起来呢?
:) 因为*的运算符优先级比()低,如果不用()就成了*(pfun()).
:) 指向类的成员函数的指针不过多了一个类的限定而已!

[cpp] view plain copy

class A
{
    void speak(char *, const char *);
};

void main()
{
    A a;
    void (A::*pmf)(char *, const char *);//指针的声明
    pmf = &A::speak; //指针的赋值
}

 

一个指向类A 成员函数的指针声明为:
void (A::*pmf)(char *, const char *);

声明的解释是:pmf是一个指向A成员函数的指针,返回无类型值,函数带有二个参数,参数的类型分别是char *和const char *。除了在星号前增加A::,与声明外部函数指针的方法一样。一种更加高明的方法是使用类型定义:例如,下面的语句定义了PMA是一个指向类A成成员函数的指针,函数返回无类型值,函数参数类型为char *和const char *:

typedef void(A::*PMA)(char *,const char *);

PMA pmf= &A::strcat;//pmf是 PMF类型(类A成员指针)的变量

 

下面请看关于指向类的成员函数的使用示例:

#include <iostream> 

using namespace std; 

class Animal
{
public:
    /*这里稍稍注意一下,我将speak()函数设置为普通的成员函数,而hello()函数设置为虚函数*/
    int value;
    void speak()
    {
        cout << "I am an animal!" << endl;
        printf("%d\n", &Animal::speak); /*在这里验证一下,输出一下地址就知道了!*/
    }
    virtual void hello()
    {
        cout << "Animal say \"Hello\"" << endl;
    }
    Animal()
    {
        value = 1;
    }

};

class Bunny : public Animal
{
public:
    void speak()
    {
        cout << "I am bunny!" << endl;
    }
    virtual void hello()
    {
        cout << "bunny say \"hello!\"" << endl;
    }
    Bunny()
    {
        value = 2;
    }
};

typedef void (Animal::*p)();//定义指向Animal类无参数无返回值的成员函数的指针
typedef void (Bunny::*q)();//定义指向Bunny类的无参数无返回值的指针

int main()
{
    Animal pe;
    int i = 1;
    p ip;
    ip = &Animal::speak; //ip指向Animal类speak函数
    (pe.*ip)(); //这个是正确的写法!

                //--------------------------------------------
                // result : I am an animal!
                // XXXXXXXXXX(表示一段地址)
                //--------------------------------------------

                /*
                *下面是几种错误的写法,要注意!
                * pe.*ip();
                * pe.(*ip)();
                * (pe.(*ip))();
                */

    Bunny bzt;

    q iq = (void (Bunny::*)())ip; //强制转换
    (bzt.*iq)();

    //--------------------------------------------
    // result : I am an animal!
    // XXXXXXXXXX(表示一段地址)
    //--------------------------------------------

    /* 有人可能会问了:ip明明被强制转换成了Bunny类的成员函数的指针,为什么输出结果还是:
    * I am an animal!在C++里面,类的非虚函数都是采用静态绑定,也就是说类的非虚函数在编译前就已经
    *确定了函数地址!ip之前就是指向Animal::speak函数的地址,强制转换之后,只是指针类型变了,里面
    *的值并没有改变,所以调用的还是Animal.speak函数,细心的家伙会发现,输出的地址都是一致的.
    *这里要强调一下:对于类的非静态成员函数,c++编译器会给每个函数的参数添加上一个该类的指针this,这也
    *就是为什么我们在非静态类成员函数里面可以使用this指针的原因,当然,这个过程你看不见!而对于静态成员
    *函数,编译器不会添加这样一个this。
    */

    iq = &Bunny::speak; /*iq指向了Bunny类的speak函数*/
    ip = (void (Animal::*)())iq; /*ip接收强制转换之后的iq指针*/
    (bzt.*ip)();

    //--------------------------------------------
    // result : I am bunny!
    //--------------------------------------------

    (bzt.*iq)();//这里我强调一下,使用了动态联编,也就是说函数在运行是才确定函数地址!

                //--------------------------------------------
                // result : I am bunny!
                //--------------------------------------------

                /*这一部分就没有什么好讲的了,很明白了!由于speak函数是普通的成员函数,在编译时就知道
                *到了Bunny::speak的地址,因此(bzt.*ip)()会输出“I am bunny!”,即使iq被强制转换
                *成(void (Animal::*)())类型的ip,但是其值亦未改变,(bzt.*iq)()依然调用iq指向处的函数
                *即Bunny::speak.
                */

                /*好了,上面讲完了普通成员函数,我们现在来玩一点好玩的,现在来聊虚函数*/
    ip = &Animal::hello; /*让ip指向Animal::hello函数*/
    (pe.*ip)();

    //--------------------------------------------
    // result : Animal say "Hello"
    //--------------------------------------------

    (bzt.*ip)();

    //--------------------------------------------
    // result : bunny say "Hello"
    //--------------------------------------------

    /*咦,这就奇怪了,为何与上面的调用结果不类似?为什么两个调用结果不一致?伙伴们注意了:
    *speak函数是一个虚函数,前面说过虚函数并不是采用静态绑定的,而是采用动态绑定,所谓动态
    *绑定,就是函数地址得等到运行的时候才确定,对于有虚函数的类,编译器会给我们添加一个指针
    *vptr,指向一个虚函数表vptl,vptl里面存放着虚函数的地址,子类继承父类的时候,也会继承这样
    *一个指针,如果子类复写了虚函数,那么该表中该虚函数地址将会由父类的虚函数地址替换成子类虚
    *函数地址,编译器会把(pe.*ip)()转化成为(pe.vptr[1])(pe),加上动态绑定,结果会输出:
    * Animal say "Hello"
    *(bzt.*ip)()会被转换成(bzt.vptr[1])(pe),自然会输出:
    * bunny say "Hello"
    *ps:这里我没法讲得更详细,因为解释起来肯定是很长很长的,感兴趣的话,我推荐两本书你去看一看:
    * 第一本是侯捷老师的<深入浅出MFC>,里面关于c++的虚函数特性讲的比较清楚;
    * 第二本是侯捷老师翻译的<深度探索C++对象模型>,一听名字就知道,讲这个就更详细了;
    *当然,不感兴趣的同学这段解释可以省略,对与使用没有影响!
    */

    iq = (void (Bunny::*)())ip;
    (bzt.*iq)();

    //--------------------------------------------
    // result : bunny say "Hello"
    //--------------------------------------------

    system("pause");
    return 0;
}

 

自制四菱天线接收DTMB(地面数字电视)信号

本文介绍自制四菱天线的方法,该四菱天线适合接收地面数字电视信号。经实际测试四菱天线接收效果优于五单元八木天线,加装反射板的四菱天线接收效果优于七单元八木天线。因此在当地电视信号不是太弱的情况下最好自制四菱天线来接收,相对于八木天线来说,四菱天线制作、调试更简单。

自制四菱天线示意图:

自制四菱天线接收地面数字电视信号

四个菱形的每条边长12厘米

制作时注意图中箭头标示的走向,由A点开始,先弯折一个12厘米段,再弯折一个24厘米段,再经过两个12厘米段,然后又是一个24厘米段并与之前的24厘米段相交,交点不连接要绝缘。之后又是一个12厘米段到达B点,继续弯折直至回到A点。

AB两点为馈电点,用同轴电缆直接连接。

制作四菱天线的材料可以采用直径几毫米的铜芯电线剥皮使用,或者其它的金属线、金属条,甚至是铁丝都可以。使用绝缘材料为四菱天线做个支撑架防止其变形。

把四菱天线用同轴电缆与电视机连接,试试效果吧,调整四菱天线的方位直到信号最强的位置。

四菱天线垂直放置为接收水平极化波;如图水平放置则是接收垂直极化波。在室内等场合有反射波的情形下,四菱天线倾斜放置也可能获得较好效果。

四菱天线尺寸的计算

无论是单菱形天线、双菱形天线还是四菱形天线,每个菱形的周长均为一个波长,据此可以根据需要的频率计算出菱形的边长。如按上述取边长12厘米,则中心频率约624兆赫(不考虑波长缩短系数等问题)。

四菱天线增益的提升

如果四菱天线不能满足接收要求,可以为其加装反射板(网),信号仍不好再加装引向器。

加装反射板(网):
取一块比四菱天线略大的金属板,对于上述边长12厘米的尺寸,金属板可以取70×20厘米,放置于四菱天线后方约8厘米位置,实际距离测试时细调。若是采用金属网,网格大小应该小于十分之一波长,多频点接收时以最高频点计算。

加装引向器:(如果是用于单频点接收,引向器菱形边长可以是λ/4×0.8;如果是用于宽频带接收,引向器的边长应该是最高频点λ/4×0.8)
制作四个边长约9.6厘米的菱形,分别放置于四菱天线的四个菱形前方约18厘米处,实际距离测试时细调。加装引向器将使四菱天线辐射角变窄,因此调试时会发现方向性更强。

How to config cppan.yml AND CMakeLists.txt ? with static lib & cxx compiler /MT

I check-out the project “tessaract” and “leptonica” to local disk. But it use dynamic link (dll) by default. I need a static link, so I make some changes on the file “cppan.yml” AND “CMakeLists.txt”.

 

cppan.yml:

local_settings:
    generator: Visual Studio 14 2015
    use_shared_libs: false
    silent: false
    copy_import_libs: true
    short_local_names: true
    build:
        cxx_compiler_flags: /MT
        cxx_compiler_flags_debug: /MTd
        c_flags: /W0
        cxx_flags: /W0
        toolset: v140_xp
        type: library
        library_type: static
        use_shared_libs: false
        silent: false
        storage_dir: D:/.cppan/

projects:
    libleptonica:
        static_only: true
        shared_only: false
        type: lib
        export_all_symbols: true

...

 

I’v set v140_xp,but it isn’t effective. Then change “CMakeLists.txt” like this:

...

set(CMAKE_CXX_FLAGS_DEBUG "/MTd /Zi /Ob0 /Od /RTC1" CACHE STRING "" FORCE)
set(CMAKE_CXX_FLAGS_RELEASE "/MT /O2 /Ob2 /DNDEBUG" CACHE STRING ""FORCE)
set(CMAKE_GENERATOR_TOOLSET "v140_xp" CACHE STRING "Platform Toolset" FORCE)

...

 

Angular5 Application running issues in IE11 (IE11 Angular5 发生错误SCRIPT5022: Exception thrown and not caught 未捕获的异常)

src:
https://stackoverflow.com/questions/45353619/angular4-application-running-issues-in-ie11

 

 

I am building a Angular5 project using Angular CLI (1.7.3). It runs perfectly in Chrome (Version 59.0.3071.115) and firefox(54.0.1) but when I tried to use IE11 (Verison 11.0.9600.18738) nothings shows up and when I open the develper mode in IE, it shows me the following Error:

SCRIPT5022: Exception thrown and not caught
File: polyfills.bundle.js, Line: 829, Column: 34

And the detailed Error message is following:

enter image description here

 

==> 解决方案:

un commented the following line of codes like this:

/** IE9, IE10 and IE11 requires all of the following polyfills. **/
import 'core-js/es6/symbol';
import 'core-js/es6/object';
import 'core-js/es6/function';
import 'core-js/es6/parse-int';
import 'core-js/es6/parse-float';
import 'core-js/es6/number';
import 'core-js/es6/math';
import 'core-js/es6/string';
import 'core-js/es6/date';
import 'core-js/es6/array';
import 'core-js/es6/regexp';
import 'core-js/es6/map';
import 'core-js/es6/set';

如何获取到微信的openid

https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842

 

微信内置浏览器获取用户的微信openid,微信公众平台OAuth2.0网页授权
———————————————————————————————–
首先你的网站入口必须是微信服务号(开通认证、拥有获取用户openid权限;订阅号是不行的)。
网页通过微信的Oauth2认证链接。

然后通过服务号菜单链接进入网站,如: https://open.weixin.qq.com/connect/oauth2/authorize?appid=YOURAPPID&redirect_uri=http://YOUWEBSITE/oauth2.php&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect

自己根据微信提供的oauth2接口文档,编写oauth2.php内容,(网上有相关官方SDK)
按下面的步骤:
1.获取用户openid
2.获取accesson_token
3.获取用户信息
4.授权注册用户,若已存在该用户则直接进入网站。

 

http://huangqiqing123.iteye.com/blog/2005770
http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html

IIS7.5+ 打开PUT方法上传文件

  1. 安装WebDAV、windows身份验证(以win10为例)
    控制面板–程序和功能–启用或关闭windows功能
    Internet Infomation Services–万维网服务–安全性,勾上:windows身份验证
    Internet Infomation Services–万维网服务–常见HTTP功能,勾上:WebDAV发布
  2. 配置WebDAV
    打开IIS管理器,点击网站根目录
    打开WebDAV创作规则,
    1)启用WebDAV
    2)添加创作规则,选择“全部内容”、“所有用户”、勾上权限“读取”、“源”、“写入”
    3)打开WebDAV设置,
    允许谓词筛选、允许文件扩展名筛选、允许隐藏段筛选、允许匿名属性查询、允许属性查询具有无限深度,设置为TRUE
    允许自定义属性,设置为FALSE
  3. 配置windows身份验证
    打开身份验证,启用Windows身份验证、匿名身份验证
  4. 打开模块,确定WebDavModule在模块中
  5. 打开处理程序映射,确定有*映射到WebDavModule

 

参考的web.config文件配置

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <modules>
            <remove name="WebDAVModule" />
            <add name="WebDAVModule" />
        </modules>
    <handlers>
	<add name="WebDAVModule" path="*" verb="*" modules="WebDAVModule" resourceType="File" requireAccess="None" />
    </handlers>
    </system.webServer>
</configuration>

 

 

配置好后,用以下代码进行测试(C#):

using System;
using System.Net;

namespace Test
{
    class Program
    {

        static void Main(string[] args)
        {
            WebClient _webClient = new WebClient();
            _webClient.Credentials = new NetworkCredential("huqingyu", "pwd1234567");
            Uri _uri = new Uri(@"http://192.168.8.166/test.txt");

            _webClient.UploadProgressChanged += _webClient_UploadProgressChanged;
            _webClient.UploadFileCompleted += _webClient_UploadFileCompleted;


            _webClient.UploadFileAsync(_uri, "PUT", @"o:\1.txt");
            Console.ReadKey();
        }
        private static void _webClient_UploadFileCompleted(object sender, UploadFileCompletedEventArgs e)
        {
            Console.WriteLine("Upload Completed...");
        }

        private static void _webClient_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
        {
            Console.WriteLine($"{e.ProgressPercentage}:{e.BytesSent}/{e.TotalBytesToSend}");
        }
    }
}

 

install chrome os

1.设置好Boot,EFI启用。安装好Windows 操作系统在原500G的硬盘上。
2.下载CloudReady或其他版本的Chrome OS。点击这里去下载->
3.制作USB启动盘。Chrome 浏览器安装Chromebook Recovery Utility,Mac,PC版本的Chrome都支持:(1).Chrome 安装 Chrome Web Store地址, 安装:

step_cr_1


(2)选择Local image 浏览到刚刚下载的CloudReady  镜像文件cloudready-free-44.1.9.bin.zip

step_cr_2


(3)写入U盘,注意U盘需要大于4G,建议8G以上。

step_cr_3

 

4.U盘系统盘制作完成后就可以安装,开机进入Boot选择界面,选择U盘安装介质。
5,进入CloudReay安装界面后,Ctrl + Alt + F2进入命令行界面,
使用用户
chronos,密码chrome,查看安装目标磁盘。 

1 sudo fdisk -l

找到目标盘,比如我的20g的SSD 是/dev/sdb

1 sudo chromeos-install –dst /dev/sdb

6.等待安装完成,Ctrl + Alt + F1 回到图型界面,重启电脑。
7.开机使用选择BOOT的方式可以进入Chrome OS。

mychrome

Chrome Agent

win7
“Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; rv:11.0) like Gecko”

WIN8:
“Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; .NET4.0E; .NET4.0C)”

win8.1
“Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; Touch; .NET4.0E; .NET4.0C; Tablet PC 2.0; rv:11.0) like Gecko”

win10
“Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; rv:11.0) like Gecko”