Android 通过应用包名启动外部应用

void startFit(String packageName)
{
    PackageManager packageManager = this.getApplicationContext().getPackageManager();
    PackageInfo pi = null;
    try {
        pi = packageManager.getPackageInfo(packageName, 0);
        if(pi == null)
        {
            Toast.makeText(FullscreenLauncher.this, "应用未安装", Toast.LENGTH_SHORT).show();
            return;
        }
    } catch (PackageManager.NameNotFoundException e) {
    }
    Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);
    resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);
    resolveIntent.setPackage(pi.packageName);
    List<ResolveInfo> apps = packageManager.queryIntentActivities(resolveIntent, 0);
    ResolveInfo ri = apps.iterator().next();
    if (ri != null ) {
        String className = ri.activityInfo.name;
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        ComponentName cn = new ComponentName(packageName, className);
        intent.setComponent(cn);
        this.getApplicationContext().startActivity(intent);
    }
}

Redmine与Gitblit联动(二)

如果git仓库在本机上就更方便了,不用迁出直接配置成对应的git仓库地址,如果在仓库另一台机子上,则需要如下操作做一个git mirror
新建一个 gitrespo ,然后将所属用户改成www-data以完成权限设定
然后  git clone –mirror
299 sudo mkdir /gitrespo
300 ll
301 cd /gitrespo/
302 mv /gitrespo/ /gitrepos
303 sudo mv /gitrespo/ /gitrepos
304 ll
305 cd ..
306 ll
307 cd /gitrepos/
308 ll
309 chmod -R 777 ./
310 sudo chmod -R 777 ./
311 sudo chown -R www-data:www-data gitrepos
312 sudo chown -R www-data:www-data ./
313 ll
314 sudo -u www-data -H git clone –mirror git://192.168.8.18/FitPose.git
319 cd FitPose.git/
320 git fetch
以上完成了迁出与git mirror操作,接下来就需要在Redmine上进行配置仓库的地址

修改git源代码的 git adapter.rb 主要是以下这段

def branches
return @branches if @branches
@branches = []
cmd_args = %w|branch --no-color --verbose --no-abbrev|
git_cmd(cmd_args) do |io|
io.each_line do |line|
branch_rev = line.match('\s*(\*?)\s*(.*?)\s*([0-9a-f]{40}).*$')
next unless branch_rev
bran = GitBranch.new(branch_rev[2])
bran.revision = branch_rev[3]
bran.scmid = branch_rev[3]
bran.is_default = ( branch_rev[1] == '*' )
@branches << bran
end
end
logger.info "1. fetch --all"
cmd_args = %w|fetch --all|
git_cmd(cmd_args) do |io|
logger.info io.readlines
end
logger.info "2. reset --hard origin"
cmd_args = %w|reset --hard origin|
git_cmd(cmd_args) do |io|
logger.info io.readlines
end
@branches.sort!
rescue ScmCommandAborted
nil
end

 

def git_cmd(args, options = {}, &block)
repo_path = root_url || url
full_args = ['-C', repo_path + '/..', '--git-dir', repo_path]
if self.class.client_version_above?([1, 7, 2])
full_args << '-c' << 'core.quotepath=false'
full_args << '-c' << 'log.decorate=no'
end
full_args += args
cmdline = self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' ')
logger.info cmdline
ret = shellout(
cmdline,
options,
&block
)
if $? && $?.exitstatus != 0
raise ScmCommandAborted, "git exited with non-zero status: #{$?.exitstatus}"
end
logger.info "execute end"
ret
end
private :git_cmd

以下是修改后的 git_adapter.rb
git_adapter.rb
修改替换后,重启redmine即可
342 ./ctlscript.sh restart apache

Redmine与Gitblit联动

配置好redmine后,访问redmine地址,用管理员帐号登录,点击顶上的管理TAB菜单,左边的选项中选择信息,可以看到当前Redmine的各种环境的版本,本次搭建的最新版本(2019-11-07)如下

Environment:
Redmine version 4.0.5.stable
Ruby version 2.5.7-p206 (2019-10-01) [x86_64-linux]
Rails version 5.2.3
Environment production
Database adapter Mysql2
Mailer queue ActiveJob::QueueAdapters::AsyncAdapter
Mailer delivery smtp
SCM:
Subversion 1.12.2
Git 2.19.1
Filesystem

Step1:在管理->配置->API 中,勾选开启Webservice

Step2:在管理->配置 ->版本库中,开启自动获取程序变更与WebService,并生成一个key密钥。因为是内网布署的,所以亮出密钥了:P

Step3:在Gitblit目录中配置apkkey与url
修改${gitblit-1.8.0-dir}/data/groovy/redmine-fetch.groovy文件以下行

/* specify the URL of your Redmine instance here */
def redmineURL = "http://192.168.8.31:8080/redmine/"
/* specify the URL of your Redmine instance here */
def apiKey = "LNOcmjUSy0Dxxu3Dpjxi"

Step4:在Gitblit版本库->编辑->receive 中Selected加入redmine–fetch

Step5:待续
参考https://blog.csdn.net/weixin_33953384/article/details/91693565

OpenCV 下 op::putText 显示中文的方法

//头上加入
#include <hstring.h>
//方法开始
void GetStringSize(HDC hDC, const char* str, int* w, int* h)
{
    SIZE size;
    GetTextExtentPoint32A(hDC, str, strlen(str), &size);
    if (w != 0) * w = size.cx;
    if (h != 0) * h = size.cy;
}
void paDrawString(cv::Mat& dst, const char* str, cv::Point org, cv::Scalar color, int fontSize, bool italic, bool underline)
{
    CV_Assert(dst.data != 0 && (dst.channels() == 1 || dst.channels() == 3));
    int x, y, r, b;
    if (org.x > dst.cols || org.y > dst.rows) return;
    x = org.x < 0 ? -org.x : 0;
    y = org.y < 0 ? -org.y : 0;
    LOGFONTA lf;
    lf.lfHeight = -fontSize;
    lf.lfWidth = 0;
    lf.lfEscapement = 0;
    lf.lfOrientation = 0;
    lf.lfWeight = 5;
    lf.lfItalic = italic;	//斜体
    lf.lfUnderline = underline;	//下划线
    lf.lfStrikeOut = 0;
    lf.lfCharSet = DEFAULT_CHARSET;
    lf.lfOutPrecision = 0;
    lf.lfClipPrecision = 0;
    lf.lfQuality = PROOF_QUALITY;
    lf.lfPitchAndFamily = 0;
//此处可定义使用的字体
    strcpy(lf.lfFaceName, "宋体");
    HFONT hf = CreateFontIndirectA(&lf);
    HDC hDC = CreateCompatibleDC(0);
    HFONT hOldFont = (HFONT)SelectObject(hDC, hf);
    int strBaseW = 0, strBaseH = 0;
    int singleRow = 0;
    char buf[1 << 12];
    strcpy(buf, str);
    //处理多行
    {
        int nnh = 0;
        int cw, ch;
        const char* ln = strtok(buf, "\n");
        while (ln != 0)
        {
            GetStringSize(hDC, ln, &cw, &ch);
            strBaseW = std::max(strBaseW, cw);
            strBaseH = std::max(strBaseH, ch);
            ln = strtok(0, "\n");
            nnh++;
        }
        singleRow = strBaseH;
        strBaseH *= nnh;
    }
    if (org.x + strBaseW < 0 || org.y + strBaseH < 0)
    {
        SelectObject(hDC, hOldFont);
        DeleteObject(hf);
        DeleteObject(hDC);
        return;
    }
    r = org.x + strBaseW > dst.cols ? dst.cols - org.x - 1 : strBaseW - 1;
    b = org.y + strBaseH > dst.rows ? dst.rows - org.y - 1 : strBaseH - 1;
    org.x = org.x < 0 ? 0 : org.x;
    org.y = org.y < 0 ? 0 : org.y;
    BITMAPINFO bmp = { 0 };
    BITMAPINFOHEADER& bih = bmp.bmiHeader;
    int strDrawLineStep = strBaseW * 3 % 4 == 0 ? strBaseW * 3 : (strBaseW * 3 + 4 - ((strBaseW * 3) % 4));
    bih.biSize = sizeof(BITMAPINFOHEADER);
    bih.biWidth = strBaseW;
    bih.biHeight = strBaseH;
    bih.biPlanes = 1;
    bih.biBitCount = 24;
    bih.biCompression = BI_RGB;
    bih.biSizeImage = strBaseH * strDrawLineStep;
    bih.biClrUsed = 0;
    bih.biClrImportant = 0;
    void* pDibData = 0;
    HBITMAP hBmp = CreateDIBSection(hDC, &bmp, DIB_RGB_COLORS, &pDibData, 0, 0);
    CV_Assert(pDibData != 0);
    HBITMAP hOldBmp = (HBITMAP)SelectObject(hDC, hBmp);
    //color.val[2], color.val[1], color.val[0]
    SetTextColor(hDC, RGB(255, 255, 255));
    SetBkColor(hDC, 0);
    //SetStretchBltMode(hDC, COLORONCOLOR);
    strcpy(buf, str);
    const char* ln = strtok(buf, "\n");
    int outTextY = 0;
    while (ln != 0)
    {
        TextOutA(hDC, 0, outTextY, ln, strlen(ln));
        outTextY += singleRow;
        ln = strtok(0, "\n");
    }
    uchar* dstData = (uchar*)dst.data;
    int dstStep = dst.step / sizeof(dstData[0]);
    unsigned char* pImg = (unsigned char*)dst.data + org.x * dst.channels() + org.y * dstStep;
    unsigned char* pStr = (unsigned char*)pDibData + x * 3;
    for (int tty = y; tty <= b; ++tty)
    {
        unsigned char* subImg = pImg + (tty - y) * dstStep;
        unsigned char* subStr = pStr + (strBaseH - tty - 1) * strDrawLineStep;
        for (int ttx = x; ttx <= r; ++ttx)
        {
            for (int n = 0; n < dst.channels(); ++n) {
                double vtxt = subStr[n] / 255.0;
                int cvv = vtxt * color.val[n] + (1 - vtxt) * subImg[n];
                subImg[n] = cvv > 255 ? 255 : (cvv < 0 ? 0 : cvv);
            }
            subStr += 3;
            subImg += dst.channels();
        }
    }
    SelectObject(hDC, hOldBmp);
    SelectObject(hDC, hOldFont);
    DeleteObject(hf);
    DeleteObject(hBmp);
    DeleteDC(hDC);
}

调用时替换原有的 cv:putText

  paDrawString(*show_img, labelstr, pt_text, black_color, 12, 0, 0);
  //cv::putText(*show_img, labelstr, pt_text, cv::FONT_HERSHEY_COMPLEX_SMALL, font_size, black_color, 2 * font_size, CV_AA);

yarn VS npm 的优势

      安装速度快 。

  1. 并行安装:无论 npm 还是 Yarn 在执行包的安装时,都会执行一系列任务。npm 是按照队列执行每个 package,也就是说必须要等到当前 package 安装完成之后,才能继续后面的安装。而 Yarn 是同步执行所有任务,提高了性能。
  2. 离线模式:如果之前已经安装过一个软件包,用Yarn再次安装时之间从缓存中获取,就不用像npm那样再从网络下载了。
  3. 安装版本统一:为了防止拉取到不同的版本,Yarn 有一个锁定文件 (lock file) 记录了被确切安装上的模块的版本号。每次只要新增了一个模块,Yarn 就会创建(或更新)yarn.lock 这个文件。这么做就保证了,每一次拉取同一个项目依赖时,使用的都是一样的模块版本。npm 其实也有办法实现处处使用相同版本的 packages,但需要开发者执行 npm shrinkwrap 命令。这个命令将会生成一个锁定文件,在执行 npm install 的时候,该锁定文件会先被读取,和 Yarn 读取 yarn.lock 文件一个道理。npm 和 Yarn 两者的不同之处在于,Yarn 默认会生成这样的锁定文件,而 npm 要通过 shrinkwrap 命令生成 npm-shrinkwrap.json 文件,只有当这个文件存在的时候,packages 版本信息才会被记录和更新。
  4. 更简洁的输出:npm 的输出信息比较冗长。在执行 npm install <package> 的时候,命令行里会不断地打印出所有被安装上的依赖。相比之下,Yarn 简洁太多:默认情况下,结合了 emoji直观且直接地打印出必要的信息,也提供了一些命令供开发者查询额外的安装信息。
  5. 多注册来源处理所有的依赖包,不管他被不同的库间接关联引用多少次,安装这个包时,只会从一个注册来源去装,要么是 npm 要么是 bower, 防止出现混乱不一致。
  6. 更好的语义化: yarn改变了一些npm命令的名称,比如 yarn add/remove,感觉上比 npm 原本的 install/uninstall 要更清晰。

FFMpeg 提取关键帧命令

ffmpeg.exe -i D:\DShare\f2.mp4 -vf select=’eq(pict_type\,I)’,setpts=’N/(25*TB)’ D:\DShare\output\%09d.jpg

Anaconda 安装 tensorflow

Anaconda 安装 tensorflow
pip install –upgrade -i https://pypi.tuna.tsinghua.edu.cn/simple –ignore-installed tensorflow
Anaconda 安装 tensorflowGPU
pip install –upgrade -i https://pypi.tuna.tsinghua.edu.cn/simple –ignore-installed tensorflow-gpu

Android ADB 命令行控制屏幕

禁用自动旋转
adb shell content insert --uri content://settings/system --bind name:s:accelerometer_rotation --bind value:i:0
启用自动旋转
adb shell content insert --uri content://settings/system --bind name:s:accelerometer_rotation --bind value:i:1
旋转屏幕
adb shell content insert --uri content://settings/system --bind name:s:user_rotation --bind value:i:1

旋转屏幕的值 可以为 0,1,2,3,对应四个方向

Ubuntu 16.04下 CPU 性能模式切换

查看CPU当前频率
cat /proc/cpuinfo | grep MHz
1、安装cpufrequtils:
sudo apt-get install cpufrequtils
2、查看当前cpu的状态:
cpufreq-info
3、把cpu调整到性能模式:
sudo cpufreq-set -g performance
 
 
使用上述方式,重启系统后又回到默认方式。修改默认模式:
 1、安装sysfsutils
sudo apt-get install sysfsutils
 
2、编辑/etc/sysfs.conf ,增加如下语句:
devices/system/cpu/cpu0/cpufreq/scaling_governor = performance
可选的有
1. performance:CPU维持最高时脉运行。
2. ondemand:程序运行时,直接调高时脉运行。(但不一定是调到最高,而是依程式需求)。没有运行时,调低时脉。
3. conservative:同上,但调整的方式,是一阶一阶地调整,而非直接调整。
4. powersave:CPU维持最低时脉运行
5. userspace:是由使用者自己定义,需要安装其他软件管理

NodeJS Request与文件上传下载流相关

本文转载自  https://segmentfault.com/a/1190000000385867

使用超简单

Request使用超简单,同时支持https和重定向。

var request = require('request');
request('http://www.google.com', function (error, response, body) {
  if (!error && response.statusCode == 200) {
    console.log(body) // 打印google首页
  }
})

任何响应都可以输出到文件流。

request('http://google.com/doodle.png').pipe(fs.createWriteStream('doodle.png'))

反过来,也可以将文件传给PUT或POST请求。未提供header的情况下,会检测文件后缀名,在PUT请求中设置相应的content-type

fs.createReadStream('file.json').pipe(request.put('http://mysite.com/obj.json'))

请求也可以pipe给自己。这种情况下会保留原content-typecontent-length

request.get('http://google.com/img.png').pipe(request.put('http://mysite.com/img.png'))

表单

request支持application/x-www-form-urlencodedmultipart/form-data实现表单上传。
x-www-form-urlencoded很简单:

request.post('http://service.com/upload', {form:{key:'value'}})

或者:

request.post('http://service.com/upload').form({key:'value'})

使用multipart/form-data不用操心设置header之类的琐事,request会帮你解决。

var r = request.post('http://service.com/upload')
var form = r.form()
form.append('my_field', 'my_value')
form.append('my_buffer', new Buffer([1, 2, 3]))
form.append('my_file', fs.createReadStream(path.join(__dirname, 'doodle.png'))
form.append('remote_file', request('http://google.com/doodle.png'))

HTTP认证

request.get('http://some.server.com/').auth('username', 'password', false);

request.get('http://some.server.com/', {
  'auth': {
    'user': 'username',
    'pass': 'password',
    'sendImmediately': false
  }
});

sendImmediately,默认为真,发送一个基本的认证header。设为false之后,收到401会重试(服务器的401响应必须包含WWW-Authenticate指定认证方法)。
sendImmediately为真时支持Digest认证。

OAuth登录

// Twitter OAuth
var qs = require('querystring')
  , oauth =
    { callback: 'http://mysite.com/callback/'
    , consumer_key: CONSUMER_KEY
    , consumer_secret: CONSUMER_SECRET
    }
  , url = 'https://api.twitter.com/oauth/request_token'
  ;
request.post({url:url, oauth:oauth}, function (e, r, body) {
  // Ideally, you would take the body in the response
  // and construct a URL that a user clicks on (like a sign in button).
  // The verifier is only available in the response after a user has
  // verified with twitter that they are authorizing your app.
  var access_token = qs.parse(body)
    , oauth =
      { consumer_key: CONSUMER_KEY
      , consumer_secret: CONSUMER_SECRET
      , token: access_token.oauth_token
      , verifier: access_token.oauth_verifier
      }
    , url = 'https://api.twitter.com/oauth/access_token'
    ;
  request.post({url:url, oauth:oauth}, function (e, r, body) {
    var perm_token = qs.parse(body)
      , oauth =
        { consumer_key: CONSUMER_KEY
        , consumer_secret: CONSUMER_SECRET
        , token: perm_token.oauth_token
        , token_secret: perm_token.oauth_token_secret
        }
      , url = 'https://api.twitter.com/1/users/show.json?'
      , params =
        { screen_name: perm_token.screen_name
        , user_id: perm_token.user_id
        }
      ;
    url += qs.stringify(params)
    request.get({url:url, oauth:oauth, json:true}, function (e, r, user) {
      console.log(user)
    })
  })
})

定制HTTP header

User-Agent之类可以在options对象中设置。在下面的例子中,我们调用github API找出某仓库的收藏数和派生数。我们使用了定制的User-Agent和https.

var request = require('request');
var options = {
    url: 'https://api.github.com/repos/mikeal/request',
    headers: {
        'User-Agent': 'request'
    }
};
function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        var info = JSON.parse(body);
        console.log(info.stargazers_count + " Stars");
        console.log(info.forks_count + " Forks");
    }
}
request(options, callback);

cookies

默认情况下,cookies是禁用的。在defaultsoptionsjar设为true,使后续的请求都使用cookie.

var request = request.defaults({jar: true})
request('http://www.google.com', function () {
  request('http://images.google.com')
})

通过创建request.jar()的新实例,可以使用定制的cookie,而不是request全局的cookie jar。

var j = request.jar()
var request = request.defaults({jar:j})
request('http://www.google.com', function () {
  request('http://images.google.com')
})

或者

var j = request.jar()
var cookie = request.cookie('your_cookie_here')
j.setCookie(cookie, uri, function (err, cookie){})
request({url: 'http://www.google.com', jar: j}, function () {
  request('http://images.google.com')
})

注意,setCookie至少需要三个参数,最后一个是回调函数。