魑魅魍魉 发布的文章

默认参数


```
var  link  =  function(height  =  50,  color  =  'red',  url  =  'http://azat.co')  {
...
}
```

箭头函数

var fn = arg1 => arg1 * 2

多行字符串

var text = `this is
 text

模板表达式


```
var  name  =  `Your  name  is  ${first}  ${last}`
```

Promise

new Promise((resolve, reject) => {
    if (success) {
        resolve(true)
    }
    else {
        reject('error')
    }
}

块级作用的 let 和 const

let writableVariable = 1
const constantVariable = 2

class Obj {
    constructor (props) {
      this.props = props
    }

    log () {
        console.log(this.props)
    }
}

模块化

export const edit = () => console.log('edit')
import { edit } from './edit.js'

拆包表达式


    ```
    let obj = { name: '', slug: '' }
    let { name,: title  slug } = obj
```

改进的对象表达式

首先,一个简单的JavaScript时间线,不了解历史的人也无法创造历史。

  1. 1995年:JavaScript以LiveScript之名诞生
  2. 1997年:ECMAScript标准确立
  3. 1999年:ES3发布,IE5非常生气
  4. 2000年-2005年:XMLHttpRequest,熟知为AJAX,在如Outlook Web Access(2002)、Oddpost(2002)、Gmail(2004)、Google Maps(2005)中得到了广泛的应用
  5. 2009年:ES5发布(这是我们目前用的最多的版本),带来了forEach / Object.keys / Object.create(特地为Douglas Crockford所造,JSON标准创建者) ,还有JSON标准。

历史课上完了,我们回来讲编程。

ES6中还有很多你可能都用不上(至少现在用不上)的可圈可点的特性,以下无特定顺序:

  1. Math / Number / String / Array / Object中新的方法
  2. 二进制和八进制数据类型
  3. 自动展开多余参数
  4. For of循环(又见面了CoffeeScript)
  5. Symbols
  6. 尾部调用优化
  7. generator
  8. 更新的数据结构(如MapSet

如果按面向对象的思路去讲 JavaScript 的 new,还是很难去理解,我们可以从另一个方向去理解一下它。

你这些人类

我是一名程序员,也是一个人,我可能:

  • 有一个响亮亮的名称
  • 在某一天出生
  • 是个男人
  • 我能行走
  • 我还能跑步
  • 还能跳跃
  • 能说话
  • 我还能写代码

那么,在 JavaScript 中,我们可能像下面这样表达我:

const me = {
  name: '大胡子农同工潘半仙',
  birth: '1988-08-08',
  sex: 'male',
  walk: function (speed, direction, duration) {
    // 以 speed 的速度向 direction 方向行走 duration 长的时间
  },
  run: function (speed, direction, duration) {
    // 像跑步一样,速度
  },
  jump: function (high, direction, angle) {
    // 以 angle 角度向 direction 方向跳 high 高
  },
  speak: function (letters) {
    // 说出 letters 这些词
  },
  coding: function (language, line) {
    // 写程序呢
  }
}

你们这些人类

当然,这个世界上不可能只有我一个程序员,更不可能只有我一个人,就像我们这个小公司,就有七八百人,似乎所有这些人的数据都保存在数据库里面:

namesexbirth
潘韬male1988-08-08
高超male1985-08-09
春雨male1999-08-08

我们从数据库中查询出上面这几条记录,在 JavaScript 可能表示为一个二维数据,然后要创建出这三个人来,可能是下面这样的:

const people = DB.query()
// people = [['潘韬', 'male', '1988-08-08'], [...], [...]]
for (let i = 0; i < people.length; i++) {
  let [name, sex, birth] = people[i]
  people[i] = {
    name,
    sex,
    birth,
    walk: function () {},
    run: function () {},
    jump: function () {},
    speak: function () {},
    coding: function () {}
  }
}

重复的资源占用

上面大家已经发现,像上面这样去创建三个对象, walkrunjumpspeakcoding 这五件能做的事情(方法),其实做法都一样,但是我们却重复的去描述该怎么做了,其实就占用了很多资源,所以,我们可能会像下面这样改进一下:

const walk = function walk () {}
const run = function run () {}
const jump = function jump () {}
const speak = function speak () {}
const coding = function coding () {}

for (let i = 0; i < people.length; i++) {
  let [name, sex, birth] = people[i]
  people[i] = {
    name,
    sex,
    birth,
    walk,
    run,
    jump,
    speak,
    coding
  }
}

不同的人共用相同的资源(方法)

但是这个世界不止有人类

对,人类相比于这个世界上的其它生物来讲,数量根本就值得一提,如果像上面这样,可能各种不同物种能做的事情都会要定义出不同的函数,蠕动肯定不是人类会去做的事情,但很多别的生物会做,那么为了代码管理方便,我们把人能做的所有事情都放在一个对象里面,这样就相当于有了一个命名空间了,不会再跟别的物种相冲突:

const whatPeopleCanDo = {
    walk: function () {},
    run: function () {},
    jump: function () {},
    speak: function () {},
    coding: function () {}
}
for (let i = 0; i < people.length; i++) {
  let [name, sex, birth] = people[i]
  people[i] = {
    name,
    sex,
    birth,
    ...whatPeopleCanDo
  }
}

原型

但是,有的人可能我们并不知道他的 sex 信息是多少,有的也有可能不知道 birth 是多少,但是我们希望在创建这个人的时候,能给不知道的数据一些初始数据,所以, whatPeopleCanDo 并不能完全的表达出一个人,我们再改进:

const peopleLike = {
    name: '',
    sex: 'unknown',
    birth: '',
    walk: function () {},
    run: function () {},
    jump: function () {},
    speak: function () {},
    coding: function () {}
}
for (let i = 0; i < people.length; i++) {
  let [name, sex, birth] = people[i]
  people[i] = {
    ...peopleLike,
    name: name || peopleLike.name,
    sex: sex || peopleLike.sex,
    birth: birth || peopleLike.birth
  }
}

这样一来,我们就可以为不知道的属性加一些默认值,我们称 peopleLike 这个东东就为原型,它表示了像人类这样的物种有哪些属性,能干什么事情。

原型链

虽然上面已经比最开始的版本好得多了,但是还是能有很大的改进空间,我们现在像下面这样改一下:

const peoplePrototype = {
    name: '',
    sex: 'unknown',
    birth: '',
    walk: function () {},
    run: function () {},
    jump: function () {},
    speak: function () {},
    coding: function () {}
}
for (let i = 0; i < people.length; i++) {
  let [name, sex, birth] = people[i]
  people[i] = {
    name: name || peoplePrototype.name,
    sex: sex || peoplePrototype.sex,
    birth: birth || peoplePrototype.birth,
    __proto__: peoplePrototype
  }
}

我们不再把人类原型里面的所有方法都绑定到某个人身上,而是像上面这样,用一个特殊的字段 __proto__ 来指定:我的原型是 peoplePrototype 这个对象,同时,我们还制定了一个规则:如果你想请求我的某个方法,在我自己身上没有,那就去我的原型上面找吧,如果我的原型上面没有,那就去我的原型的原型上面去找,直到某个位置,没有更上层的原型为止

像上面这样创建的 people 对象,有自己的属性,但是当我们去访问 people.speak() 方法的时候,其实访问的是 people.__proto__.speak(),这是我们的规则。

更优雅的创建新新人类

我们总不能在需要创建新人的时候,都像上面这样,自己去写一个对象,然后再手工指定它的原型是什么,所以,我们可以创建一个函数,专门用来生成人类的:

const peoplePrototype = {
    name: '',
    sex: 'unknown',
    birth: '',
    walk: function () {},
    run: function () {},
    jump: function () {},
    speak: function () {},
    coding: function () {}
}
const makePeople = function makePeople(name, sex, birth) {
  let people = {}
  people.name = name || peoplePrototype.name
  people.sex = sex || peoplePrototype.sex
  people.birth = birth || peoplePrototype.birth
  people.__proto__ = peoplePrototype
  return people
}

people = people.map(makePeople)

现在这样我们只需要引入 makePeople 这个函数就可以随时随地创建新人了。

更优雅一点的改进

显然,上面这样并不是最好的办法,定义了一个原型,又定义了一个原型对象,我们可以把这两个合并到一起,所以,就可以有下面这样的实现了:

const People = function People (name, sex, birth) {
  let people = {}
  people.name = name || People.prototype.name
  people.sex = sex || People.prototype.sex
  people.birth = birth || People.prototype.birth
  people.__proto__ = People.prototype
  return people
}

People.prototype = {
    name: '',
    sex: 'unknown',
    birth: '',
    walk: function () {},
    run: function () {},
    jump: function () {},
    speak: function () {},
    coding: function () {}
}

我们直接把创建人类的那个函数叫作 People,这个函数有一个属性叫 prototype,它表示用我这个函数创建的对象的原型是什么,这个函数做的事情还是以前那些事儿,创建临时对象,设置对象的属性,绑定一下原型,然后返回。

神奇的 this

我们除了人,还有别的动物,比如 TigerFish等,按上面的方式,在 Tiger() 或者 Fish() 函数里面都会建立不同的 tiger 或者 fish 名称的临时对象,这样太麻烦,我们把这种函数创建出来的对象,都可以统一叫作“这个对象” ,也就是 this object,不在关心是人是鬼,统一把所有的临时对象都叫 thisObject 或者更简单的就叫作:这个,即 this

const People = function People (name, sex, birth) {
  let this = {}
  this.name = name || People.prototype.name
  this.sex = sex || People.prototype.sex
  this.birth = birth || People.prototype.birth
  this.__proto__ = People.prototype
  return this
}

当然,上面的这一段代码是有问题的,只是假想一样,这样是不是可行。

new

到现在为止,我们发现了整个代码的演变,是时候引出这个 new 了,它来干什么呢?它后面接一个类似上面这种 People 的函数,表示我需要创建一个 People 的实例,它的发明就是为了解决上面这些所有重复的事情,有了 new 之后,我们不需要再每一次定义一个临时对象,在 new 的上下文关系中,会在 People 函数体内自动为创建一个临时变量 this,这个就表示即将被创建出来的对象。同时,对于使用 new 创建的实例,会自动的绑定到创建函数的 prototype 作为原型,还会自动为 People 创建一个 constructor 函数,表示这个原型的创建函数是什么,所以,我们可以改成下面这样的了:

const People = function People (name, sex, birth) {
  this.name = name || People.prototype.name
  this.sex = sex || People.prototype.sex
  this.birth = birth || People.prototype.birth
}

People.prototype.name = ''
People.prototype.sex = 'unknown'
People.prototype.birth = ''
People.prototype.walk = function () {}
People.prototype.run = function () {}
People.prototype.jump = function () {}
People.prototype.speak = function () {}
People.prototype.coding = function () {}

people = people.map(p => new People(...p))

总结

new 到底干了什么?当 new People() 的时候

  1. 创建临时变量 this,并将 this 绑定到 People 函数体里
  2. 执行 People.prototype.constructor = People
  3. 执行 this.__proto__ = People.prototype
  4. 执行 People 函数体中的自定义
  5. 返回新创建的对象

已经入了人生中第一台胶片相机,GSW690 II,是一台 6x9 画幅的120相机,现在主要还是拍黒白的,不过,我也确实拍得不怎么样,但是这个过程还是很不错的,第一次去了北京东方明珠图片社,做了胶片的冲洗、底扫,同时,还直接给第一卷8张冲洗了15寸的照片,不过说实话,冲洗质量真的不怎么样。

华威西里公交站

华威西里公交站

华威西里公交站

华威西里公交站

中国尊

中国尊

潘家园十字路口

潘家园十字路口

金帝广场外的早餐亭

金帝广场外的早餐亭

中国尊

中国尊

中国尊

中国尊

中国尊

中国尊

第一郑基本上就是在试快门了,手机上面装了一个测光App提供测光,还是有很多问题,旁轴机还没有适应,以后慢慢练习吧,就是成本有点高,摄影这个坑总是越跳越深的,这不开始想着要自己冲洗胶片了,查找了一些资料,似乎也不是很难,记录一下学习笔记,往后如果自己冲洗成功了,再来一篇详细点的冲洗笔记。

需要的工具

  • 黑白胶片 Black & white film
  • 135胶片盒开盖器 Cassette end cap remover
  • 剪刀 Scissors
  • 显影罐 Developing tank
  • Spiral
  • Film clips or pegs
  • 计时器 Timer
  • Large measuring cylinders * 3
  • Small measuring cylinder
  • 吸管 Pipette
  • 温度计 Thermometer
  • Squeegee
  • 塑胶手套 Rubber gloves
  • 护目镜 Safety glasses

需要的药水

  • Developer: This makes the image appear on the film (ILFOTEC DD-X)
  • Stop bath: Brings development to an end (ILFOSTOP)
  • Fixer: Makes the developed image permanent
  • Wetting agent: Helps the film dry quickly and evenly

实体店

北京

  • 今日捷成图片社

    • 地址:海淀区羊坊店西路20号
    • 电话:010-51650999
  • 东方明珠图片社

    • 地址:西城区宣武门内大街,西单地铁站下向南
    • 电话:010-66062820
    • 评价:普通彩色负片、黑白就不用往这送了,反转片冲洗还可以
  • Spring Cameras

    • 地址:东城区车辇店胡同52号(近北锣鼓巷)
    • 电话:010-67292366
  • 盛世九州图片社

    • 地址:西城区 官园胡同甲1-1号(近梅兰芳大剧院)
    • 电话:010-66517144
    • 评价:大众评价不太好的一个店

哈尔滨

  • 影友图片社(安发街店)

    • 地址:道里区安发街31号(近安固街)
    • 电话:0451-84548543

广州

  • GZnow青年影像

    • 地址:广州市天河路365号天俊阁1603
    • 电话:020-85165985
  • 八景摄影冲印(华师店)

    • 地址:天河区 华师科技大楼155-156号(地铁华师站E出口)
    • 电话:020-85213937
  • 八景摄影冲印(总店)

    • 地址:海珠区 赤岗西路236-238号金帆大厦1楼(近珠影公交站)
    • 电话:020-84204605 020-89885362

青岛

  • 天堂鸟图片社

    • 地址:市北区延安路174号

淘宝冲扫查询:

我一直玩户外都有拍视频记录的习惯,最近半年一直想着拍VLog(当然以前的只是记录),但是直到现在才真正的试着先计划分镜再拍,第一个,下面任何一个链接都可以看,如果想看4K的,选择 Youtube,国内打不开的话,自己想办法。

下一次还需要注意,我应该再加上下面这些分镜:

  • 起床
  • 收拾装备
  • 关灯出门
  • 电梯间
  • 步行前往地铁站
  • 进入地铁站(展示地铁站名称)
  • 安检
  • 手机进地铁
  • 地铁车辆驶入
  • 进地铁
  • 出地铁
  • 上大巴

前面这些总共不超过36秒,大概3秒一个分镜

大巴到达目地地的时候,下车过程以及刚进山的过程必须得有。

在拍摄过程中,摄像机位写好后,还是没有演好,唉,得努力练习演技了。

最近在做一个新的基于 Flutter 应用,创建应用的命令是:

flutter create -i swift -a kotlin app

依赖了自己开发的 wechat 插件,之后执行 flutter run 的时候,就一直报下面这个错误了:

code's output:
    === BUILD TARGET Runner OF PROJECT Runner WITH CONFIGURATION Debug ===
    While building module 'wechat' imported from /Users/pantao/workspace/gitee/onmr/chain-app/ios/Runner/GeneratedPluginRegistrant.m:6:
    In file included from <module-includes>:1:
    In file included from /Users/pantao/workspace/gitee/onmr/chain-app/build/ios/Debug-iphonesimulator/wechat/wechat.framework/Headers/wechat-umbrella.h:13:
    /Users/pantao/workspace/gitee/onmr/chain-app/build/ios/Debug-iphonesimulator/wechat/wechat.framework/Headers/WechatPlugin.h:2:10: error: include of non-modular header inside framework module 'wechat.WechatPlugin':
    '/Users/pantao/workspace/gitee/onmr/chain-app/ios/Pods/Headers/Public/WechatOpenSDK/WXApi.h' [-Werror,-Wnon-modular-include-in-framework-module]
    #include "WXApi.h"
             ^
    1 error generated.
    /Users/pantao/workspace/gitee/onmr/chain-app/ios/Runner/GeneratedPluginRegistrant.m:6:9: fatal error: could not build module 'wechat'
    #import <wechat/WechatPlugin.h>
            ^
    2 errors generated.

最简单的解决办法:

TARGETS -> Build Settings -> 搜索 Allow Non -> 将 Allow Non-modular includes in Framework Modules 设置为 YES

WX20181224-200614@2x.png

就像 React Native 一样,在 Flutter 应用中,如果需要调用第三方库的方法或者有一些功能需要使用原生的开发来提供,使用 Flutter Plugin 是一种不错的方式,它本质上就是一个 Dart Package,但与其它的 package 不同点在于,Flutter 插件中一般都存在两个特殊的文件夹:androidios,如果需要编写Java、Kotlin或者 Object-C 以及 Swift 代码,我们就需要在这两个文件夹项目中进行,然后通过相应的方法将原生代码中开发的方法映射到 dart 中。

- 阅读剩余部分 -

一直都在自己的 React Native 应用中使用 Redux,其实更大情况下也是使用它来管理应用的会话状态以及当前登录的用户信息等等简单的数据,很好用,自从 Google 发布 Flutter 之后,就一直想着拿它来做点啥,准备拿一个新项目开刀,先研究下怎么把以前在 React Native 中需要用到的一些技术在 Flutter 找到对应的实现方法,本文记录下 Flutter + Redux + Redux Persist 的实现。

项目地址:https://github.com/pantao/flutter-redux-demo-app

- 阅读剩余部分 -

改 repo 仓库

cd ~/.cocoapods/repos
pod repo remove master
git clone https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git master

完成上面步骤之后,进入项目的 ios/Podfile 文件,在文件第一行前插入下面这一行:

source 'https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git'

最近创建旅行星球的星球点亮页,需要在整个屏幕中创建一个可操作并且遵行自然规则的3D地球,哦,不对,星球 —— Travo Planet,本文记录下整个开发过程。

安装 threejs

yarn add three

创建 Planet 类:

import THREE from 'three'

const defaultAspect = {
  width: window.innerWidth,
  height: window.innerHeight
}

const defaultOptions = {
  aspect: {
    ...defaultAspect
  }
}

export default class Planet {
  constructor (container, options = { ...defaultOptions }) {
    this.container = container
    this.options = {
      ...defaultOptions,
      ...options
    }

    this.init(container, options)
  }

init (container, options) {} 
}

之后的所有开发都将在这个文件中进行,要基于 ThreeJS 展示什么,我们至少需要三样东西:一个 scene,一个 camera 以及一个 renderer

  init (container, options) {
    if (this.inited) {
      return this
    }

    const {
      aspect
    } = options

    const scene = this.scene = new THREE.Scene()
    const camera = this.camera = new THREE.PerspectiveCamera(45, aspect.width / aspect.height, 0.01, 1000)
    camera.position.z = 1.5

    const renderer = this.renderer = new THREE.WebGLRenderer()
    renderer.setSize(aspect.width, aspect.height)
  }

scene 的作用用来跟踪与展示我们需要展示的对象们,接下来添加光效,如下图所示,分别为:Ambient lightDirectional light 以及 ·Ambient & Directional light`:

sphere-earth-light.jpg

scene.add(new THREE.AmbientLight(0x333333))
const directionalLight = new THREE.DirectionalLight(0xffffff, 1)
directionalLight.position.set(5, 3, 5)
scene.add(directionalLight)

安装极光插件

yarn add jpush-react-native jcore-react-native

链接插件

react-native link
# rnpm-install info Linking jcore-react-native ios dependency
# rnpm-install info Platform 'ios' module jcore-react-native has been successfully linked
# ? Input the appKey for JPush xxxxxxxxx
# patching android/settings.gradle...
# patching android/**/AndroidManifest.xml...
# patching android/**/build.gradle...
# patching ios/**/AppDelegate.m...
# done!
# rnpm-install info Linking jpush-react-native ios dependency
# rnpm-install info Platform 'ios' module jpush-react-native has been successfully linked
# rnpm-install info Platform 'android' module jpush-react-native is already linked

这一步操作会做下面这些操作:

android/settings.gradle 文件中添加下面这几行:

include ':jcore-react-native'
project(':jcore-react-native').projectDir = new File(rootProject.projectDir, '../node_modules/jcore-react-native/android')

include ':jpush-react-native'
project(':jpush-react-native').projectDir = new File(rootProject.projectDir, '../node_modules/jpush-react-native/android')

android/app/build.gradle 文件里面添加

android {
  ...
  defaultConfig {
    manifestPlaceholders = [
       JPUSH_APPKEY: "xxxxxxxx",
       APP_CHANNEL : "default"
     ]
  }
  ...
}

android/app/src/main/AndroidManifest.xmlapplicaiton 中添加两个 meta-data

<meta-data android:name="JPUSH_APPKEY" android:value="${JPUSH_APPKEY}" />
<meta-data  android:name="JPUSH_CHANNEL" android:value="${APP_CHANNEL}" />

ios/AppName/AppDelegate.m 中添加:

- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler
{
  NSDictionary * userInfo = notification.request.content.userInfo;
  if ([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
    [JPUSHService handleRemoteNotification:userInfo];
    [[NSNotificationCenter defaultCenter] postNotificationName:kJPFDidReceiveRemoteNotification object:userInfo];
  }

  completionHandler(UNNotificationPresentationOptionAlert);
}

- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler
{
  NSDictionary * userInfo = response.notification.request.content.userInfo;
  if ([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
    [JPUSHService handleRemoteNotification:userInfo];
    [[NSNotificationCenter defaultCenter] postNotificationName:kJPFOpenNotification object:userInfo];
  }

  completionHandler();
}

手动配置

IOS

在 iOS 工程中设置 TARGETS-> BUILD Phases -> LinkBinary with Libraries 找到 UserNotifications.frameworkstatus 设为 optional

在 iOS 工程中如果找不到头文件可能要在 TARGETS-> BUILD SETTINGS -> Search Paths -> Header Search Paths 添加如下路径:

$(SRCROOT)/../node_modules/jpush-react-native/ios/RCTJPushModule

在 xcode8 之后需要点开推送选项: TARGETS -> Capabilities -> Push Notification 设为 on 状态

删除原有 boost

sudo rm –rf /usr/local/include/boost
sudo rm –rf /usr/local/lib/libboost_*

brew uninstall boost

重新从官网下载 Boost

cd ./node_modules/react-native/third-party

查看 boost 版本号,从官方网站上面下载 boost https://www.boost.org/users/download/

可以下载适合你的版本。

替换 .rncache 目录下面的 boost

将下载的 boost 包复制至 .rncache 目录下,解压该文件,

cd ./boost_1_63_0
./booststrap.sh
sudo ./b2 install

再次尝试应该是可以了

react-native run-ios
如果还不行的话,可以试试直接将 /opt/local/include/boost 复制至 ./node_modules/react-native/third-party 目录下。

_GFX2906.jpg

往年的这个时候都会去北京城的各个红叶黄叶区去拍拍照,今年没有去什么人多的地方,只是在现在住的地方周边转了一下,那天下了点小雨,一个人背着相机瞎转,秋天伴着细雨落下来,安静的躺在路上,水泥就在脚下,它们已经无法归根……

- 阅读剩余部分 -

# 获取 Android 默认的 debug.keystore 指纹

keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android

# 获取生产环境使用的 keystore 指纹

keytool -list -v -keystore /path/to/NAME.keystore -alias ALIAS -storepass PASS -keypass PASS

上周末,带着 GFX 50S 去了躺内蒙,拍了几张人像,感觉全幅的细节跟中幅真的是没法比,也没怎么后期,就直接手机上面套了几个滤镜就直接上图了吧,细节基本上全部丢失。

IMG_20180911_005304.jpg

IMG_20180911_005343.jpg

IMG_20180911_005430.jpg

IMG_20180911_005130.jpg

IMG_20180911_004859.jpg

IMG_20180911_004746.jpg

IMG_20180911_004658.jpg

IMG_20180911_004513.jpg

IMG_20180911_004331.jpg

IMG_20180911_004235.jpg

IMG_20180911_004109.jpg

IMG_20180911_004010.jpg

IMG_20180911_003936.jpg

IMG_20180911_003805.jpg

IMG_20180911_003636.jpg

IMG_20180911_003607.jpg

IMG_20180911_003119.jpg

IMG_20180911_002815.jpg

IMG_20180911_002715.jpg

IMG_20180911_002546.jpg

IMG_20180911_002420.jpg

IMG_20180911_001735.jpg

IMG_20180911_001539.jpg

IMG_20180911_001047.jpg

IMG_20180911_002319.jpg

Polarr 转了几张黑白(其实机身直出黑白感觉更好):

_DSF0559_polarr_2.jpg

_DSF0561_polarr_1.jpg

佳能全出了,换了一个 Fujifilm GFX 机身 + 63mm/F2.8 镜头,这里记录一下。


更新几张样片,感觉得慢慢掌握了,就这一次上传原图了,五张图,100多M,以后得小小图了。

南新园小区楼

_DSF0013.jpg

_DSF0022.jpg

_DSF0043.jpg

_DSF0047.jpg

最近想着自己得静下心来搞摄影了,感觉自己这玩了近十年相机,其实根本就算不上是在摄影,只能说是在记录吧,这么久了跟大家说的是因为我只喜欢自然光,所以从来不使用闪光灯,虽然说我的闪都买了好几年了,到今天都还没真正的把玩过(对,把玩,我是按着自己的兴趣在玩相机,而不是以这个为主业)。

前几天我一口把很多镜头都出了,感觉用了这么多镜头,各种焦段、品牌的,感觉自己常用的也就那些,镜头多了还导致我有选择困难症,所以,就都出了吧,以后出门一台富士 XT-2 + 18-55/F2.8,因为我都是出户外拍得多,除了风景外,也给同行的人拍拍纪念照啥的,以前都不带闪光灯(镜头带得太多),这次决定为了更好的服务于广大人民,就买了一个富士的闪光灯。


有点扯远了,回到正题,什么是 TTL 功能呢?它的命名叫 *Through The Lens,其实,就是说,闪光灯跟相机已经关联在一起了,它能通过相机的拍摄参数设置以及现场环境光线来自动的决定光量。

闪光灯的快门同步速度

如果利用闪光灯拍摄,相机不单要计算现场光的曝光量,还需要计算闪光灯闪光之后的曝光量对现场光的影响,由于需要同时进行两种光的计算,加上闪光灯只在快门开放的那一刹进行照明,如果快门速度高于同步快门,还没有开启高速同步闪光功能的话,就会出一半变量的情况。为了令相片加了闪光灯后还能提供一个正确的曝光值,于是相机就有了同步快门,摄影者需要设定相机在拍摄时,速度必须比同步快门慢,才能让闪光灯均匀的照亮整个画面。

昨天把 Samba 服务器搞定了,现在已经开始用上了,之后,我把以前的移动硬盘插在了新买的华为荣耀路由器上面,启用了路由器的 Samba 服务,配置情况如下:

  • IP: 192.168.3.13
  • 用户名:username
  • 密码:password

接下来,在我的 Elementary 上面,连接该服务,并将里面的文件同步到本机。

继续之前,需要先安装 smbclient 工具:

sudo apt-get install smbclient

使用 smbclient 连接

smbclient 可以用于浏览 Samba 服务器上面的所有共享资源,也可以用于直接访问 Samba 服务器指定的共享资源。

浏览 Samba 服务器所有共享资源可以使用如下命令:

smbclient -L 192.168.3.13 -U username

输入上面命令之后,终端会要求你输入该用户名的密码,如果想直接连同密码一起输入到命令行工具中,可以像下面这样:

smbclient -L 192.168.3.13 -U username%password

终端输出如下结果:

Domain=[WORKGROUP] OS=[Unix] Server=[Samba 3.0.37]

    Sharename       Type      Comment
    ---------       ----      -------
    Seagate_usb1_1  Disk      
    Seagate_usb1_2  Disk 

如果要直接访问 Samba 服务器指定共享资源,可以使用下面这行命令:

smbclient //192.168.3.13/Seagate_usb1_2 -U username%password

输出:

Domain=[WORKGROUP] OS=[Unix] Server=[Samba 3.0.37]
smb: \> 

在 smb 环境下,我们就可以对文件进行操作。

使用 mount 方式

使用 smbclient 访问,还是很麻烦,一般我们都会将资源挂载到本地计算机上面,这样使用起来就会方便得多:

mount -t cifs //192.168.3.13/Seagate_usb1_2 /home/pantao/CloudStorages/HonorRouter -o username=username%password

如果要永久使用 Samba 服务器共享资源,可以将挂载信息写入到 /etc/fstab 文件中,在最后添加以下这行:

//192.168.3.13/Seagate_usb1_2 /home/pantao/CloudStorages/HonorRouter cifs defaults,username=username%password 0 0

由于 /etc/fstab 文件的默认权限是 0644,也就是说所有用户都可以读取,如果你不希望其它用户看到你的 Samba 用户名与密码的话,那可在 /etc/samba/pwd.conf 文件中,添加以下内容:

username=username password=password

然后在 /etc/fstab 中添加下面这行:

//192.168.3.13/Seagate_usb1_2 /home/pantao/CloudStorages/HonorRouter cifs defaults,credentials=/etc/samba/pwd.conf 0 0

 使用自动挂载

/etc/auto.master 文件中加入以下内容:

/home/pantao/CloudStorages/HonorRouter /etc/samba.misc--timeout=30 # timeout 值可以根据实际网络情况设置

然后建立 /etc/samba.misc 文件,加入以下内容:

samba-fstype=cifs,username=username,password=password ://192.168.3.13/Seagate_usb1_2

Samba,是种用来让UNIX系列的操作系统与微软Windows操作系统的SMB/CIFS(Server Message Block/Common Internet File System)网络协议做链接的自由软件。第三版不仅可访问及分享SMB的文件夹及打印机,本身还可以集成入Windows Server的网域,扮演为网域控制站(Domain Controller)以及加入Active Directory成员。简而言之,此软件在Windows与UNIX系列操作系统之间搭起一座桥梁,让两者的资源可互通有无。

 安装软件

sudo apt-get install samba

 配置共享

sudo vi /etc/samba/smb.conf

在文件末尾添加以下内容:

[public]
path=/data/nfs
browseable=yes
read only=no
guest ok=yes

文件夹的可读写权限我在已经设置好了,添加了匿名的文件读写权限。

 添加系统用户到 Samba 账号:

sudo smbpasswd -a pantao # 添加系统用户 pantao 至 samba 
在执行 smbpasswd 前,需要先添加好用户 pantao,否则命令会执行失败。

重启 samba 服务

sudo service smbd restart

客户端访问

Linux 访问

smbclient -L //192.168.3.3/public

Windows 客户端访问

可以直接访问如下地址即可:

\\192.168.3.3\public

如果 public=no,则此时需要输入 samba 的用户名与密码,如果 public=yes,则作为 nobody 用户直接访问。

另外,在 Windows 客户端可以使用 net use * /del /y 这条命令清理访问缓存。

Samba 常用参数

  • comment=smb share test:该共享的备注信息
  • path=/data/nfs:共享路径
  • allow hosts=host(subnet):设置该 Samba 服务器允许的工作组或域
  • deny hosts=host(subnet):设置该 Samba 服务器拒绝的工作组或域
  • available=yes|no:设置该共享目录是否可用
  • browseable=yes|no:设置该共享目录是否可显示
  • writable=yes|no:指定该目录缺省是否可写,也可以用 readonly = no 来设置可写
  • public=yes|no:指明该共享资源是否能给游客使用, guest ok=yes 其实与 public=yes 是一样的
  • user=user,@group: user 设置所有可能使用该共享资源的用户,也可以用 @group 代表 group 这个组的所有成员,不同的项目之间使用空格或者英文逗号隔开
  • valid users=user,@group:指定能够使用该共享资源的用户和组
  • invalid users=user,@group:指定不能够使用该共享资源的用户和组
  • read list=user,@group:指定只能读取该共享资源的用户和组
  • write list=user,@group:指定能读取和写入该共享资源的用户和组
  • admin list=user,@group:指定能管理该共享资源(包括读写和权限赋予等)的用户和组
  • hide dot files=yes|no:是否像 Unix 一样,隐藏以 . 号开头的文件
  • create mode=0755:指明新建立的文件的属性,一般是0755
  • directory mode=0755:指明新建立的目录的属性,一般是 0755
  • sync always=yes|no:指明对该共享资源进行写操作后是否进行同步操作
  • short preserve case=yes|no:是否区分文件名大小写
  • preserve case=yes|no:是否保持大小写
  • case sensitive=yes|no:是否能大小写敏感,一般选 no,不然可能会引起错误
  • mangle case=yes|no:指明混合大小写
  • default case=upper|lower:指明默认的文件名是全部大写还是小写
  • force user=testuser:强制设置新建立的文件的属主是谁,如果我有一个目录, guest 用户 可以写,那么 guest 就也可以删除文件 ,但是如果我强制把建痒痒的文件的属主设置为 testuser,同时限制 create mode=0755,那么 guest 就不能删除了
  • wide links=yes|no:指明是否允许共享外符号连接,比如共享资源里面有一个连接指向非共享资源里面的文件或者目录,如果设置为 wide links=no,将使该链接不可用
  • max connections=100:最大同时连接数
  • delete readonly=yes|no:是否能删除共享资源里面已经被指定为只读的文件