设置ABP默认使用中文

ABP提供的启动模板, 默认使用是英文:

虽然可以通过右上角的菜单切换成中文, 但是对于国内项目来说, 默认使用中文是很正常的需求.
本文介绍了如何实现默认语言的几种方法, 希望能对ABP爱好者有所帮助, Let’s begin!

前期准备

使用ABP CLI创建一个名为AbpStudy的ASP.NET MVC项目:

abp new AbpStudy

关于MVC的启动模板可以看文档, 这里就不赘述.

使用ABP版本的是当前最新的v0.19, 后续版本应该也适用

方法1: 通过服务设置

该方法参考了此回答, 谢谢@maliming.

  1. 编辑AbpStudy.Web工程下的Startup.cs文件, 在Configure方法的开始增加一行代码:
        public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
        {
            app.ApplicationServices.GetService<ISettingDefinitionManager>().Get(LocalizationSettingNames.DefaultLanguage).DefaultValue = "zh-Hans";     // 默认使用中文
            app.InitializeApplication();
        }

该方法首先获取了SettingDefinitionManager的服务实例, 然后调用Get方法获取了默认语言的SettingDefinition, 然后设置了默认值”zh-Hans”, 即中文.

运行, 就会发现默认语言已经变成中文了:

怎么样, 非常简单吧?

关于ABP的Setting, 现在官方的文档还未写完. 等待官方文档完善后我会更新到文章里

方法2: 通过数据设置

虽然方法1非常简单, 但是因为是通过代码写死了默认语言, 如果想设置其他默认语言, 只能再次修改代码.

既然默认语言是通过Setting设置的, 那么我们可不可以通过数据设置默认语言呢?答案是肯定的.

ABP启动模板的数据库中有一个名为AbpSettings的表, 里面即是各种Setting的值.

我们可以向其中增加一条默认语言的记录:

INSERT INTO AbpSettings(Id, Name, Value, ProviderName)
Values(newid(), 'Abp.Localization.DefaultLanguage', 'zh-Hans', 'Global')

其中的Name的值即是方法1中LocalizationSettingNames.DefaultLanguage的值, 相当于默认语言Setting的一个Key.
插入后的结果:

把方法1中我们增加的那行代码删除后, 再次运行确认默认语言仍然是中文.

如果我们把记录中的”zh-Hans”改为”en”, 重新运行后默认语言就会切换成英文了.

方法3: 通过Seed设置

方法3实际上是方法2的一个改进: 我们利用了ABP提供了Seed系统(即可通过代码初始化系统的一些数据), 这样我们在正式上线项目时, 不需要再额外执行SQL语句来执行数据初始化了.

首先我们把AbpSettings表中我们手动插入的那条记录删除.

然后在AbpStudy.Domain工程的Settings文件夹中增加一个名为AbpStudySettingDataSeedContributor的类, 用来为Setting设置初始化数据. 类代码如下:

    public class AbpStudySettingDataSeedContributor : IDataSeedContributor, ITransientDependency
    {
        private readonly IGuidGenerator _guidGenerator;
        private readonly ISettingRepository _settingRepository;

        public AbpStudySettingDataSeedContributor(IGuidGenerator guidGenerator, ISettingRepository settingRepository)
        {
            _settingRepository = settingRepository;
            _guidGenerator = guidGenerator;
        }

        public async Task SeedAsync(DataSeedContext context)
        {
            await _settingRepository.InsertAsync(new Setting(
                _guidGenerator.Create(),
                LocalizationSettingNames.DefaultLanguage,
                "zh-Hans",
                GlobalSettingValueProvider.ProviderName
            ));
        }

该类注入GuidGenerator用来生成GUID, 和SettingRepository用来向AbpSettings表插入数据.

SeedAsync方法中使用InsertAsync方法插入了默认语言的记录, 记录的值与方法2中SQL中是一致的.

然后我们运行AbpStudy.DbMigrator工程, 这是启动模板附带的一个用来执行数据库迁移的一个工具, 它会扫描到我们刚写的AbpStudySettingDataSeedContributor类并调用它, 从而完成数据初始化.

AbpStudy.DbMigrator工程有自己的数据库连接串, 定义在appsettings.json文件中, 别忘了将它修改成与Web工程中的一样.

运行DbMigrator截图:

再次查看AbpSettings表中的数据, 发现记录已经插入了, 与我们使用SQL语句插入的一样, 所以默认中文也同样可以生效.

禁用其他语言

如果你的项目不用考虑多语言, 那么右上角的语言切换菜单就显得有点多余了, 我们可以通过以下修改禁用其他语言:

修改AbpStudy.Web工程下的AbpStudyWebModule类, 将ConfigureLocalizationServices方法中其他语言的options.Languages.Add(...)代码删除, 只保留中文的即可:

        private void ConfigureLocalizationServices()
        {
            Configure<AbpLocalizationOptions>(options =>
            {
                options.Resources
                    .Get<AbpStudyResource>()
                    .AddBaseTypes(
                        typeof(AbpUiResource)
                    );

                //options.Languages.Add(new LanguageInfo("cs", "cs", "Čeština"));
                //options.Languages.Add(new LanguageInfo("en", "en", "English"));
                //options.Languages.Add(new LanguageInfo("pt-BR", "pt-BR", "Português"));
                //options.Languages.Add(new LanguageInfo("tr", "tr", "Türkçe"));
                options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
            });
        }

再次运行, 发现右上角语言切换的菜单就不见了, 完美!

关于ABP框架设置默认语言的方法就介绍到这, 示例工程放到GITHUB中.
Happy Coding!

玩转SpringBoot 2 之项目启动篇

SpringBoot 启动方式有哪些?

SpringBoot 有4种方式进行启动,具体方式如下:

  1. IDEA方式启动
  2. Eclipse 方式启动
  3. Maven 启动方式
  4. 通过SpringBoot 程序 jar 包启动

每种启动方式操作演示

1 IDEA方式启动

选中我们的 SpringBoot 项目,通过下图操作方式进行正常启动 或者 Debug 方式进行启动。

也可以通过打开 SpringBoot 的启动类,右击选择 Run StartdemoApplication 进行正常方式启动,选择 Debug StartdemoApplication 进行 Debug 方式的启动。

2 Eclipse 启动方式

通过Eclipse 创建好我们的 SpringBoot 项目后,选中项目然后点击 Run As,然后在点击 Spring Boot App 就可以启动 SpringBoot 项目。具体操作: 选择项目-> Run As-> Spring Boot App 具体操作如下图:

也可以通过Debug 方式进行启动,方式和上面一样。不同的是我们要选择 Debug As,具体操作: 选择项目-> Run As-> Debug As 具体操作如下图:

除了通过上面选择项目的方式,我们还可以点击springboot 启动类,通过执行main方法来启动项目。具体操作如下图:
点击 Java Application 和 Sprign Boot App 效果是一样的。

3 Maven 启动方式

通过cmd 进入到我们 SpringBoot 项目的根目录中,然后执行 mvn spring-boot:run 就可以运行我们的 SpringBoot 项目啦。

startdemo 项目目录下内容如下:

4 通过 SpringBoot 程序 jar 包启动

首先将程序打包并且跳过单元测试 mvn clean package -Dmaven.test.skip=true,然后将打好的jar包通过 java -jar xxx.jar 来启动。

具体操作方式如下图:

执行完打包命令后在 targer目录下会有一个可执行的 jar。

执行 java -jar startdemo-0.0.1-SNAPSHOT.jar 如下图所示:

指定 端口

通过 java -jar -Dserver.prot 可以指定SpringBoot项目启动的端口号,具体操作如下:
java -jar -Dserver.prot=端口号 jar包名称

指定配置文件进行启动

在 SpringBoot 的 application.ym 配置文件中配置如下图配置:

创建我们开发环境的配置 具体配置如下图:

创建我们的正式环境配置具体配置如下图:

正常启动 SpringBoot 项目会以后缀为dev的配置文件进行启动

我们可以通过 java -jar -Dspring.profiles.active 来动态执行具体执行那个后缀配置文件。具体操作如下:

将 SpringBoot 执行 mvn clean package -Dmaven.test.skip=true, 如下图所示:

执行 java -jar -Dspring.profiles.active=配置文件后缀 jar包名称 如下图所示:

小结

工作中你可以根据需要采用上述方式任意启动方式来启动SpringBoot,一般情况下根据你使用的开发工具采用 IDEA方式启动或Eclipse 方式启动。如果使用 SpringCloud 的方式情况下对于不需要进行开发而且必须启动的项目可以使用 java -jar的方式。

Python+Selenium – Web自动化测试(二):元素定位

前言

前面已经把环境搭建好了,现在开始使用 Selenium 中的 Webdriver 框架编写自动化代码脚本,我们常见的在浏览器中的操作都会有相对应的类方法,这些方法需要定位才能操作元素,不同网页的元素也不同,可以根据自己情况选择使用类方法。下面开始学习元素定位

New一个后缀为.py的Python文件写一段代码,先感受一下代码吧!写完以后Ctrl+Shift+F10运行代码。

# -*- coding:utf-8 -*-
from selenium import webdriver   # 从selenium模块中导入webdrive类
 driver = webdriver.Chrome()   # 定义新的变量名,打开浏览器  driver.maximize_window() # 浏览器窗口最大化
 driver.get("https://baidu.com")  # 打开百度网址 # 定位百度首页的搜索框,然后在搜索框中输入Selenium
driver.find_element_by_id('kw').send_keys('Selenium') # 定位百度首页的百度一下,然后点击一下
driver.find_element_by_id('su').click()

浏览不同的网页元素也不同,可以选择使用最合适你的情况的方法使用,下面介绍Selenium其中的16种定位方法:

WebDriver8种基本元素定位方式:

id定位:find_element_by_id(self, id_)
name定位:find_element_by_name(self, name)
class定位:find_element_by_class_name(self, name)
tag定位:find_element_by_tag_name(self, name)
link定位:find_element_by_link_text(self, link_text)
partial_link定位:find_element_by_partial_link_text(self, link_text)
xpath定位:find_element_by_xpath(self, xpath)
css定位:find_element_by_css_selector(self, css_selector)

这8种其实和上面的8种一样的只不过后者是以复数形式出现(这些复数定位方法会返回一个列表的值):

id复数定位:find_elements_by_id(self, id_)
name复数定位:find_elements_by_name(self, name)
class复数定位:find_elements_by_class_name(self, name)
tag复数定位:find_elements_by_tag_name(self, name)
link复数定位:find_elements_by_link_text(self, text)
partial_link复数定位:find_elements_by_partial_link_text(self, link_text)
xpath复数定位:find_elements_by_xpath(self, xpath)
css复数定位:find_elements_by_css_selector(self, css_selector)
8种基本定位介绍,掌握这8种基本可以横着走了:
以百度为例这张图是百度输入框的,一眼看过去就看到了三种定位方式:

1. 通过id定位:

 

driver.find_element_by_id('kw').send_keys('Selenium')

2. 通过name定位:

driver.find_element_by_name('wd').send_keys('Selenium')

3. 通过class定位:

driver.find_element_by_class_name('s_ipt').send_keys('Selenium')

4. 通过tag定位:

tag其实是通过标签名去定位的,一般情况下一个页面会存在大量相同的标签名这种定位方式不是很实用,所以用的也就比较少;

driver.find_element_by_tag_name('input').send_keys('Selenium')

5. 通过link_text定位:

HTML代码中以a标签开头的一般是超链接元素的标记可以使用link_text可以精准匹配;

<a href="http://news.baidu.com" name="tj_trnews" class="mnav">新闻</a>

driver.find_element_by_link_text('新闻').click()

6. 通过partial_link_text定位:

这种定位方式和上面的一样也是通过HTML的a标签定位,唯一不同的这种方式是模糊匹配,当超链接名称过长时,这时候可以使用模糊匹配方式,截取其中一部分字符串就可以了;

driver.find_element_by_partial_link_text('').click()

7. 通过xpath定位:

xpath是XML路径语言,它可以用来确定xml文档中的节点元素位置,通过元素的路径来完成对元素的查找。HTML就是XML的一种实现方式,可以自行选择绝对路径和相对路径作为匹配的路径

双斜杠(//) = 相对路径,可以选择任何一个节点作为起始点

单斜杆(/) = 绝对路径,就是从网页代码的html开始一层一层找

(*)= 匹配任何元素节点;(@*)= 匹配任何属性节点

  1. xpath可以使用id,name,class元素进行定位:


    # 使用xpath方法的id属性定位'
    driver.find_element_by_xpath("//*[@id='kw']").send_keys('Selenium')
    
    # 使用xpath方法的name属性定位
    driver.find_element_by_xpath("//*[@name='wd']").send_keys('Selenium')
    
    # 使用xpath方法的class属性定位
    driver.find_element_by_xpath("//*[@class='s_ipt']").send_keys('Selenium')
  2. 除了使用class,id,name定位,也可以手动选取节点来进行定位:

    # 使用 // 选取当前节点
    driver.find_element_by_xpath("//input[@id='kw']").send_keys('Selenium') 
    # 使用 // 选取父节点 driver.find_element_by_xpath("//span[@class='bg s_ipt_wr quickdelete-wrap']/input").send_keys('Selenium')
    # 使用 // 选取爷节点 driver.find_element_by_xpath("//form[@id='form']/span[1]/input").send_keys('Selenium')
  3. 使用绝对路径定位代码会很长,有其中一个元素发生变化就会失效还有程序在运行的时候会检索会比较慢,剥丝抽茧一层层的找会很慢,不建议使用;

     

    driver.find_element_by_xpath('html/body/div[1]/div[1]/div/div[1]/div/form/span[1]/input').send_keys('Selenium')

8. 通过css定位:

  1. css也颇为强大xpath可以干的事css也可以干,css的语法更为简洁,更为高效。而相对初学者xpath看起来更直观,更好理解;

    # 使用 css 通过 id 定位
    driver.find_element_by_css_selector('#kw').send_keys('Selenium')
    
    # 使用 css 通过 class 定位
    driver.find_element_by_css_selector('.s_ipt').send_keys('Selenium')
    
    # 使用 css 通过 name 定位
    driver.find_element_by_css_selector("[name='wd']").send_keys('Selenium')
    
    # 使用 css 通过 autocomplete 定位
    driver.find_element_by_css_selector("[autocomplete='off']").send_keys('Selenium')
  2. css除了使用元素的属性定位也可以和xpath一样使用层级关系进行定位:

    # 使用 css 通过 标签定位
    driver.find_element_by_css_selector('input').send_keys('Selenium')
    # 使用 css 标签属性定位
    driver.find_element_by_css_selector('input.s_ipt').send_keys('Selenium')
    driver.find_element_by_css_selector('input#kw').send_keys('Selenium')
    # 层级关系
    driver.find_element_by_css_selector("input[id='kw']").send_keys('Selenium')
    driver.find_element_by_css_selector("input[name='wd']").send_keys('Selenium')
    driver.find_element_by_css_selector("input[autocomplete='off']").send_keys('Selenium')
    # 层级关系
    driver.find_element_by_css_selector("form#form>span>input").send_keys('Selenium')
    driver.find_element_by_css_selector("form.fm>span>input").send_keys('Selenium')
    driver.find_element_by_css_selector("form[name='f']>span>input").send_keys('Seleniu

本章说的是8种基本定位的方法,学会了8种就足够日常使用了,其中xpath和css的定位方法远远不止我写的几种,想要深入了解xpath、css、复数定位的请自行百度进行学习。

 

 

 

C# NAudio录音和播放音频文件-实时绘制音频波形图(从音频流数据获取,而非设备获取)

  NAudio的录音和播放录音都有对应的类,我在使用Wav格式进行录音和播放录音时使用的类时WaveIn和WaveOut,这两个类是对功能的回调和一些事件触发。

  在WaveIn和WaveOut之外还有对音频流读写使用的WaveFileWriter和WaveFileReader类,具体细节可查看其源码进行分析。

  其中绘制音频波形图根据录制和播放需要不同途径实现。

  1.录音时实时显示波形图,在录音时实时获取需要使用WaveIn.DataAvailable回调事件,在这个回调事件中会传递出音频流数据,数据类型Byte[],这就是音频内容

  但这个Byte数组需要还原为真实的数据,它的真实数据类型需根据PCM写入时的数据格式定,主要有8bit、16bit、24bit、32bit,如写入时是16bit就需将其转换为16bit数据

  然后根据WaveIn.WaveFormat的channels去获取音频波形值,然后输出出来,具体示例如下:

 private void waveSource_DataAvailable(object sender, WaveInEventArgs e)
        {
            if (waveFile != null)
            {
                waveFile.Write(e.Buffer, 0, e.BytesRecorded);
                waveFile.Flush();

               
                float[] sts = new float[e.Buffer.Length / channels];
                int outIndex = 0;
                for (int n = 0; n < e.Buffer.Length; n += channels)
                {
                    sts[outIndex++] = BitConverter.ToInt16(e.Buffer, n) / 32768f;
                }

                for (int n = 0; n < sts.Length; n += channels)
                {
                    Add(sts[n]);
                }
            }
        }

  其中Add()方法就是添加波形值到UI控件上的方法,可根据自己需求实现。 

 

 2.播放录音文件时显示波形图

  播放录音时需初始化AudioFileReader类,并传入需要播放的文件路径,并将这个类传入WaveOut类中,最后用继承自ISampleProvider的类加载和初始化调用Play方法,然后会调用到WaveOut类Read方法时,会可以使用AudioFileReader.Read()方法进行获取参数,获取的是float数组,可直接用于绘制波形图

   private void AnalysisRecord_Click(object sender, RoutedEventArgs e)
        {
           
            var inputStream = new AudioFileReader(recordList[0]);
            ISampleProvider aggregator = new NAudioReader(inputStream);
            aggregator.MaximumCalculated += Aggregator_MaximumCalculated;
            aggregator.Start();
            waveOutDevice.Init(aggregator);
            waveOutDevice.Volume = 0;
            waveOutDevice.PlaybackStopped += WaveOutDevice_PlaybackStopped;
            waveOutDevice.Play();
        }

 

public int Read(float[] buffer, int offset, int count)///这个函数是ISampleProvider调用的函数 
{ var samplesRead = source.Read(buffer, offset, count); for (int n = 0; n < samplesRead; n += channels) { Add(buffer[n + offset]); } return samplesRead; }

  至于绘制波形的WPF细节就在Demo中看吧,主要要注意WaveIn和WaveOut、WaveFileReader和WaveFileWriter相关内容,具体可下源码和Demo看下

  具体可调试示例如下:示例 (也是粗浅学习,可交流,轻拍砖)

 

RocketMQ 4.3.2 standalone Installation and Configuration

1 Download RockeMQ Package:

  You need to download it and put it to the OS Image.

wget http: //apache .claz.org /rocketmq/4 .3.2 /rocketmq-all-4 .3.2-bin-release.zip and unzip the package to  /opt/rocketmq


2 Prerequsite

 JDK installed.

3 Create service account for Jetty

useradd  -m rocketmq echo  "umask 002"  >>  /home/rocketmq/ .bash_profile


4 Modify PATH system variable
4

run  /opt/rocketmq/bin/os .sh change JVM parameters  in  /opt/rocketmq/bin/runserver .sh

 


5 Configure RocketMQ

run  /opt/rocketmq/bin/os .sh change JVM parameters  in  /opt/rocketmq/bin/runserver .sh change JVM parameters  in  /opt/rocketmq/bin/runbroker .sh #Note: Usually set the Xmn to 1/8 or Xmx

 

8 Add RocketMQ to system service

 

cd  /etc/init .d vi  rocketmq  and add     #!/usr/bin/env bash # # rocketmq - this script starts and stops the rocketmq daemon # # chkconfig:   - 85 15 ROCKETMQ_HOME= /opt/rocketmq ROCKETMQ_BIN=${ROCKETMQ_HOME} /bin ADDR=` hostname  -i`:9876 LOG_DIR=${ROCKETMQ_HOME} /logs NAMESERVER_LOG=${LOG_DIR} /namesrv .log BROKER_LOG=${LOG_DIR} /broker .log start() {      if  [ ! -d ${LOG_DIR} ]; then         su  - rocketmq -c  "mkdir ${LOG_DIR}"      fi      cd  ${ROCKETMQ_HOME}      su  - rocketmq -c   "nohup sh $ROCKETMQ_HOME/bin/mqnamesrv > ${NAMESERVER_LOG} 2>&1 &"      echo   "The Name Server boot success..."      su  - rocketmq -c   "nohup  sh $ROCKETMQ_HOME/bin/mqbroker -n ${ADDR} > ${BROKER_LOG} 2>&1 &"      echo   "The broker[%s, ${ADDR}] boot success..." } stop() {      cd  ${ROCKETMQ_HOME}      su  - rocketmq -c  "sh $ROCKETMQ_HOME/bin/mqshutdown broker"      sleep  1      su  - rocketmq -c  "sh $ROCKETMQ_HOME/bin/mqshutdown namesrv" } restart() {      stop      sleep  5      start } case  "$1"  in      start)          start          ;;      stop)          stop          ;;      restart)          restart          ;;      *)          echo  $ "Usage: $0 {start|stop|restart}"          exit  2 esac     ################################################# chmod  a+x rocketmq chkconfig --add rocketmq chown  -R rocketmq:rocketmq  /opt/rocketmq

9 add a boot script to setup Rocketmq JVM(below script is only for standalone mode)

#!/bin/bash #set -x #this script is only going to set Rocketmq standalone installation(nameserver and broker server in a same host)   RQ_HOME_BIN= /opt/rocketmq/bin #RQ_HOME_BIN=/home/dc-user/rq/rocketmq-all-4.3.2-bin-release/bin #$RQ_HOME_BIN/runserver.sh to modify the #39  JAVA_OPT="${JAVA_OPT} -server -Xms4g -Xmx4g -Xmn2g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m" #$RQ_HOME_BIN/runbroker.sh to modify the #39   JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g -Xmn4g" #get current physical memory setting mem_size=` free  -m |  grep  Mem |  awk  '{print $2}' ` #set jetty JVM xmx to 50% of mem jmem=$(($mem_size /4 )) jmemn=$(($jmem /2 )) jmem=$jmem "m" jmemn=$jmemn "m" sed  -i  "s/-Xmn[0-9]\+[g|m]/-Xmn$jmemn/g"  $RQ_HOME_BIN /runserver .sh sed  -i  "s/-Xms[0-9]\+[g|m]/-Xms$jmem/g"  $RQ_HOME_BIN /runserver .sh sed  -i  "s/-Xmx[0-9]\+[g|m]/-Xmx$jmem/g"  $RQ_HOME_BIN /runserver .sh sed  -i  "s/-Xmn[0-9]\+[g|m]/-Xmn$jmemn/g"  $RQ_HOME_BIN /runbroker .sh sed  -i  "s/-Xms[0-9]\+[g|m]/-Xms$jmem/g"  $RQ_HOME_BIN /runbroker .sh sed  -i  "s/-Xmx[0-9]\+[g|m]/-Xmx$jmem/g"  $RQ_HOME_BIN /runbroker .sh

 

硅谷炙手可热的明星工程师面临牢狱之灾

本文来自微信公众号:新浪科技(ID:techsina),作者:猫叔在硅谷,题图:Photo by Charles  on Unsplash

他曾是硅谷最炙手可热的技术才俊,是谷歌创始人最为器重的明星工程师,是科技巨头争相招徕的无人车大牛。但现在,他却是硅谷最声名狼藉的窃密者,是员工职业道德的反面教材,更面临着牢狱之灾。

这一切,都是因为贪念。他本并不缺钱,身家早已上亿;但却渴求更多的财富和更高的地位,不惜铤而走险窃取商业机密作为自己的铺路砖。

33项指控和10年监禁

美国加州北区联邦检察官本周正式向前谷歌无人车技术高管安东尼·莱万多夫斯基(Anthony Levandowski)提起刑事诉讼。这位39岁的工程师面临着高达33起盗窃和试图盗窃商业机密的指控,最高将面临10年监禁以及每项指控25万美元的罚金(即最高825万美元)

科技公司和离职高管对簿公堂并不少见,但是事情上升到刑事诉讼,情况就严峻得多。这一次,莱万多夫斯基是真的惹上了大麻烦。

莱万多夫斯基周二主动来到圣何塞投案自首,但表示自己对所有指控都不会认罪。虽然莱万多夫斯基表示自己可以马上拿出30万美元的现金保释金,但美国司法部不仅要求200万美元的担保,还要求他佩戴电子脚链,未经许可不得离开加州北部和东部。此外,政府还要求莱万多夫斯基的父母家人和商业伙伴都进行登记,以确保他不会畏罪逃跑。谷歌和Uber目前正在配合联邦司法部的调查。

对资产上亿的莱万多夫斯基来说,800万美元的罚金只是小菜一碟(是的,他不是千万富翁,是亿万富翁)。但入狱服刑则意味着他在科技行业的大好前途尽毁,带来的损失甚至上亿美元;实际上,他在硅谷的名声早已毁于一旦,已经成为了人所皆知的没有职业道德的窃密者。

在莱万多夫斯基遭到起诉之后,他在2018年联合创办的自动驾驶创业公司Pronto当天就任命了新CEO,网页上也撤下了莱万多夫斯基的介绍。此外,Pronto发表声明称,公司的技术没有涉及莱万多夫斯基案件涉及的激光雷达领域。

谷歌给了他1.2亿美元

在2017年之前,莱万多夫斯基是硅谷最炙手可热的技术天才。他在伯克利大学上学期间,就设计出了一辆自动驾驶摩托车,参加了美国自动驾驶车辆大赛,而且是其中唯一一辆摩托车。这辆车现在还在美国国家历史博物馆中展览。

莱万多夫斯基的无人驾驶研究吸引了谷歌,这家互联网巨头给26岁的他开出了百万美元的年薪。2007年加入谷歌之后,莱万多夫斯基很快就成为了明星员工,延续对自动驾驶车辆的热情。2008年他的团队就基于激光雷达技术改装了一辆丰田普锐斯,实现了自动驾驶。这也是第一辆上路测试的自动驾驶车辆。

在后来的Google X实验室,莱万多夫斯基直接领导了谷歌无人车的激光雷达技术团队,是谷歌无人车的联合创始人和核心技术高管。据称,他深得谷歌联合创始人谢尔盖·布林(Sergey Brin)的赏识。据后来谷歌起诉他的法庭文件显示,莱万多夫斯基在谷歌9年时间,总计拿到了超过1.2亿美元的总薪酬,他是谷歌收入最高的技术员工之一。

换成普通员工,拥有上亿美元已经足够财富自由,尽情享受生活。但在不断造梦的硅谷,技术天才总会有更大的野心,总想自己创办一家独角兽乃至更大规模的公司。他曾经对同事说,自己终有一天会挣到10亿美元。

在谷歌效力期间,莱万多夫斯基还在继续自己的项目。而谷歌先后收购了他创办的两个和无人车相关的创业项目。虽然这两笔收购本身也涉及到职业道德问题,但求贤若渴的谷歌当时并没有深究。

2015年下半年,谷歌宣布重组为Alphabet,将X实验室独立出来,并计划将无人车项目分拆。在这个过程中,无人车项目的一些核心高管和谷歌高层出现了意见分歧。作为激光雷达技术团队负责人,莱万多夫斯基在这个时候也开始筹备自己的创业项目。

2016年1月,他向谷歌正式提出辞职,理由是自己希望寻找机遇,更快推动无人车的商业化。由于加州并没有竞业禁止协议,莱万多夫斯基在签署了保密协议之后就完成了离职手续。

半年赚了2.5亿美元

离职谷歌当月,莱万多夫斯基和另外一位谷歌同事(谷歌地图负责人)创办了卡车自动驾驶创业公司Otto。Otto自己不做卡车,而做自动驾驶辅助软硬件。莱万多夫斯基的团队包括了来自特斯拉、苹果等公司的顶尖工程师,他还挖走了一些谷歌无人车团队的工程师。

令外界瞠目结舌的是,仅仅半年之后,共享出行巨头Uber就斥资6.8亿美元收购了Otto。莱万多夫斯基随即带着相关技术和不到50名技术人员加入了Uber,出任副总裁负责后者的无人车部门。

这笔交易当时就引发了外界质疑,为什么Uber这么着急花大价钱收购一个成立半年多的自动驾驶创业公司?

Otto和Uber总部都设在旧金山,在2016年春季,莱万多夫斯基多次被人看到与Uber创始人兼CEO卡拉尼克(Travis Kalanick)会面。后者一直非常赏识莱万多夫斯基,多次希望他加入Uber。或许Uber着急收购的另一个原因是,卡拉尼克希望在上市之前加入自动驾驶出租车业务,给Uber的上市有更多故事可讲。

在外界的眼中,莱万多夫斯基无疑是人生大赢家:离开谷歌之后创业,迅速出售给Uber,担任Uber无人车业务负责人;而他也从这笔交易中获得了巨大财富。法庭文件显示,Uber给了莱万多夫斯基个人500万股Uber股票,按当时二级市场估值衡量,莱万多夫斯基在半年时间赚得了2.5亿美元。

窃取谷歌1.4万份文件

然而,莱万多夫斯基的明星光环在很快就骤然消散。他从一个令人艳羡的创业明星变成了一个遭人唾弃的窃密嫌疑人,还引发了两家科技巨头之间的诉讼大战。

谷歌是如何发现莱万多夫斯基窃密的?一个说法是,2016年底,谷歌Waymo无意收到一份错发的激光雷达供应商邮件,更震惊地发现里面涉及到的Uber激光雷达技术细节居然和自己的专利技术高度相似。意识到技术泄露的Waymo随即展开调查,加入Uber的前谷歌无人车激光雷达负责人莱万多夫斯基成为了最大的嫌疑人。

另外一个说法是,在Uber斥资6亿美元收购Otto之后,导致了谷歌Waymo团队的人心涣散。一些工程师开始四处寻找新的创业机遇,而不是继续呆在谷歌打工。这种局面让Waymo负责人非常担忧,他们希望了解这些离职的员工,包括莱万多夫斯基,是否遵守了公司的保密协议,是否利用了他们在谷歌期间研发的技术。

Waymo经过调查发现,莱万多夫斯基在2016年1月离职之前,在2015年12月中下旬私自访问了存储核心技术的服务器,下载了高达9.8GB超过1.4万份包括谷歌无人车研发核心数据的文件,并且未经授权拷贝到自己的个人电脑。这些文件里面包括了激光雷达设计、专有电路板等诸多无人车核心技术。

按照Waymo的指控,莱万是精心收集了谷歌无人车的核心技术之后才提出了辞职。更令Waymo愤怒的是,莱万多夫斯基创业之后从Waymo挖来的工程师,也在离职前下载了Waymo的激光雷达技术和供应商文件。

Uber理亏赔偿谷歌

2017年3月,Waymo在加州地区法庭指控Uber和莱万多夫斯基以及其他人涉嫌窃取自己与无人车技术相关的商业机密。Waymo起诉的不仅是莱万多夫斯基,还有Uber。

根据Waymo的指控,莱万多夫斯基在2016年1月离开谷歌无人车团队之后就得到了卡拉尼克的承诺股权,早就约好要带着技术加入Uber,创办Otto根本是一个暗度陈仓的幌子。

然而,在法庭的调查取证过程中,作为此案的核心人物,莱万多夫斯基却援引美国宪法第五修正案的沉默权利,拒绝回答问题和配合调查,避免自己所说的证词和所交出的文件成为自己未来遭到诉讼的证据。他的这种拒绝态度,也让Uber在Waymo的诉讼中处于非常不利的地步。

2017年5月,美国加州法庭发布对Uber的禁令,要求莱万多夫斯基必须交出从谷歌窃取的技术文件,并限制了他在Uber的具体工作。就在这个月,莱万多夫斯基黯然离开了Uber。

2018年2月5日,这起案件转到旧金山的联邦法院进行审理。但仅仅四天之后,Uber就和Waymo达成和解,Uber向Waymo母公司Alphabet赔偿自己0.36%的股票。按照Waymo当时的公开表述,这笔赔偿金对Uber的估值是720亿美元,相当于2.6亿美元。Uber在今年5月上市,首日即遭破发,目前市值已经缩水到563亿美元。

当时Uber一位律师公开表示,Uber后悔(通过收购)雇佣莱万多夫斯基,招致了这起诉讼。当时审理这起案件的联邦法官将案件移交给了美国联邦检方判定是否应该对莱万多夫斯基提起刑事调查。这也是本周联邦检察官对莱万多夫斯基提起诉讼的原因所在。

终于承认带走文件

过去两年时间,硅谷无人车行业发生了多次工程师离职前私自下载公司机密技术文件的事件,其中三名华人工程师(两位来自苹果,一位来自特斯拉)都已经被捕,面临着和莱万多夫斯基类似的刑事指控和最高10年的监禁。而巧合的是,三位工程师在私自下载公司文件之后,加入了同一家中国电动车创业公司。

尽管已经被媒体和外界定性为“窃密内贼”,但莱万多夫斯基并没有保持低调。他很快又组建了一个新的创业公司Pronto.AI,还是做卡车的辅助驾驶系统,帮助司机保持车道、避免碰撞和定速巡航,可以看作是特斯拉Autopilot的卡车版。

不过,莱万多夫斯基依然对无人车念念不忘。去年10月,莱万多夫斯基坐着他自己改装的丰田普锐斯,号称在没有任何人工操作的情况下,在四天内从旧金山一路无人驾驶到纽约。莱万多夫斯基向媒体得意地表示,自己的无人车只依靠六个低分辨率的摄像头和基本数字地图就实现了无人车横穿美国。

曾经是激光雷达技术领域最出色工程师的莱万多夫斯基,现在却完全依靠计算机视觉了?虽然外界猜测,他是因为害怕再次遭到谷歌诉讼,而没有使用自己之前擅长的激光雷达技术,但莱万多夫斯基却对媒体坚决否认,称自己不用激光雷达是因为设备价格过于昂贵。

两年前拒绝回答任何问题,也不肯回应是否窃取谷歌文件的莱万多夫斯基,此次遭到刑事诉讼之后,却通过律师否认了窃密指控,称自己的确下载了文件,但却是无辜的。他通过律师表示,自己下载谷歌技术文件时还在谷歌任职,因此是符合规定的,而且也没有将那些技术文件用于Uber的无人车项目。

换句话说,这相当于他承认自己的确在离职前下载了大量谷歌机密技术文件。然而,莱万多夫斯基并没有对此感到愧疚。他在去年的媒体采访中抱怨自己被塑造成一个没有职业道德的坏人,使得很多投资人不敢继续投资他的新项目。

一位几年前曾经在谷歌无人车团队和莱万多夫斯基共事的工程师向新浪科技透露,“和他打过交道的人,几乎没有人说过什么好话。他是个技术天才没错,但人品确实不怎样。对于他现在的结局,没有人会感到意外,一点都没有冤枉。”

本文来自微信公众号:新浪科技(ID:techsina),作者:猫叔在硅谷

博士要在学术圈外择业,没想象中容易

本文来自微信公众号:IPP评论(ID:IPP-REVIEW),作者:张若梅,华南理工大学公共政策研究院研究助理、政策分析师。题图来自:东方IC

近日,华为创始人任正非签发了一封总裁办电子邮件,宣布对部分2019届顶尖毕业生实行年薪制管理,而该邮件中八名实行年薪制管理的顶尖人才学历均为博士,“博士高薪流入产业界”这一话题在榜单上居高不下。

但与之相应的讨论便是华为顶尖人才流失问题,据报道,2014年入职华为的博士四年后的留职率不足六成。部分学者认为博士流入产业界属于“线性学术管道的泄漏”,甚至是背离了“以学术为业”的传统博士培养逻辑。不同观点则表示学术圈外科研活动的开展,为博士职业选择提供了多元化渠道,也有助于削弱企业与学科间的界限。

不断增长的博士生就业需求与学术圈有限的就业岗位相冲突。

探寻根源,其中博士投身于产业界的背后,一方面是不断增长的博士生就业需求与学术圈有限的就业岗位相冲突;另一方面则是知识经济发展和产业部门科研需求的上升,促使博士毕业生就业领域向学术圈“外溢”。再观企业中博士的高离职率,则多由于双方合作间的不适配性,产业界批评博士生研究兴趣与现实脱节,而企业博士则责备企业工作模式和发展理念差异颇大。因此本文通过分析“学术圈外的博士”就职原因以及存在的问题,进一步反思当前我国的博士生培养理念。

学术圈外博士的择业动因

严峻的学术圈就业形势:博士帽年年增多,学术职位的数量却相对稳定。对比2012—2017年毕业的博士生与普通高校专任教师新增人数的变化情况来看,博士毕业生数量均高于当年教师新增数量,虽然2013年博士毕业生数量略低于普通高校专任教师新增数量,但也致使博士毕业生数量与教师增长量间的差值进一步扩大,且2014年高校专任教师年增长为-33.57%。

博士帽年年增多,但学术职位的数量却相对稳定。

一方面囿于高校教师职业稳定性,使该职业退出率相对较低。同样对比2012—2017年普通高校专任教师离职情况来看,其离职人数占当年专任教师总数始终保持在0.8%—1%的水平,离职人数较少且离职率较为稳定;另一方面,对比博士培养周期和高校教师退休年龄,博士培养周期一般为3—4年,而我国高校男女性教师的退休年龄按照60和55岁计算,其平均教师替换周期长达27年,而27年的岗位轮换面临的则是4年一周期的博士求职者,使得学术岗位的求职环境日益严峻。

图1  毕业博士生及普通高校专任教师新增数量年增长变化情况

数据来源:2013—2018年《中国教育统计年鉴》

图2 高校专任教师离职数占教师总数的年变化情况

数据来源:2013—2018年《中国教育统计年鉴》

学术圈外择业范围进一步扩大:在读博士职业目标选择和博士毕业生就业单位类型呈现多元化特征。2015年《自然杂志》发起一项对研究生的职业生涯规划调查,全球3400份问卷中60%受访者称,未来“可能”或“非常可能”会在企业工作,61%受访者表示“可能”或“非常可能”选择在政府机关或者基金会工作,在读博士职业选择目标呈现多样性特征。

另外以中国九校联盟内的高校博士毕业生去向为例,发现2016—2018年三年间虽然高等院校仍然是博士就业主战场,但2018年企业类聘用博士总占比已经超过30%,一度接近高等院校的博士吸纳比例。而国有企业、民营企业、三资企业,以及党政机关近年来招收博士的比例增加,整体博士毕业生就业单位呈现多元化特征。   

图3 2016—2018年C9院校联盟博士毕业生的就业情况

数据来源:2016—2018年C9高校毕业生就业质量报告

高校博士的教育培养观“滞后”

主要表现为:注重博士生学术能力的培养,而忽视毕业博士知识可迁移能力的发展。博士就业向学术圈“外溢”这一普遍现象折射出博士劳动力市场的变化,与之相应其培养方式也应开始改变。以英国为例,《罗伯茨报告》中就强调了可转移技能训练应成为改进博士教育的中心问题,截至2009年,英国已有3/4的研究机构为博士生提供可转移技能的结构化训练。

但对比我国一所“双一流”院校的工程博士培养方案与英国博士可迁移能力培养方式来看,虽然我国工程学博士也强调人才的市场应用性,但其学位课程中的“企业调研”、“工程领域前沿讲座”等内容也仅仅是增进博士生对企业的了解,而非提高博士生内在的就业能力。而从面向英国所有学科博士的可迁移能力训练来看,其中不仅仅包括培养博士的学术能力,也包括未来面向各行各业所需的自我管理能力、沟通能力以及人际交往能力(具体见表1)

表1 英国博士可迁移能力训练内容


资料来源:Vitae官网资料整理https://www.vitae.ac.uk

另外也有学者从博士生职业发展需求这一视角,对高校教育满意度进行调研,受访者中52.1%选择从事非学术职业,其中以非学术职业为目标的博士生认为教育应当培养其跨学科研究能力、适应企业文化挑战能力、团队合作交流的能力、领导力、组织协调能力以及创业能力等。而上述能力在当前高校博士的培养过程中并未涉及,仍然以塑造学术型人才为目标的培养方案和“唯论文”式的评价考核不断加固着博士毕业生们的“教职目标”,可现实中教职岗位的稀缺性又让多数博士求职无门,“学术圈外”的岗位能力又缺乏准备,使其择业更为艰难。

正是高校博士“滞后”的培养路径与博士多元化职业需求不相适应,导致博士择业艰难,也极易引发企业博士的高离职率。学者在对入职企业的博士毕业生调研中,发现仅有41.5%比例的博士生认为工作岗位与所学专业“密切相关”,而两者“完全不相关”比例达到9.9%。访谈中博士更是表态,“企业工作与自我设想差别较大、不能发挥学术想象力、学术能力无法应用到企业之中”等。正是基于同样的原因,华为博士类员工近五年累计平均离职率为21.8%,且2014年入职博士仅半数在职。另外从企业角度而言,雇主更希望雇员具备高学历、职业技能以及高水平“软技能”,即沟通能力、领导能力、跨部门协作能力。但研究发现部分企业雇主认为博士在创造力、领导力、沟通能力以及跨部门工作能力方面有所欠缺。

“学术圈外”博士教育改革的未来策略

围绕国家创新发展战略,重塑博士培养目标。政府以政策及资金为引导,就各地禀赋优势由中央、地方以及高校三方筹资共建“博士培养中心”,尤其以国家重点发展领域为核心,集聚不同学科博士生及不同领域的专家,使人才培养面向市场以打破学界与产业间的人才隔阂,同时也能实现服务于国家发展战略的跨学科人才培养目标。

从校方培养到多方协同博士培养模式或将成为趋势。其一,所成立的“博士培养中心”是以跨学科、跨机构平台为依托的博士学位项目,即此类博士的培养方式就已经从校方培养向多方利益主体参与转变,企业、政府、大学以及研究机构都是人才的培养的参与方,博士就读过程中将无可避免与学术界内外的人员合作,使其博士期间的研究训练兼具实践性与学术性。其二,传统高校导师制也即“一导一学”的培养方式或将发生改变,以工业界和学术界的导师组(2—3人制)形式来指导博士研究,或者引入跨学科同辈小组的学习方式进行,其间对于博士的指导则包括教学课程、项目研究以及可迁移技能训练等。

从专业主导向通专结合,增设通用型课程,培养博士可迁移能力。建议一,借鉴英国博士贯穿全程的可迁移能力训练,以核心课程学习为主,搭配兴趣课程的学习小组,来提升博士学生能力、自我管理能力、沟通能力和人际交往能力,以适应未来各类型岗位需求。建议二,高校应分阶段明确博士未来职业选择,早期以及中期培养阶段仍然以学术训练和可迁移能力训练为主,对于后期选择进入市场就业的博士则需要分专业进行系统职业指导,为未来的学术圈外就业提供准备。

本文来自微信公众号:IPP评论(ID:IPP-REVIEW),为华南理工大学公共政策研究院(IPP)官方微信平台,作者:张若梅,华南理工大学公共政策研究院研究助理、政策分析师。

免费网络摄像头里的另一个世界

本文来自微信公众号:游戏研究社(yysaag),作者:热得快,封面:视觉中国

Susan Dennis的客厅里有一颗摄像头,70岁的她在这颗摄像头下生活了20年。

几乎每一天,她都会坐在沙发上做些针线活,面前摆着电脑,时不时上网随便看看或者撸撸猫,就像一位普通的退休老人那样。

但Susan知道,成百上千名网友可能正通过摄像头注视着她。

Susan每天的作息都很有规律

在一个叫作Opentopia的免费网站上,她客厅里的这颗摄像头几乎成了镇站之宝,被人们造访过101万次,留下了492页的评论,最高峰时曾经有8000多人同时观看。

作为一个私人搭建的小网站,Opentopia唯一的内容就是通过简易算法,从网上自动抓取公开的摄像头内容,并且分类展示。它早在2005年就上线运行了,那个时候微软还在开发Vista系统,后来让直播行业声名大噪的Twitch也还有6年才会正式出现。

由于Opentopia扫描到的大多是各处的监控摄像头,一般都是对着停车场之类的公共场所,像Susan这样的内容十分少见,很快就有一群网友聚集在了评论区里,每天默默地观看她的生活。

当然,除了善意地表示“我很喜欢她的客厅”之外,也有人指出这可能会侵犯到她的隐私,没过多久就有网友查到了Susan的联系方式,告诉了她这个网站的事情。

Susan的反应显得格外宽容,她甚至还跑到了Opentopia的评论区加入了讨论,因为“我并不是一个有很多秘密的人!”

实际上,Susan早已习惯了这样的生活。世纪初的时候,网络摄像头还是个新鲜玩意儿,她在一本杂志上看到了架设的方法,于是就试着安装了一个,用来和远方的妈妈通讯。

后来,Susan也和弟弟建立起了这样的联系。他在自己的店里也装了一个摄像头,这样就可以互相交流了。在那个摄像头下面,还贴了一张写着“向我在西雅图的姐姐打招呼”的纸。

对于像她这种曾经在IBM和微软工作过将近20年的人来说,网络时代的来临并不是一件很难接受的事。

早在2002年,她就开始了每天在网络上写日志的生活,直到今天依然如此,期间几乎没有中断过一次。而在她搭建的个人网站上,也罗列着自己的各种信息。

这也许代表了他们这一批率先“网络冲浪”的人心中的互联网精神——自由、平等、分享。

时过境迁,如今的我们很难再去把它当作网络生活的一条准则。收录Susan家那颗摄像头的Opentopia,也用自己发展的历程侧面印证了这一点。

在Opentopia最鼎盛的时候,曾经有几千个摄像头的内容可供观看,甚至还有一家俄罗斯的医院在手术室里架设了一颗镜头,让观众们可以实时观看医生们的操作过程。

但随着人们对隐私的要求逐渐提高,更新换代的设备往往自带加密,不会再像之前那样大咧咧地展示在网络上任人观看。如今的Opentopia上只剩几百个可用的摄像头,基本上也都处于年久失修的状态。

这种曾经在“前直播时代”默默存在的网络现象,正一步步地慢慢消失,被人忘记,虽然依旧忠实地展示着此刻的现实,但它们自身已经成了留在过去的遗迹。

它们的历史,来源于我们对“实时了解世界”的渴望。

前不久,世界上最古老的网络摄像头“Fogcam”也宣布将在月底停止运行,结束它25年的直播生涯。

1994年的时候,两名旧金山大学的学生将它安装在了校园里。那时要通过电话线路上传信息,一分钟只能更新一次画面,但依然成为了科技界的轰动话题,不少人慕名访问他们的网站,只为看一眼此刻旧金山的样子。

而如果再向上追溯,更早的尝试则是来自英国的剑桥大学。

1993年,那里的计算机科学家们正面临一个十分困扰的小问题:工作需要补充咖啡因,但只有主实验室里有一台咖啡机,于是他们往往从不同楼层的不同实验室走过来,才发现咖啡壶是空的,白白浪费时间。

因此,他们想出了一个十分符合自己职业特点的解决方法:他们在咖啡机前安装了一台小相机,每分钟传递3次画面。这样一来,只需要看一眼屏幕,就知道现在有没有咖啡可喝了。

“咖啡机摄像头”提供的画面

没想到的是,当这台摄像机被公布到网络上后,竟然成为了大家津津乐道的话题,甚至有不少人会在去剑桥大学的时候特意拜访,只为参观那个著名的咖啡壶。

但随着科技的发展,维护这台摄像机变得越来越困难,最终科学家们在2001年关掉了它,传输的最后一幅画面就是按下“停止”键的手指。值得一提的是,这台著名的咖啡机后来还在eBay上拍卖出了3350英镑的高价。

关停前的最后一瞬

有了这两个先行者之后,网络摄像头也逐渐流行起来。“被监控”的感觉固然不爽,但只要它可以被控制,就能反过来成为人们满足好奇心的工具。

比如,你一定对下面这张照片并不陌生:

它是披头士1969年发布的专辑《艾比路》的封面,从标题到封面都取自录音室所在小路Abbey Road。

如今,这里不仅成为了乐迷们打卡的圣地,录音室还特意在这里安装了一个摄像头,用来随时随地看到这条小路的样子。

如今的艾比路,大家横穿马路的时候还是会格外注意一下体态

在国内,网络摄像头这种古老的形式虽然已经几乎消失,但依然有着类似的内容,比如成都大熊猫繁育基地开设的“iPanda”,其实就可以算是精神上的后继。熊猫TV倒下后的今天,货真价实的“熊猫直播”却依然安稳地24小时播出着。

当然,就像硬币的正反面一样,它也可以用来肆无忌惮地作恶。

2017年闹得沸沸扬扬的“360水滴直播”事件就是这样:大量摄像头的录像在未经授权的情况下被公开在了网络上,其中不乏涉及隐私的内容。开发商把责任一股脑推给了散播破解方法的黑客们,可是背后的种种恶意显然不止于此。

当时到处都是出售破解资源的人

虽然从时间上来看,网络摄像头似乎是直播的某种前身,但它们真正的区别其实在于内容——网络摄像头原始而粗糙,往往呈现的是未经修饰的现实;而直播则或多或少带有刻意表演的成分。

人类天生就有了解世界的欲望。无论是网络摄像头还是网络直播,都像是我们眼睛的延伸,让我们可以打破空间的疆界,与世界上的任何一个角落建立起实时的联系。

我们认为那就是真实。

在前几年汹涌的浪潮与乱象消退之后,网络直播在我们的生活中留下了一个模糊的位置,像一枚忘记摘下的隐形眼镜。

它已经存在得够久,久到“新事物”的狂热和资本一起褪去。但我们的好奇、窥私欲还有猎奇心理并不会消失,它们在某种意义上是永恒的。

秀场的歌舞继续上演,人们继续在镜头前吃下满桌食物,十万观众继续涌进大妈的直播间、留下他们的感想……但也许那些来自“前直播时代”的网络摄像头们,可以用粗糙的现实感给我们带来一些启发:透过模糊的画面,我们终于又看到了真实生活着的人。

Opentopia上如今最受欢迎的摄像头,来自西班牙的一家酒吧:停摆的电扇下,一位女招待和来访的客人闲聊,他们身后的墙壁前几天刚刚重新装饰过。

你也许可以把它算作某种巧合——这家酒吧,就开在巴塞罗那的乔治·奥威尔广场边上,后者正是这个国家最早安装监控摄像头的地方。

参考资料:

http://www.susandennis.com Susan的个人网站

http://www.opentopia.com Opentopia的地址

http://fogcam.org Fogcam的网站

https://www.abbeyroad.com/crossing 艾比路直播

本文来自微信公众号:游戏研究社(yysaag),作者:热得快,封面:视觉中国

贫困,竟然是个神经学问题?

造就第457位讲者 Jeffrey Erlich

上海纽约大学神经学与认知科学助理教授

纽约大学全球特聘助理教授

贫困是我们这个时代最大的健康危机。世界上最贫穷的国家和最富裕的国家之间,人的预期寿命差距达到了30年。在非洲的国家中,人们的平均死亡年龄是55岁;而在美国,人们的预期寿命超过了80岁。

该图比较了2015年联合国承认的所有182个国家的预期寿命和人均GDP

当然,贫困有着很多原因:战争、饥荒,还有疫病。但即使是在美国,最贫穷地区和最富裕地区的预期寿命也有20多年的差距。

关于贫困,最悲惨的事情之一就是,它会从上一代传到下一代。出生在贫困家庭的孩子,他们在获取食物、医疗和教育资源方面的机会较少。这会导致他们错失机遇以及压力增大,而这又会导致他们收入变得更低,然后他们的孩子重蹈相同的厄运。

贫困,竟然是个神经学问题?

那么,贫困与神经科学有什么关系呢?

贫困其实有两个方面跟神经科学存在关联。首先,贫困属于一种慢性压力状态;其次,贫困涉及到财务决策。神经科学对这两者都有着相对广泛的研究,尤其是对压力的研究。

贫困属于一种慢性压力状态,它会从生理上表现出来。如果我们测量贫困人群的血压或激素水平,跟正常人群相比,他们的血压或激素水平都会显得高出很多,这种现象甚至可见于生活在贫困中的儿童身上。

能在儿童身上验证这一点是很重要的,因为就成年人而言,你可以说,导致他们高血压的原因是他们不健康的生活习惯,因为抽烟、喝酒或缺乏运动。但我们很难把这套论证用在儿童身上。神经科学研究压力已经有100多年的时间,毫无疑问,我们都会用到压力这个词语。像是工作让我感到有压力,做这场演讲让我感到有压力等等。

但在生物学中,我们对压力有着更具体的定义。所谓压力源,给我们带来压力的东西,就是让我们失去平衡的东西。我们会使用“稳态”(homeostasis)这个术语,但它实际上只是一种我们跟周遭环境的平衡感。饥饿、口渴、疲倦、孤独以及失控的感觉,这些都是压力源。

举个例子,我们的工作有一个截止日期,我们要在那之前提交成果,那会促使我们努力工作,并做出良好表现。这是好的压力,它会促使我们做一些事情,让自己再次达到平衡状态;

但如果我们有太多的工作要做,一次又一次地错过最后期限,而且无法真正达到平衡,那么这会导致我们进入承受慢性压力的状态。

我们已经知道,慢性压力会对我们的身体和大脑产生严重的长期负面影响。在大脑中,慢性压力会导致跟记忆和执行功能(例如自我控制和决策)有关的脑区出现萎缩,同时它也会增强那些跟习惯和本能有关的脑区。这方面的研究已经非常成熟了。所以,这是贫困与神经科学之间的第一个联系。

至于第二个联系,就像我前面说到的,是财务决策。

神经科学研究决策已经有相当长的时间了,我们对决策涉及到的神经回路有着相对深入的理解,尽管这种理解肯定不全面,但这仍然是一个非常活跃的研究领域,而压力对大脑的影响也是如此。

我们现在已经知道,处于贫困状态的人倾向于做出糟糕的财务决策,他们背负高息贷款,不会为退休提前存钱,诸如此类。这些糟糕的财务决策如何导致贫困的恶性循环,这是一个越来越受到研究人员关注的课题。

这里要着重说明一点,我们把这些财务决策称之为跨期偏好(intertemporal preference),也就是相较于当前的我自己,我有多喜欢未来的自己。如果我更喜欢未来的自己,我就是有耐心的;或者,如果我更喜欢当前的自己,那你就可以认为我是冲动的。

假设我今天彩票中了奖,当前的我自己可能只想买下一辆豪华轿车,买下一套豪华公寓。但未来的自己并不希望如此,未来的自己希望把这些钱存下来,这样我在退休后就能过得舒舒服服。

研究人员已经找到很好的证据表明,贫困人群倾向于喜欢当前的自己,他们聚焦的是当下。当然,有人可能会说,他们这也是没办法,如果他们连买食物的钱都没有,他们又怎么能为退休存钱呢?

但是实验研究表明,即使是中产阶级和上层阶级的人,如果让他们处于慢性压力状态下,他们做出的选择也会转变为更聚焦于当下。

因此,这表明可能存在一种核心生物机制,压力通过它将我们关注的焦点从未来转移到当下,而这可能导致贫困的恶性循环。

但是,我们几乎不可能在人类身上验证这一点,因为有太多其他影响因素,比如教育和文化,比如你从父母那里学到的东西,这样的因素数不胜数,还有无法干预的遗传因素。所以,我们需要一个动物模型来解决这个问题:慢性压力是否真的会导致人们的跨期偏好转变为聚焦于当下。

两次技术革命改变了神经科学

那么,我在自己动物模型中选择的动物为何是啮齿动物呢?比如大鼠和小鼠。

啮齿动物和人类都属于哺乳动物。两者大脑结构是类似的,虽然尺寸有很大的差异,而且不同脑区的相对作用也存在着一些差异,但总体而言,它们拥有类似的结构。

我选择啮齿动物的另一个原因是,神经科学领域已经发生了两场革命,它们让我们在决策神经科学的研究进程中出现了一次范式转变。

第一场革命,在我看来是被低估的,它就是我们在这些日子一直都有耳闻的计算机革命。这场革命让电子产品的成本、我们可以存储的数据以及用来追踪行为和神经活动的传感器数量都发生了变化,我们现在可以生成数以TB乃至PB的数据,然后以相对低廉的成本进行存储和分析,而这一切在十年前根本没有可能做到。

这种技术让我们现在能够以前所未有的水平记录神经回路活动,我们还在用跟制造计算机芯片相同的技术制造探针,当我们把这些探针放入脑部,我们可以在动物做出行为时一次性记录下一万个神经元的活动。

能够做到这些真的非常重要,因为大脑太复杂了。传统的工具只能让我们一次查看一个神经元,我们无法获得完整的图景,无从得知大脑活动和个体行为的联系。

第二场革命,你们也听说过,就是基因工程革命。

在过去的10年~15年,我们监测和扰动神经回路的能力已经出现了指数级的提升。利用病毒载体(viral vectors)插入来自其他动物或是合成产生的蛋白质,这让我们能够以毫秒精度控制神经活动。

利用这些工具,我们可以对大脑某个区域的神经元实施控制,我们可以控制从一个区域投射到另一个区域的神经元,可以控制表达特定生物标志物(比如多巴胺或5-羟色胺的受体)的神经元,甚至可以根据神经元的活动模式来控制它们。

事实上,麻省理工学院的研究人员已经利用这个工具将老鼠的正面记忆转变为负面记忆。而普林斯顿大学的研究人员则使用了一种类似的技术,他们用一只老鼠进行实验,转换它的位置,基本上就是观察老鼠在一个地方的神经活动模式。接着把它换到另一个位置后,研究人员在老鼠的大脑中重播那个模式,老鼠会认为自己还在原先的位置。这在现在,真的像是科幻小说中的场景。

在我的实验室里,这些工具让我们得以使用价格便宜的电子设备建立一个高通量的训练中心,目前每天一个技术人员,就可以训练100只动物。因为如果我们希望实验对象学习复杂的认知任务,那么我们就需要很多的动物,这也有助于我们研究个体差异。在神经科学领域,这是另一件存在缺失的事情。

所以说,这些新工具真正让我们得以把DNA跟蛋白质、跟神经回路、跟行为联系在一起。

那么,回到我们的问题:我们希望了解慢性压力如何影响到财务决策,尤其是在未来跟当前之间的权衡;而且,我们想在老鼠身上开展研究,我们想把那些研究成果应用在人类身上。

如何在老鼠身上做人类思维实验?

这里存在一个挑战,老鼠不是人,它们不会为退休存钱,你们懂的。

但事实上,人们已经在实验室对跨期选择做了广泛的研究。关于这个课题的研究论文汗牛充栋,数以千计,有的从经济学视角,有的从心理学视角,也有的从神经科学视角。

我们在实验室研究经济选择的通常方法是,我们向被试者提问:你是想今天拿到10美元,还是在30天后拿到15美元?

更多的人会选择第二项,这很好。如果你选的是第一项,那你千万不要自己去投资,你该找个财务顾问。在30天里拿到15美元,平均年化收益率相当于600%,你在股市可遇不到这种好事。这就是我们在人类身上研究这个问题的方法。

那么,我们怎么在老鼠身上研究这个呢?老鼠不会说话,所以,我们需要找到方法把这个任务转译一下,老鼠是通过反复试错进行学习的,它们从经验中学习。这是我们在研究人类和研究动物之间的一个差距,一个从言语到非言语的差距,第二个是时间跨度差距。

就人类来说,我们的确总是在做出短期决策。举例来说,我本人经常支付2美元来移除手机应用上的广告,这样我就不必每次都等上20秒或是之类的东西。但我们也会做出长期的决策,时间跨度有几天、几周、几个月乃至几年。我们永远不可能去问一只老鼠,你愿不愿意现在放弃一些食物,以换取在两周后获得另一些食物,它永远无法把以后的奖励跟自己在今天做出的选择联系起来。

所以,这是我们需要克服的两个差距。对我和我的团队来说,真正让我们投入精力去研究的原因是:尽管关于这个课题的研究论文数以千计,但没有人真正回答了这个问题:

你在老鼠身上研究的那种决策,那种基于经验为一个奖励而等待几秒钟的决策,是否跟人类在做出涉及几天、几个月或几年的长期决策时所使用的认知过程是一样的?

我们决定自己回答这个问题。

那么,我们怎么做呢?我们决定像训练老鼠一样训练人,我们把志愿者请到实验室,简单来说我们为他们制作了一款电子游戏。我们没有告诉他们游戏是什么,我们只是说,每次你们看到金币时,那跟真钱是挂钩的。然后,我们像调教老鼠一样,是用高音调的声音训练他们:

  • 像是yiii,这样高音调的声音,意味着一份大奖励;

  • 而低音调的声音,像是wuuu,则意味着一份廉价的小奖励;

  • 如果是wan…wan…wan这样的慢调子,那意味着长时间的延迟;

  • 如果他们听到的是wan wan wan这样的快调子,那就是短时间的延迟。

在每次实验中,他们会听到一个声音,然后要做出一个选择:我是应该等待着那份大奖励的出现,还是应该把眼前的小奖励拿到手?

我们多少能够看到其中的权衡选择。如果声音的音调很高,那意味着奖励很大;如果延迟是短时间的,那么你会感到高兴。你喜欢的是短延迟的大奖励,这很好,你不会喜欢长延迟的小奖励,没有谁会喜欢。

我们把被试带到实验室,我们用这项非言语任务对他们进行训练,然后让他们完成三次不同的实验。通过几百次尝试,被试学会了声音和奖励选项之间的对应关系。

在完成这项实验后,我们再把被试请回来,让他们做这道用言语编写的经典选择题。我们找来的被试有说英文的,也有说中文的,我们因人而异呈现不同的语言版本。

然后,我们提出的问题是:那些在言语任务中表现最冲动的人,是否也是在非言语任务中表现最冲动的人呢? 

我们发现,这里面存在着一种高得惊人的相关性。在这张图表上,我们可以看到:

在言语任务中最耐心的被试者,也是非言语任务中最耐心的被试者;而言语任务中最冲动的被试者、最不耐烦的被试者,同样也是非言语任务中最不耐烦的被试者。

这一点真的很重要,因为它向我们展示的是人们在做出有关当前和未来的决策时所表现的偏好差异,不管那个决策是基于经验还是基于一个用言语呈现的选项,他们都表现出了相同的偏好,这表明他们正在使用相同的认知策略,而这又证明,我们可以使用老鼠来研究这种行为。

所以,我们在训练老鼠来完成这些任务以及其他财务相关任务。在我讲这些话时,我的博士后研究员们正在实验室里,他们在向老鼠施加压力,然后对它们表现出的偏好进行测量,但我还没有得到结果。

所以我很遗憾地说,我的演讲到这里就要结束了。不过,我希望你们能够对我们如何解决这个具有挑战性的问题,有所了解。

后记

虽然Erlich教授的演讲暂时还无法给出确凿的结论,但是它给了我们一个很好的示范,关于如何在神经学领域把微观、宏观之间统摄起来,神经学学者尝试用神经学去跨学科地解答一些看似是社会学、心理学的综合性问题。这也是今天我们跨学科地把自然科学与社会科学联系起来的重要路径,或许会对未来解决社会问题提供了更丰富便捷的方案。

当面孔成为大数据“养料”,你的脸还好吗?

本文来自微信公众号:全媒派(ID:quanmeipai),封面:视觉中国

“刷脸”进门,“靠脸”吃饭……在人脸识别技术日渐成熟的今天,这些早已经无限接近于现实。根据前瞻行业研究院的预测,未来五年中国人脸识别整体市场将快速成长,实现多行业应用,预计到2021年中国人脸识别市场规模将突破50亿元。

在2018年北京安博会上,参观者走过一个展示面部识别软件的屏幕

但是,在人脸识别一路狂奔的同时,技术开发所涉及的隐私问题日渐暴露,应用中的弊病也逐渐凸显。

试想,在简单“刷脸”就能完成一切的同时,你的五官数据将永远成为网络数据集的一部分,甚至有可能被不同的机构调用。人脸识别所带来的并不只是便利、高效和未来感,在现阶段,它应该更多地与伦理、审查、规范化相联系。

本期全媒派(ID:quanmeipai)带来独家编译,让我们放下对这项技术的想象与憧憬,从最现实的角度对其进行探讨和反思。

当研究数据被永久存储

如何划定隐私边界

当你走进一家坐着20个人的咖啡店,至少会有22个摄像头在你身边:每个人的手机里有一个,另一个通常高高悬挂在角落。你说的内容可能被偷听或被发布出去,你甚至可能出现在另一位顾客的自拍或视频会话背景中。但即使最注重隐私的人,也不会因此而拒绝进入咖啡店,因为人们都能接受进入公共场所而存在的固有风险。

正是这种对隐私的“合理”期望,使那些需要在公共场合采集人脸识别研究对象的研究者心安理得。但是,当公共场合采集的信息成为了永久且开放的数据集,如何划定“合理”的隐私边界,就成为了一片学术伦理尚未完善的灰色地带。

成为数据集的研究对象

杜克大学、斯坦福大学和科罗拉多州立大学多泉分校的学者们,都利用了校园监控作为捕捉研究对象的手段,但这一行为引起了群众强烈反对。虽然人们对在咖啡店里被人偷听有心理准备,但却没有想过会突然变成研究对象,更何况被录入的研究对象将永远成为数据集的一部分。

伦理委员会(IRB)批准了这三个使用学生数据来改进机器学习算法的研究项目。杜克大学研究员Carlo Tomasi在《杜克大学纪事报》(Duke Chronicle)的一份声明中表示,他“真诚地认为”自己遵循了委员会的指导方针。

为了开展研究,他和他的同事在公共区域的所有入口处张贴海报,告诉人们他们正在被记录,如果他们想要删除自己的数据,可以留下联系信息。Tomasi也告诉《纪事报》,没有人主动来联系研究团队删除数据。

但Tomasi承认,他没有通知IRB自己研究范围的变化。一般来说,微小的变化是可以不用上报的,但是Tomasi获得的批准是在室内录制,并且只有提交请求才能访问数据库。但现实中,他在室外录制,并且将数据库向所有人开放。他向《纪事报》表示,“IRB不应该受到指责,因为我没有在关键时刻咨询他们。我对我的错误承担全部责任,我向所有被记录的人和此举对杜克大学造成的影响道歉”。

有限的监管和失控的后果

在科罗拉多州立大学多泉分校,首席研究员表示虽然他们通过学生数据来测试技术,但是团队从未收集过具体到个人的识别信息。在独立声明中,大学们都重申IRB批准了所有研究,并强调了其对学生隐私的承诺。

但问题在于,大学伦理委员会的监管范围是有限的。他们主要关注研究是如何进行的,但对研究将会如何结束,后续会产生什么影响却并不关心。

正如盖辛格的IRB领导委员会主席、生物伦理学家Michelle Meyer所解释的那样,IRB主要关注的隐私问题是在公共场所开展观察研究时,研究对象是否被单独识别,以及对他们的识别是否会使他们面临实质利益或生理上的伤害。

“从理论上讲,如果你正在制造一枚核弹,其中涉及调查或采访人类受试者,那么IRB考虑的风险将是直接参与该项目的人员面临的风险,而不是核爆炸的潜在风险。”

值得注意的是,在信息时代,大多数学术研究都依靠互联网,而互联网上的信息将永远存在。为其他研究人员开放数据集会增加伴生风险,但IRB在这一方面并没有多少管辖权。因为从根本上说,数据共享与研究本身并不是一回事,因此它处在“一个奇怪的灰色监管地带”。

如果IRB对研究可能导致的后果漠不关心,那么其他不受IRB标准约束的研究人员,就可以下载数据集并按照他们的意愿随意使用。而被研究的对象却对自己正在被研究这件事全然不知,这可能会导致各种消极的后果。

这些后果或许远远超出研究人员的想象。德国反监视专家Adam Harvey,在全球范围内发现了100多个引用杜克数据集的机器学习项目。他创建了一张地图,用于追踪这一数据集在全球的传播情况,就像飞机的航线图一样。从杜克大学向各个方向延伸出长长的蓝线,指向世界各地的大学、初创企业和研究机构,包括中国的商汤科技(SenseTime)和旷视科技(Megvii)。

每次有新项目访问数据集时,损害可能导致的影响和范围都会发生变化。数据的可移植性和互联网的快速度结合在一起,大大扩展了一个研究项目的可能边界,也把风险扩展到远远超出任何一所大学能承担的范围。

解决尝试:建立学术审查系统

杜克大学最终决定删除与该研究相关的数据集。斯坦福大学清除了研究人员基于旧金山咖啡馆的顾客所创建的数据集。

科罗拉多大学博尔德分校信息科学系助理教授Casey Fiesler,撰写了关于在研究中使用公共数据的伦理学。Fiesler提出了一种用于审查数据集访问的系统,与审查版权类似。她指出,系统中的使用条款主要关注请求者计划如何使用该数据。

为这些数据集设置守门人是一个好主意。”她说,“因为只要明确使用目的,请求者就能够访问数据集。”类似的规则,在开源软件和Creative Commons的标准化版权许可协议上已有应用。

Creative Commons是一种基于许可的系统,请求者只能将获得的作品作为非商业用途,而一旦他们隐瞒或歪曲意图,则需要承担责任。这些标准可能与学术环境并不完全匹配,但至少在切断后续伤害方面是有用的。“这并不是将规则繁琐化,但它提出了一种方法,使得你无论决定要做什么时,都把前后因果考虑进去。”Fiesler说。

种族歧视&影响执法

应用中暴露的技术盲区

当人脸识别技术走出实验室,走进现实生活,它就被赋予了更多意义——你的脸将不再只是一张具有生物属性的脸了。在足球比赛中,你的脸是货币,用于在体育场购买食物。在商场,它是一个账本,用于告诉销售人员你过去的购买行为以及购物偏好。在抗议中,你的脸会反映出你过去被逮捕的历史。即使在太平间,脸也能帮助官方机构识别遗体。

随着人脸承载的意义不断加强,技术错误导致的后果严重性也随之增强。在现阶段的应用中,人脸识别技术的一些弊端已经暴露。

识别准确度存在差异加剧种族歧视

2016年麻省理工学院的研究员Joy Buolamwini研究表明,人脸识别技术的准确性在肤色较浅的男性中表现优于肤色较深的男性,而对于肤色较深的女性则表现最差。

美国公民联合会(ACLU)也发现了类似的问题。当ACLU将国会议员与犯罪数据库进行匹配时,亚马逊的Rekognition软件对黑人议员的错误识别比白人议员多得多,尽管黑人议员在总体数量中占比更小。其中包括众议院议长Elijah Cummings,一名巴尔的摩人。

对不同肤色人种间识别的准确度差异可能加剧种族歧视的指责,微软和亚马逊都声称,自麻省理工学院和ACLU的报告发布以来,公司已经优化了技术对识别不同种族在准确性方面的差异。但是,更准确地识别有色面孔只是技术需要改进的一部分,因为即使完全准确的技术仍然可以用来支持对有色人种有害的执法措施。

对技术本身的改进和完善并不是最重要的议题,如何使用这项技术才更应该被关注。微软和亚马逊提出的解决方案是在技术应用后对面部识别存在问题进行纠正,但这只是亡羊补牢。

人脸识别执法可行性存疑

5月初,《华盛顿邮报》报道称,警方正在使用面部识别软件抓捕疑犯。一名目击者向警方描述了嫌疑人的外貌,警察据此画出草图上传到亚马逊的Rekognition,并最终逮捕了某人。这一事件震惊了国会听证会上的专家——提交给数据库的草图竟可以被当做逮捕嫌疑人的充分依据。

对此,亚马逊网络服务首席执行官Jassy称,亚马逊从未收到对警方误用技术的投诉。就在今年5月,亚马逊股东投票否决了一项禁止向警方出售Rekognition的提案。亚马逊的一位代表在一份声明中说:“亚马逊从未收到过任何公众投诉,而且地方机构在使用Rekognition方面没有任何问题。”

立法者&制造商:把“危险的”人脸识别关进笼子

为了平衡人脸识别技术的回报与风险,华盛顿州、马萨诸塞州、奥克兰市以及美国立法机构提出了一系列监管建议。众议院监督和改革委员会的共和党人和民主党人举行了几个小时的听证会,并表示两党愿意共同努力来规范这项技术。

Face API和Rekognition软件的制造商微软和亚马逊也对联邦监管表示支持。今年6月,美国排名第一的随身摄录机制造商Axon同意其道德委员会的建议,即不要让Axon相机配备面部识别装置。

去年,微软法务总裁Brad Smith呼吁各国政府“立法来规范这项技术”。而亚马逊网络服务公司首席执行官Andy Jassy在6月份表示附和,他将这项技术比作一把刀。这位来自世界上最强大的面部识别技术公司的高管想表达这个东西很危险。

但在呼吁监管方面,微软和亚马逊采取了一个巧妙的伎俩:他们没有就面部识别是否应该被广泛应用进行辩论,而是在讨论这一技术应该如何被应用。

亚马逊在《大西洋月刊》上发表的一份声明中表示,它正在与研究人员、立法者及其客户合作,“了解如何最好地平衡面部识别的益处和潜在风险”,并指出Rekognition具有多种用途,包括打击人口贩卖并找到失踪人员。微软重申Smith的声明,表示支持面部识别法规的建立,包括施行针对滥用行为的规范,以及获得被识别对象的许可。

但一些隐私专家认为这些公司别有用心。罗切斯特理工学院哲学教授Evan Selinger,指责微软和亚马逊试图“遏制强有力的监管”。他认为,这些公司努力推动联邦层面的监管,是因为全国性的法律通常代表着底线,与地方性法律相比,它们不太可能对私营公司如何使用该技术进行限制。

目前看来,学术伦理和技术盲区的问题正在逐步解决,人脸识别的“狂奔”之路并不会因此减速。在人脸识别技术大范围应用之前,这可能是我们拥有自己面孔的最后时光。

终有一天,我们的脸将不再属于我们,但在此之前,我们对这项技术的了解决定了我们会成为受益者还是受害者。当科技公司不断地缩小问题的讨论范围,将公共治理转变为服务条款协议,我们能做的就是在一方设定条款的时候,不要当不感兴趣的另一方,只会简单地说:“我同意。”

本文来自微信公众号:全媒派(ID:quanmeipai),封面:视觉中国