微信机器人的架设

1.安装docker。装完之后别忘了在advance目录里设置一下镜像所在目录,还有就是设置share文件夹把要给docker使用的磁盘share给docker

2.使用

docker pull registry.docker-cn.com/zixia/wechaty

来拉取中国区镜像,关于中国区镜像问题可以参考。

https://www.docker-cn.com/registry-mirror

3.挂载镜像文件

docker run -ti –rm –volume=”F:\mycode\wechaty”:/bot registry.docker-cn.com/zixia/wechaty mybot.js

这里的–volume后面的路径要求是当前之前share过的那个磁盘的路径,否则无法加载,这句话的意思就是挂载wechaty这个文件夹为镜像里的bot目录,因为wechaty默认运行的路径就是启动bot目录下的mybot.js这个文件。

写好之后可以用-d 命令长期后台。下面考虑做出一个接口,让这个bot可以访问一些内部服务,于是只要发指令给bot,bot就可以查询内部接口返回结果了。

4.接下来尝试将现有数据序列化,首先下载了一个mongo镜像

docker run -d -p 27017:27017 -v mongo_configdb:/data/configdb -v mongo_db:/data/db –name mongo docker.io/mongo

然后下载并运行了一个mong-express镜像
docker run –link mongo:mongo -p 8081:8081 mongo-express

现在本地有一个数据库服务器和一个数据库服务器的管理器了。下一步可以考虑写一个express的接口了。

Advertisements

appium连接夜神模拟器

首先需要安装appium,直接从官网下载即可。

打开之后并不需要配置它和模拟器的连接,模拟器连接是靠ADB来做的。

接着在夜神模拟器目录下执行adb device命令,活的当前活动设备的列表,如果显示

E:\nopx\Nox\bin>adb devices
List of devices attached
127.0.0.1:62001 device

这种即表示完成了,接着把这个目录下的adb加到path里面,让任何目录调用的时候都能找到他。

当然还需要安装python的类库pip install Appium-Python-Client

# coding=utf-8
from appium import webdriver
接着就在python里引用然后调用
driver = webdriver.Remote(‘http://127.0.0.1:4723/wd/hub’, desired_caps)
注意这里的http地址其实是appuim配置服务器的地址和端口。

去天津玩了一趟

据说所有事情都早晚会变成回忆。所以为了让回忆有趣意一点,我来记述一下这两天去天津旅游的行程。

第一天早晨乘坐九点多的高铁一路顺利的到达天津。下车之后出错了站台,导致后来选错了酒店。

在酒店踌躇半天之后跑去看了张学良故居

以上是张学良故居的一角。

中午在金牌餐厅吃了八珍豆腐。这个菜很好吃


下午去听了人民公园里的西岸相声。我常来听,主要是为了发掘自己有多高明


晚上在听一居吃了天津老爆三


第二天逛了大悲禅院


中午吃了包子

Reload Express.js application on file save

When you start with Node.js and Express you are probably friends with
CTRL + S (Save file)

CMD + Tab (Mac, switch windows)

CTRL + C (Stop server/application in terminal)

UP ARROW then ENTER (Restart server/application)

However there are tools to do this for you, one is Nodemon, and you can install this globably with
npm install -g nodemon
For your standard Node.js app which you start with node server.js you change that call to nodemon server.js. Now, each time you make a change Nodemon will handle restarting the app … think of it frantically calling CTRL+C, UP ARROW & ENTER in the background for you.
For Express.js the setup is slightly different. From the terminal you would use something like this (Mac/Linux) npm start or DEBUG=myApp npm start to get your project up and running on http://localhost:3000. To use Nodemon here you need to edit your projects package.json file so it looks like this

  “scripts”:{

    // “start”: “node ./bin/www”

    “start”: “nodemon ./bin/www”

   }
Once that’s done, start your Express.js project the normal way and each time you make a change you can go straight to the browser and refresh the page.

Nodejs里的异步编程模型

三套机制

  • 事件发布/订阅模式。
  • Promise/Deferred模式。
  • 流程控制库。

事件发布/订阅模式的操作极其简单,示例代码如下:

// 订阅
emitter.on("event1", function (message) {
  console.log(message);
});
// 发布
emitter.emit('event1', "I am message!");

可以看到,订阅事件就是一个高阶函数的应用。事件发布/订阅模式可以实现一个事件与多个回调函数的关联,这些回调函数又称为事件侦听器。通过emit()发布事件后,消息会立即传递给当前事件的所有侦听器执行。侦听器可以很灵活地添加和删除,使得事件和具体处理逻辑之间可以很轻松地关联和解耦。

事件发布/订阅模式自身并无同步和异步调用的问题,但在Node中,emit()调用多半是伴随事件循环而异步触发的,所以我们说事件发布/订阅广泛应用于异步编程。

事件发布/订阅模式常常用来解耦业务逻辑,事件发布者无须关注订阅的侦听器如何实现业务逻辑,甚至不用关注有多少个侦听器存在,数据通过消息的方式可以很灵活地传递。在一些典型场景中,可以通过事件发布/订阅模式进行组件封装,将不变的部分封装在组件内部,将容易变化、需自定义的部分通过事件暴露给外部处理,这是一种典型的逻辑分离方式。在这种事件发布/订阅式组件中,事件的设计非常重要,因为它关乎外部调用组件时是否优雅,从某种角度来说事件的设计就是组件的接口设计。

从另一个角度来看,事件侦听器模式也是一种钩子(hook)机制,利用钩子导出内部数据或状态给外部的调用者。Node中的很多对象大多具有黑盒的特点,功能点较少,如果不通过事件钩子的形式,我们就无法获取对象在运行期间的中间值或内部状态。这种通过事件钩子的方式,可以使编程者不用关注组件是如何启动和执行的,只需关注在需要的事件点上即可。下面的HTTP请求是典型场景:

var options = {
  host: 'www.google.com',
  port: 80,
  path: '/upload',
  method: 'POST'
};
var req = http.request(options, function (res) {
  console.log('STATUS: ' + res.statusCode);
  console.log('HEADERS: ' + JSON.stringify(res.headers));
  res.setEncoding('utf8');
  res.on('data', function (chunk) {
    console.log('BODY: ' + chunk);
  });
  res.on('end', function () {
    // TODO
  });
});
req.on('error', function (e) {
  console.log('problem with request: ' + e.message);
});
// write data to request body
req.write('data\n');
req.write('data\n');
req.end();
  • 如果对一个事件添加了超过10个侦听器,将会得到一条警告。这一处设计与Node自身单线程运行有关,设计者认为侦听器太多可能导致内存泄漏,所以存在这样一条警告。调用 emitter.setMaxListeners(0);可以将这个限制去掉。另一方面,由于事件发布会引起一系列侦听器执行,如果事件相关的侦听器过多,可能存在过多占用CPU的情景。
  • 为了处理异常,EventEmitter对象对error事件进行了特殊对待。如果运行期间的错误触发了error事件,EventEmitter会检查是否有对error事件添加过侦听器。如果添加了,这个错误将会交由该侦听器处理,否则这个错误将会作为异常抛出。如果外部没有捕获这个异常,将会引起线程退出。一个健壮的EventEmitter实例应该对error事件做处理。

 

angularjs和WebApp(试着翻译)

2.0跟IE的关系

IE6和IE7无法特别稳定执行,因为custom tags 和 hashchange events无法使用

在IE8里面则需要手动定义自定义标签,并插入到DOM树上,比如(document.createElement(‘ng-pluralize’),document.createElement(‘ng-view’)

3.0数据绑定和作用域切换

事件绑定机制根据事件自动触发,触发之后进行数据检查,$scope本身提供了一个key/value存储的哈希表。输入事件(比如键盘被按键了,鼠标焦点之类)、浏览器事件(timeout一类)、服务唤起(比如$http一类的)都会导致脏数据检测。顺便有些情况下,比如地址栏被改变了,或者你希望直接改变那里面的数据,就得手动调用 $scope.$apply()。一般情况下不推荐这么做。

4.0 $rootScope对象之妙用

每个controller里面的scope都是rootscope的子类,然后跟rootscope其实有联系。

$scope extends $rootScope

看个例子

App.run([‘$rootScope’,function($rootScope) { //this will be available to all scope variables $rootScope.includeLibraries = true; //this method will be available to all scope variables as well $rootScope.include = function(libraries) { var scope = this; //attach each of the libraries directly to the scope variable for(var i=0;i<libraries.length;i++) { var key = libraries[i]; scope[key] = getLibrary(key); } return scope; }; }]);

controller实例里面可以解决的方式如下

App.controller(‘SomeCtrl’, [‘$scope’, function($scope) { if($scope.includeLibraries) { //the flag was set in the $rootScope object $scope = $scope.include([‘plugin1’, ‘library1’]); } }]);

5.$apply 和 $digest 和 $$phase

如果在angularjs中引入了第三方类库,你需要有个额外的功能监视数据的变化,比如第三方框架使用了某些动作改变页面数据,这时候需要调用 $scope.$apply(),这个动作意味着调用了$watch把所有的变量变化都监控了一下,本来这件事是系统后台调用的。

部分情况下这个动作可能会抛出异常,因为后台此时正在运行一个digest,为了避免这种情况的发生,需要使用一个全局对象 $scope.$$phase来判断当前是否有后台进行的数据更新操作。

于是为了稳妥起见我们可以自己使用 下面的安全更新操作

//when you add it to the $rootScope variable, then it’s accessible to all other $scope variables. $rootScope.$safeApply = function($scope, fn) { fn = fn || function() {}; if($scope.$$phase) { //don’t worry, the value gets set and AngularJS picks up on it… fn(); } else { //this will fire to tell angularjs to notice that a change has happened //if it is outside of it’s own behaviour… $scope.$apply(fn); } }; //and you can run it like so. $scope.some_value = ‘value…’; $scope.$safeApply($scope, function() { //this function is run once the apply process is running or has just finished });

下面有个例子,这里我们要修改location url所以使用下面的代码

//be sure to inject $scope and $location somewhere before this var changeLocation = function(url, force) { //this will mark the URL change $location.path(url); //use $location.path(url).replace() if you want to replace the location instead $scope = $scope || angular.element(document).scope(); if(force || !$scope.$$phase) { //this will kickstart angular if to notice the change $scope.$apply(); } };

6.0在services和controller中进行通信

如果现在有个用户动作需要影响几乎所有的controller和directive的话,那就需要使用$emit, $on and $broadcast

如果你现在有个需要所有controller都处理的事件,可以用broadcast来做

//get the topmost scope var $scope = angular.element(document).scope(); //logout event var logoutEvent = ‘logout’; var logoutArgs = [‘arg’]; $scope.$broadcast(logoutEvent, logoutArgs); //login event var logoutEvent = ‘logout’; var logoutArgs = [‘arg’]; $scope.$broadcast(logoutEvent, logoutArgs);

接下来在每个controller里面接收代码如下

// //in your controller

//

App.controller(‘Ctrl’, [‘$scope’, function($scope)

{ $scope.$on(‘logout’, function(args) { alert(‘bye bye’); });

$scope.$on(‘login’, function(args) { alert(‘hello there’); }); }]);

在directive里面

// //in your directive // App.directive(‘sessionStatus’, function() { return function($scope, element, attrs) { $scope.$on(‘login’, function() { element(‘html’, ‘You are logged in!’); }); $scope.$on(‘logout’, function() { element(‘html’, ‘You are logged out!’); }); }; });

如果在是字controller里面提交一个动作给全局,那么可以用$emit

App.controller(‘Ctrl’, [‘$scope’, function($scope) { $scope.onLogoutClick = function() { $scope.$emit(‘logout’); } }]); //upper $scopes will respond to this with the same $on method.

7.0 为router上的controller加上点附加处理功能

example of it:

//checkout the route code below first before reading this
App.controller('Ctrl', ['$scope', '$http', 'argument1', 'argument2', 'argument3',
                function($scope,   $http,   argument1,   argument2,   argument3) {
  alert(argument1); //someDependeny's value or toString method
  alert(argument2); //"some value"
  alert(argument3); //the response.data value returned from GET /path/to/some/url
}]);

//here's where the magic happens
App.config(['$routeProvider',function($routeProvider) {
  $routeProvider.when('/some/page/with/an/:id',{
    templateUrl: '/path/to/some/template.html',
    controller: Ctrl,
    resolve: {
      // this is a registered dependency and works the same
      // as a dependeny injection would within a controller
      argument1: 'someDependency', 

      //this is resolved instantly since there is nothing going on
      argument2: function() { return 'some value'; }, 

      argument3: function() {
        return $http.get('/path/to/some/url',function(response) {
          //this is what is returned as the value for argument3
          return response.data; 
        }
      }
    }
  });
}]);

When the application makes it’s way to the path /some/page/with/an/:id

这个动作实际上就是绕过router的动作,直接处理请求并发起请求绕过了。这算是一种补充数据的办法

当然,还可以直接改router对象

The $route variable can also be injected directly into the controller and this can be used to fetch information about the current route:

App.controller('Ctrl', ['$route', function($route) {
  $route.current.templateUrl; //the URL of the template
  $route.current.params; //same as $routeParams
  $route.current.controller; //the name of the controller (Ctrl)
}]);

继续

8.0自定义自己的services

your application.

App.factory('myHttp',['$http',function($http) {
  return function() {
    get : function(url, success, fail) {
      $http.get(url).success(function(response) {
        return response.data;
      }).error(fail);
    }
  };
}]);

//this service can now be called by doing...
$myHttp.get('/path', function(data) {
  alert(data);
});

Also, below is a description of how data is shared between services within the same model.

App.factory('myFoo',['$http',function($http) {
  //any variables defined in this area will be ACCESSIBLE
  //within the any of the other services which are defined
  //within the same module. So if a variable called foo...
  var foo = 'bar';
  //then foo can be accessed in another service. Be sure to
  //keep this in mind since it's hard to debug
  return foo;
}]);

App.factory('myBar',['$http',function($http) {
  var bar = 'bar2';
  return foo.toString() + bar; //this should return either bar2 or barbar2
}]);

You can also inject any of your own services into any other services when created; this is very useful for code reuse and testing.

这地方就是自己弄个一个services,封装了原来的http动作,然后加上了点自己的动作。

9.0 ngshow什么的改变css

The same effect can be created by using angular

<div class="session">
  <span class="admin" data-ng-show="isAdmin">Hello Adminspan>
  <span class="admin" data-ng-hide="isAdmin">Hello Userspan>
div>

Just be sure to set the binding value

$scope.isAdmin = true; //or false or whatever

This works, but when the page is still downloading (when first loaded) you may see both values at the same time so to get around this just use cloaking.

<div class="session ng-cloak">...div>

And define the CSS for it as well:

.ng-cloak {
  /* this will change to block when scope and angular is ready */
  display:none;
}

Oh! And one more thing. If you wish to set the isAdmin value directly into your HTML, then do the following using the data-ng-init:

<div class="session ng-cloak" data-ng-init="isAdmin=false;">
  <span class="admin" data-ng-show="isAdmin">Hello Adminspan>
  <span class="admin" data-ng-hide="isAdmin">Hello Userspan>
div>

The data-ng-init attribute is useful for pre-setting values

10.错误异常捕获

route is not recognized within your application.

$routeProvider.when('/404',{
  controller : ErrorCtrl
});
$routeProvider.otherwise({
  redirectTo : '/404'
});

then you can capture the event within your scope by doing the following:

App.run(['$rootScope','$location',function($rootScope, $location) {
  $rootScope.$on("$routeChangeError", function (event, current, previous, rejection) {
    //change this code to handle the error somehow
    $location.path('/404').replace();
  });
}]);

set a custom service to wrap all your AJAX calls then you can catch errors before they’re passed onto other parts of your application.

App.factory('myHttp',['$http','$location',function($http, $location) {
  var onEmpty = function() {
    window.location = '/404';
  };

  return function() {
    get : function(url, success, fail) {
      $http.get(url).success(function(response) {
        var data = response.data;
        if(!data) {
          onEmpty();
          return;
        }
        success();
      }).error(onEmpty);
    }
  };
}]);

Be sure to only use this method when you access resources and data that is required within your application (like JSON data for a specific view).

11 使用$index在循环中获取循环变量进度

To get access to the index of a loop in angular you can access it from the $index value directly.

<ol>
  <li data-ng-repeat="option in options">
    <h2>Option #{{ $index + 1 }}: {{ option.value }}h2>
  li>
ol>

Keep in mind that there are also other options available such as $first, $middle, and $last. All of these and more are covered within the

location对象的获取

angular可以处理location对象,专门用于保存本地链接地址的哈希值

To keep track of the URL when it changes, you will need to setup a polling event.

App.run(['$rootScope', '$location', function($rootScope, $location) {
  $rootScope.$watch(
    function() { return $location.path() },
    function(path) {
      //new path!
      alert(path);
    }
  );
}]);

Additionally you can set these events explicitly within your scope variable

App.run(['$rootScope', function($rootScope) {
  $rootScope.$on('$locationChangeStart', function(event, newUrl) {
    alert('new location');
  });
}]);

自定义filter

App.filter(‘my’, function() {
return function(data) {
return data;
};
});
You can use of these filters directly in your HTML:

<span class=”some-data”>{{ value | my }}<span>
Or you can also access these filters directly in your services and controllers via dependency injection.

App.factory(‘someService’, [‘$filter’, function($filter) {
return function(data) {
return $filter(‘my’)(data);
};
}]);

表单的处理

<form novalidate class=”simple-form”>
<ol class=”fields”>
<li>
<label for=”input-name”>Name:</label>
<input id=”input-name” type=”text” data-ng-model=”name” />
</li>
<li>
<label for=”input-email”>Email:</label>
<input id=”input-email” type=”email” data-ng-model=”email” />
</li>
</ol>
<button data-ng-click=”submit()”>Submit</button>
</form>

表单出来的时候是处理的双向绑定数据,数据提交需要自己处理

这是国家化代码的例子

Ideally you wouldn’t stick the english translations directly into your own webapge so you can switch this so that translations are looked up in a global translation lookup table.

You would have to define your own lookup since this is something angular doesn’t provide by itself.

var LOOKUP = {
‘messages.zero’ : ‘No have no messages in your inbox’,
‘messages.one’ : ‘You have one message in your inbox’,
‘messages.many’ : ‘You have %messagesCount% messages in your inbox’
}
var translate = function(key, args) {
var data = LOOKUP[key];
if(data) {
for(var key in args) {
var value = args[key];
key = ‘%’ + key + ‘%’;
data = data.replace(key,value);
}
return data;
}
return ”;
};

时间日期国际化的例子

<!– this shows up as Sep 9, 2012 –>
<span class=”string-date”>{{ site.curl_left }} ‘2012-09-01′ | date:’medium’ {{ site.curl_right }}</span>

<!– same thing but longer and using a variable –>
<span class=”string-date”>{{ site.curl_left }} someDateVariable | date:’fullDate’ {{ site.curl_right }}</span>

<!– and you can set your own –>
<span class=”string-date”>{{ site.curl_left }} anotherDateVariable | date:’EEEE, MMMM d,y’ {{ site.curl_right }}</span>
You can also access the date filter directly within your controllers and services with use of the $filter service.

var dateFilter = $filter(‘date’);
var mediumDateString = dateFilter(‘2012-09-01’, ‘medium’);
var fullDateString = dateFilter(someDateVariable, ‘fullDate’);
var anotherDateString = dateFilter(anotherDateVariable, ‘EEEE, MMMM d,y’);