關於Cross-origin resource sharing (CORS)

總有些時候網頁可能會需要存取「其他網站」的資料,例如透過ajax,此時就會遇到cors的問題:
XMLHttpRequest cannot load “http://…” The ‘Access-Control-Allow-Origin’ header has a value ‘http://abc.com’ that is not equal to the supplied origin. Origin ‘http://def.com’ is therefore not allowed access.

webpage的header會用Access-Control-Allow-Origin定義你可以存取哪些網站的資源,當你只定義了A網站,就不能發request給B網站。解決方法也是很直觀,在header加入允許的網站清單,或是乾脆不限制任何網站

For example (nodejs + coffee)

app.use (req,res,next)->
        res.header("Access-Control-Allow-Origin", "*")
        res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS,X-XSRF-TOKEN')
        res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
        next()

另外,如果有用angularJS

app.config ['$httpProvider',($httpProvider)->
    $httpProvider.defaults.useXDomain = true
    delete $httpProvider.defaults.headers.common['X-Requested-With']
]

最後,還有一點很重要,不知道為何Chrome會cache這個header
也就是當你在localhost測試成功可以cors,丟到遠端server測試卻失敗時,試著清理你的browser cached data.

Build a Web Client with Nodejs: wireup AngularJs + Express + coffeescript + Jade + Less

廢話

有沒有這麼一個概念:「用同一套方式開發iOS、Android以及web?」隨著javascript的日益強大以及前端MVC的迅猛發展,這個概念變得越來越可行了。

一個完整的application通常包含web端以及mobile端,而web已經可以被視為iOS, Android以外的第三個「client」了。在技術的分類裡,iOS, Android, web backend的主流開發框架都已經是MVC了,惟獨剩下web frontend尚未完全「進化」成MVC。而近年來,前端MVC的優秀框架如雨後春筍般出現,像是AngularJs, Backbone, Ember …等,讓web frontend這塊紛亂之地也逐漸被MVC給攻克佔據…

一招MVC打天下,似乎不再遙不可及。

以前也是有開發過web,但在我的戰鬥經驗裡,web frontend的經驗值始終是初心者等級。現在既然有了MVC跟咖啡,是不是應該來練一下等級。用這麼酷的方式寫web我還是第一次,這些前端的MVC中,又以Google開發的angularjs最為火紅,(因為是Google大神開發的),有道是「站在巨人的肩膀上,才能看得更遠」不是嗎?所以這兩天便學了一下AngularJs,在此做個筆記~

先說說幾個開發時主要的component:

Express

Nodejs最火紅的套件之一,建立網站必備

Jade

類似rails的haml,擁有簡潔的語法,真的很簡潔,用過就會愛上,用來編譯成html

Less

類似rails的Sass,強化版的css語法,可以有變數,巢狀結構(這超重要),用來編譯成css

Coffeescript

Javascrip雖然強大,但其語法看就噁心,寫就想吐,debug更是會令人當場身亡! Coffeescript結合了ruby跟python的優點,是我看過語法最漂亮的程式語言,不只簡潔,而且有力,會幫你避掉許多Javascript語法設計不良的小毛病(例如global scope)。就像賽亞人+地球人=超強混血,沒什麼好講的,必備。

LiveReload

寫web最常做的事就是不停的reload reload re-re-re-re-reload頁面,re到手都快抽筋了,這個小工具可以讓生命更美好一點。它會在程式存檔的當下自動reload瀏覽器頁面(神奇吧),

AngularJs

前端主角,不解釋。

Notifier

Nodejs啟動時給一個桌面小提示,可含圖示跟聲音,不須切換視窗就能知道server啟動成功或失敗。 一樣是讓生命更美好的小工具

node-dev

一旦存檔就自動重啟nodejs server,搭配Notifier服用考試都100分。

bower

第三方js與css的套件管理程式,像是rails的gem,iOS的pod。意外嗎?一開始我也覺得意外,but… welcome frontend!

前面幾個component的setup在這篇文章有不錯的介紹,我就不打算贅述了,畢竟有好的輪子就不用再重新發明了是吧。(我決定繼承那篇文章然後結束這回合。)


檔案結構

一圖解千文

/api

放跟api server相關的程式。為什麼有api server? 因為我想把web搞得像client,就像mobile一樣ㄎㄎ

/bower_components

存放用bower這個前端套件管理程式所安裝的第三方套件,brow會自動創建此資料夾

/node_modules

存放用npm這個後端套件管理程式所安裝的第三方套件,npm會自動創建此資料夾

/routes

routing的規則,由於是thin server,所以只做很簡單的routing,大部份的routing會在AnglarJs裡做,在AngularJs尚未建立之前,還是需要由server供給一些基本的啟動檔案

/views

jade檔的家

/client

frontend端相關的檔案,AngularJs及Less的東西會分別存放在coffee/與less/裡,最後會compile成js與css,分別放在/public/js與/public/css資料夾裡,程式每次修改都要重來一次。(不要覺得很恐怖,這些過程都會全自動)

package.json

新增一個package.json檔,npm預設會找到這個檔案並安裝其內容,"*"代表安裝最新版本

{
  "name": "theApp",
  "version": "0.0.1",
  "description": "...",
  "author": "tpy",
  "devDependencies": {
    "express": "3.2.6",
    "request": "~2.27.0",
    "jade": "*",
    "underscore": "*",
    "routes":"*",
    "coffee-script":"*",
    "node-notifier":"*",
    "less-middleware":"*",
    "connect-coffee-script":"*",
    "livereload":"*"
  }
}

然後

npm install

另外幾個比較特別的要安裝在系統比較方便,以便當指令用

sudo npm install node-dev bower -g 

node-dev

安裝完node-dev後新增一個檔案.node-dev.json,內容如下

{
  "coffee": "coffee-script/register",
  "ls": "LiveScript",
  "clear": true
}

這讓node-dev可以看懂coffee,不需要手動compile成js,寫咖啡必備

app.coffee

...

lessDir = __dirname + '/client/less'
coffeeDir = __dirname + '/client/coffee'
publicDir = __dirname + '/client/public'
bowerDir = __dirname + '/bower_components'

lessMiddleware = require 'less-middleware'
app.configure ()->
    app.set 'port', port
    app.set 'views', __dirname + '/views'
    app.set 'view engine', 'jade'
    app.use express.favicon()
    app.use express.logger('dev')
    app.use express.bodyParser()
    app.use lessMiddleware lessDir, 
        dest: publicDir,
        force: true, # development only, force re-compile in each request
        preprocess: 
            path: (pathname, req) ->
                return pathname.replace '/css/', '/'
        # without preprocess: get http://domain/css/app.css will look up lessDir/css/app.less
        # with preprocess: get http://domain/css/app.css will look up lessDir/app.less

    app.use require('connect-coffee-script')
        src: coffeeDir,
        dest: publicDir+'/js',
        prefix : '/js'
        force: true   # development only
        # without prefix: get http://domain/js/item.js will look up coffeeDir/js/item.coffee
        # with prefix: get http://domain/js/item.js will look up coffeeDir/item.coffee

    app.use express.static(publicDir)
    app.use('/bower_components',  express.static(__dirname + '/bower_components'));

...

新版的express已經抽離less的模組,所以需要額外require 'less-middleware'。less-middleware能讓你coding時寫less,並讓client端自動收到css。由於我們的程式存放目錄跟user request的url不同,所以要額外做一些設定。我們這邊用lessDir作為less的來源資料夾,並用publicDir作為他compile成css後目的資料夾。在預設的情況下,當request http://domain/css/app.css時,less-middleware會去找lessDir/css/app.less,但很顯然我們的目錄結構並非如此,所以我們用他的preprocess功能,把/css濾掉,這樣才會找到lessDir/app.less,然後他也很聰明的是,將app.less`` compile完之後會直接放到回目的資料夾裏的正確置,也就是publicDir/css“`。

同理connect-coffee-script也是。它能讓你coding時寫coffee並讓client自動收到js。他的檔案結構跟user request的路徑也不一樣,所以一樣要做額外設定。他們的原理大同小異,但設定機制有點不同,如有興趣可以去github看官方的說明。

最後宣布publicDir就是可以直接存取的靜態檔案,無需經過routing規則,也就是

app.use express.static(publicDir)

另外附帶一提,為了讓bower安裝的套件能更方便地被存取,再新增一個靜態檔案存取規則:

app.use '/bower_components', express.static(__dirname + '/bower_components')

當請求http://domain/bower_components/時,會對應到bowerDir/

為什麼要把事情搞得複雜?

這是一個好問題,如果把coffee/js,less/css都放在同一個地方事情會簡單許多,我通常也不喜歡事情變得複雜,但是在coding的時候維持一個好的檔案目錄結構是一件很重要的事,這會讓程式碼易於被理解,我認為目錄結構應該跟request url獨立開來。

全部通通放在public然後再用express去擋coffee跟less的請求也是個做法,但這樣”public”資料夾的存取規則就有了例外,而我討厭例外。

接著套入notifier, development only

server = app.listen port, ()->
    console.log 'Web Server Started at port: '+ port
    notifier.notify 
        'title': 'Web Server Start',
        'message': 'Port: ' + port, 
        icon: './ok.png',
        sound: true

再套入livereload, development only

livereload = require('livereload').createServer
    exts: ['jade', 'less', 'coffee']
livereload.watch(coffeeDir);
livereload.watch(lessDir);
livereload.watch(__dirname+'/views');

目前整個app.coffee看起來像這樣:

express = require 'express'
path = require 'path'
notifier = require 'node-notifier'
lessMiddleware = require 'less-middleware'

port = 8888
app = express()
lessDir = __dirname + '/client/less'
coffeeDir = __dirname + '/client/coffee'
publicDir = __dirname + '/client/public'
bowerDir = __dirname + '/bower_components'

app.configure ()->
    app.set 'port', port
    app.set 'views', __dirname + '/views'
    app.set 'view engine', 'jade'
    app.use express.favicon()
    app.use express.logger('dev')
    app.use express.bodyParser()
    app.use lessMiddleware lessDir, 
        dest: publicDir,
        force: true,
        preprocess: 
            path: (pathname, req) ->
                return pathname.replace '/css/', '/'

    app.use require('connect-coffee-script')
        src: coffeeDir,
        dest: publicDir+'/js',
        prefix : '/js'
        force: true


    app.use express.static(publicDir)
    app.use '/bower_components',  express.static(bowerDir)


app.configure 'development', () ->
    app.use express.errorHandler()


server = app.listen port, ()->
    console.log 'Web Server Started at port: '+ port
    notifier.notify 
        'title': 'Web Server Start',
        'message': 'Port: ' + port, 
        icon: './ok.png',
        sound: true

# LiveReload
livereload = require('livereload').createServer
    exts: ['jade', 'less', 'coffee']
livereload.watch(coffeeDir);
livereload.watch(lessDir);
livereload.watch(__dirname+'/views');

啟動server

node-dev app.coffee

ng-app

新增一個layout.jade至/views

doctype
html(ng-app='theApp')
    head
        meta(charset='utf8')
        base(href='/')
        title HellpApp
        link(rel='stylesheet' href='/css/app.css')
        script(src='//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.js')

    body
        block body

在html標籤宣告ng-app,讓AngularJs的作用範圍等同整個document頁面。至於必要的angular.js從google的cdn拿就可以了XD。

再新增一個item.jade至/views

extends layout
block body
    .item
    script(src='/js/config.js')

目前就只有一個空的div(class="item")。注意到jade的的layout跟view是可以分開的,這把layout.jade從view中抽出,讓相依性進一步降低,rails也有類似的機制。

最後在末端載入config.js,這裡面會定義整個ng-app module,新增一個/client/coffee/config.coffee

angular.module 'theApp',[]

這一行基本上宣告了一個名為theApp的module,後面搭配一個空陣列表示沒有用到其他額外的module。這邊的module可以理解成一個容器,將來許多angular的元件像是component, filter, service, …等都必須放置在這個容器裡,基本上就是一個top level的容器,之後一些必要的設定也會在此進行,所以我把檔名命名成config,也有很多人會把檔名命名成app,up to you。

ng-controller

新增一個/client/coffee/controllers.coffee

app = angular.module 'theApp' #注意後面沒有array參數
class ItemController
    constructor: ($scope)->
        item = {title:'cup', photos:['1.jpg','2.jpg']}
        item.photos = (@getS3ImageUrl(photo) for photo in item.photos)
        $scope.item = item
    getS3ImageUrl: (imageName) ->
        url = 'http://images.theApp.com/'+ imageName

app.controller 'ItemController', ItemController

首先

app = angular.module 'theApp'

把剛剛在config.coffee定義好的theApp module拿出來,而

app.controller 'ItemController', ItemController

則把這個ItemController放進容器裡。

constructor裡有一個$scope參數,這是angular內建的service,angular會在instantiate物件時自動把所需的內建service餵進去。所有$開頭的變數都是angular的內建service。這個$scope代表的是一個DOM標籤的scope,例如



...

這個$scope就代表整個div,然後$scope.item = ...就表示我們在這個div的範圍裡定義了一個名為item的angular變數。這邊有完整的service列表。

然後

(@getS3ImageUrl(photo) for photo in item.photos)

用@getS3ImageUrl對item.photos做一點加工,並回傳一個新的array賦值回item.photos。這是coffee從python借來的list comprehension,酷吧! 其中@getS3ImageUrl的意思是this.getS3ImageUrl。

最後還有一個地方要修改,angular用關鍵字比對去認出那些內建的service像是$scope,但是在minify js檔案的時候變數名稱很可能都會被更動,如此便導致angular找不到關鍵字,解決這個問題的方式,就是我們同時把這個關鍵字也宣告成字串,這樣minify時就不會去動到它了。

app.controller 'ItemController', ItemController

改成

app.controller 'ItemController', ['$scope',ItemController]

現在我們有了item,可以在頁面中呈現資訊了,修改/views/item.jade

extends layout
block body
    .error(ng-hide="item")
    .item(ng-show="item" ng-controller='ItemController')
        .title {{item.title}}
        img(ng-repeat="photoUrl in item.photos" ng-src="{{photoUrl}}" style="margin: auto;")
    script(src='/js/config.js')
    script(src='/js/controllers.js')

首先link到controller.js,ItemController才會有定義,我們已經在ItemController裡定義了$scope.item,所以這邊就可以透過兩個大括號去access它{{item}}

這邊我們看到幾個用法

ng-hide

顧名思義,item存在時就這個tag就hide

ng-show

item存在時就這個tag就不hide,很ng-hide組合搭配很好用,能夠輕易地控制頁面內容,無需手動jQuery操作DOM

ng-repeat

這個ng-repeat一樣是用了跟coffee極度類似的list comprehension表示式,咖啡懂了這個就懂了。順帶一提ng-repeat跟ng-src不一定要在同一個tag,例如也可以這樣

ul(ng-repeat="photoUrl in item.photos")
    li img(ng-src="photoUrl")
cartoon porn
How to Become a Fashion Designer in Japan
porno As world weary and vengeance filled as the Count is

Wolverine rescues Casey Anderson on America the Wild
cartola fc cultural differences are generally described as being influenced

Do Potatoes Make You Fat
rastreamento correios ashworth interlock not hollow pullover

Getting Fierce with Christian Siriano
kinokiste Time for a trip to the anime basement

Prezzi Competitivi E Prodotti Di Marca
rape porn Sew all the seams together to make the sack dress

Picking Perfect Clothes For Petite Women
xvideos people in the past looked ridiculous

Fashion Star Episode 1 recap and Episode 2 advice
hd porn And even after I ventured forth

Best Food for Summer to Loose Weight
miranda lambert weight loss the style start obtains more compact establishing suitable for

Apple Push Notification Service (APNS): How your server push notifications to your apps?

Say, you have your own server, you want to push notifications to your apps, how to do that? Well, basically it should be easy because Apple do that for you by Apple Push Notification Service (APNS). But it’s not quite easy enough because the authentication process is cumbersome.

It’s all about authentication

Your Server -> APNS -> Your iOS apps

Under your provisioning profile, you have an App ID, if you want to enable the Push Notification, you need to create a certificate for it.

This is the way you do:

  • Create public/private key.
  • Create certificate signing request (CSR)
  • Upload the CSR to Apple to create certificate
  • Download the certificate
  • Convert the certificate to cert.pem
  • Convert private key to key.pem
  • Feed key.pem and cert.pem to your server
  • Get device token and upload it to your server
  • Start push notification in your server

CSR vs Certificate:

CSR is a request that you tell Apple you wan to get a certificate. You signed on it (with private key) first, submit to Apple and after Apple agrees your request, he generates a certificate and signed on it and give it to you.

Basically, a certificate is just like a paper that signed with you and Apple. It is a registration of your private key and your private key somehow represent yourself. It’s all about an identity of YOU.

Convert the certificate to cert.pem

In keychain access, find the certificate named “Apple Development iOS Push Server: appID”, export (cmd+shift+E) to dev_cert.p12.

openssl pkcs12 -clcerts -nokeys -in dev_cert.p12 -out dev_cert.pem

Convert private key to key.pem

In keychain access, export the private key associated with the certificate to dev_key.p12.

openssl pkcs12 -nocerts -out dev_key.pem -in dev_key.p12

And make it unencrypted:

openssl rsa -in dev_key.pem -out dev_key.unencrypted.pem

The Client Side

The client side is relatively easy: just tell iOS you want to register remote notification and implement some delegate functions.

[application registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert| UIRemoteNotificationTypeBadge |  UIRemoteNotificationTypeSound)];

This method will show up an alertView asking the user to agree with your push notification request, if the user disagree, you’ll get no tokens.

# pragma mark - Remote Notification Delegate
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    NSString *key = [[[userInfo objectForKey:@"aps"] objectForKey:@"alert"] objectForKey:@"loc-key"];
    NSString *soundFile = [[userInfo objectForKey:@"aps"] objectForKey:@"sound"];
    DLog(@"didReceiveRemoteNotification: %@",key);
}

// Once successfully received the token, you should send the token to your sever and stores it. Here is just a demo.
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
    NSString* tokenString = [[[NSString stringWithFormat:@"%@",deviceToken] stringByReplacingOccurrencesOfString:@" " withString:@""]substringWithRange:NSMakeRange(1, 64)];
    DLog(@"%@",tokenString);
}

-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{

}

A very nice ref: iOS用戶端的APNS服務簡介與實現

And some nice refs that are helpful to understand the concept:

black porn
the Perfect Shorts for Perfect Looking Summer Legs
cartola fc How to Become a Kid Catalog ModelDid pastor go too far when he told congregation to say
jogos da barbie underfunded and innovative

Dressing for the fashion shows
movie2k that’s a pretty epic crazy curse for one film

Naperville Florist L Naperville Flower Shop
ebay kleinanzeigen You can purchase one that is closest to your plan

Beyonce Makes Surprise Personal Appearance
gay porn children weren required to

An Oktoberfest Beer Girl Costume Indicates Mischievous Good Times
large porn tube Exploring their freedom motivates the Sag

Tribal Rings bring out the
snooki weight loss normal value appropriate after impression transfer is grueling

Old Fashion Sweet Potato Pie Recipe
miranda lambert weight loss and they’re not about going

Fastest: Nginx + WordPress

Fastest Approach

Recently, I found this nice repo, which is a linux script helping you build a website based on nginx/php/mysql/wordpress (or non-wordpress).

It’s awesome, quick and easy.

To see how awesome it is:

wget -qO ee rt.cx/ee && sudo bash ee     # install easyengine
ee site create example.com --wp          # Install required packages & setup WordPress on example.com

And visit http://example.com.

hd porn
Dress how you want to dress pt 2
anime porn With his relationship with Emma

The MOD Shop shopping experience and fashion show at PLUNGE hosted
rastreamento correios and ultimately loses his life

competition showcases Tampa stylists Photos
kinox -4-free arnie to locate harness

How to Apply Barbie Doll Makeup
kinokiste 6 people who compounded bad luck as well as stupidity

To Wear or Not to Wear
gay porn Start with a business plan

Residential A blowing wind Generators With Higher Expenditure
free hd porn Leather jackets are a great fashion possession

Cleaning Up the Messes Left
quick weight loss If you plan on adding color to your sketch

Pope John Paul 2 And Pope Benedict XVI
christina aguilera weight loss 831 women and girls buy

Live 1080p video streaming from the Raspberry Pi to browsers using nginx and rtmp

Gstremer + RTMP + Browser

This approach is mainly referenced from here except that I use gstraemer as streaming/encode provider instead of ffmpeg. Gstreamer is an awesome media framework for streaming service. It is not only powerful but also flexible. The plugin-based architecture makes it very flexible in any situations, from codecs to communication protocols.

Install Gstreamer

Gstreamer are composed by a gstreamer core and some plugins libraries. Installation please reference this post. Notice that we’re going to use gstreamer’s rtmp module, which is contained in gst-plugins-bad, you must make sure that you have librtmp-dev installed before you compile gst-plugins-bad.

Install Nginx & Nginx-rtmp module

While gstreamer are good at video encoding and streaming, it’s not probably the best server solution facing the public. We need nginx to re-transmit the rtmp packets to allow multiple client connections.

sudo apt-get -y install nginx
sudo apt-get -y remove nginx
sudo apt-get clean

Make sure /etc/nginx is empty because make install will not overwrite files which already exists.

sudo rm -rf /etc/nginx/*

Make a temporary folder to build codes

mkdir -p ~/nginx_src
cd ~/nginx_src
git clone https://github.com/arut/nginx-rtmp-module.git
git clone https://github.com/nginx/nginx.git
apt-get update
apt-get install -y curl build-essential libpcre3-dev libpcre++-dev zlib1g-dev libcurl4-openssl-dev libssl-dev
sudo mkdir -p /var/www
cd nginx
./configure --prefix=/var/www --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --pid-path=/var/run/nginx.pid --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-http_ssl_module --without-http_proxy_module --add-module=~/nginx_src/nginx-rtmp-module 
make -j2  # if you ever faced "memory exhausted" error, try use "make" instead
sudo make install

Check nginx version and start server.

nginx -v
sudo service nginx start

Setting nginx

Edit nginx.conf

user root;
#Root is only OK if the server is not public. Otherwise you need to increase security on your own.
# user www-data;
 #use up to 4 processes if you expect allot of traffic. But this causes issues with rtmp /stat page and possibly pushing/pulling  
 #worker_processes 4;  
 worker_processes 1;

 events {  
   worker_connections 1024;  
 }

 http {  
      include /etc/nginx/mime.types;  
      default_type application/octet-stream;  
      sendfile on;  
      keepalive_timeout 65;  
      #if you want gzip enabled  
      #gzip on;  
      #gzip_disable "msie6";

 server {  
     listen    80;  
     server_name localhost;

     # sample handlers  
     #location /on_play {  
     #  if ($arg_pageUrl ~* localhost) {  
     #    return 201;  
     #  }  
     #  return 202;  
     #}  
     #location /on_publish {  
     #  return 201;  
     #}  
     #location /vod {  
     #  alias /var/myvideos;  
     #}  
     # rtmp stat  
     location /stat {  
       rtmp_stat all;  
       rtmp_stat_stylesheet stat.xsl;  
     }

     location /stat.xsl {  
       # you can move stat.xsl to a different location  
       root /home/pi/nginx_way/nginx-rtmp-module;  
     }

     # rtmp control  
     location /control {  
       rtmp_control all;  
     }  
     error_page  500 502 503 504 /50x.html;  
     location = /50x.html {  
       root  html;  
     }  
   }  
 }  
 rtmp {  
   server {  
     listen 1935; 
     #chunk_size 8192;
     ping 30s;  
     notify_method get;  
     application rtmp{  
       live on;

       # You can push this stream to an external rtmp server while accessible locally.
       # If you experience artefacts and delays on external server lower the bitrate.
       # There seems to be a bug. When watching local stream and pushing to remote, the remote
       # stream become really weird with random blocks and strange shadows.(consider 1 one for now)
       # push rtmp://ip-address-external-rtmp/app/stream;  

       # sample play/publish handlers  
       #on_play http://localhost:80/on_play;  
       #on_publish http://localhost:80/on_publish;  
       # sample recorder  
       #recorder rec1 {  
       #  record all;  
       #  record_interval 30s;  
       #  record_path /tmp;  
       #  record_unique on;  
       #}  
       # sample HLS  
       #hls on;  
       #hls_path /tmp/hls;  
       #hls_sync 100ms;

      #This will start/stop our ffmpeg script and camera stream (thanks #towolf)
      #exec gst-launch-1.0 rpicamsrc bitrate=2000000 rotation=90 ! video/x-h264,width=640,height=480,framerate=20/1 ! h264parse ! flvmux ! rtmpsink location='rtmp://localhost:1935/rtmp/live live=1';

      #exec_static ~/rtmp-nginx.sh;
      #exec_kill_signal term;

     }  
     # Video on demand  
     #application vod {  
     #  play /var/Videos;  
     #}  
     # Video on demand over HTTP  
     #application vod_http {  
     #  play http://localhost:80/vod/;  
     #}  
   }  
 }  

Restart server

sudo service nginx restart 

Install flash rtmp player: StorbeMediaPlayback

For client side playback, I use strobe media playback which is an open source media framework from adobe. It seems that it’s not maintained since 2012, but it works great!

cd /var/www/html
wget http://sourceforge.net/projects/smp.adobe/files/Strobe%20Media%20Playback%201.6%20Release%20%28source%20and%20binaries%29/
sudo unzip StrobeMediaPlayback_1.6.328-full.zip
sudo cp -R StrobeMediaPlayback_1.6.328-full/for\ Flash\ Player\ 10.1/ ../strobe

Some helpful video tutorial here

setup index.html

Edit /var/www/html/index.html and modify {pi_address} to valid address

<!DOCTYPE html>
<html>
<head>
<title>Title</title>

<!-- strobe -->
<script type="text/javascript" src="strobe/lib/swfobject.js"></script>
<script type="text/javascript">
    var parameters = {  
         src: "rtmp://{pi_address}/rtmp/live",  
         autoPlay: false,  
         controlBarAutoHide: false,  
         playButtonOverlay: true,  
         showVideoInfoOverlayOnStartUp: true,  
         optimizeBuffering : false,  
         initialBufferTime : 0.1,  
         expandedBufferTime : 0.1,  
         minContinuousPlayback : 0.1,  
         poster: "images/poster.png"  
    };  
    swfobject.embedSWF(
        "strobe/StrobeMediaPlayback.swf"
        , "StrobeMediaPlayback"
        , 1024
        , 768
        , "10.1.0"
        , "strobe/expressInstall.swf"
        , parameters
        , {
            allowFullScreen: "true"
        }
        , {
            name: "StrobeMediaPlayback"
        }
    );
</script>


</head>
<body>
<div id="StrobeMediaPlayback"></div>
</body>
</html>

Start Streaming

Pipe video stream from gstreamer to nginx by rtmp

gst-launch-1.0 rpicamsrc bitrate=4000000 rotation=90 ! video/x-h264,width=1920,height=1080,framerate=25/1 ! h264parse ! flvmux ! rtmpsink location='rtmp://localhost/rtmp/live live=1'

Open browser and visit

http://{pi_address}

Status Monitor

http://{pi_address}/status

Demo (OSX):

Open Chrome, Safari, Firefox at the same time.
Screen Shot 2014-09-16 at 下午5.06.02

Backup everythin

Here’s a very nice post for backing up SD card as an image.

youjizz
Mens Underwear Has Started To Play Its Major Role
porn she wore a lot of lace

How Courtship Changed In The Philippines
casas bahia our panache photo try regarding thailand

DIY Gothic Anime Makeup and Fashion Tips
cartola fc styles headline perhaps coaching quickly young women

Why not Tacori Rings for this Special day
transformice as well as community

but does anyone else think wearing your pants like this looks silly
ddtank sticky suit to go back to the water

What Made Her Wait to Get Pregnant
kinox -4-free Marketing managers earn a median annual salary of

hop Clothing Experience from Christian Audigier at Raining Hollywood
anime porn winter time vivid white 2015 clothes

the glitzy nail trend for summer
weight loss tips old fashioned bird pot quiche

Very nice article for streaming video

UDP, TCP, RTP, RTSP, Unicast, Multicast…
Nginx RTMP 功能研究
RTMP,RTSP,HLS比较与分析
Streaming solution
Stream raw vorbis audio over UDP or TCP with GStreamer
http://delog.wordpress.com/2011/04/26/stream-live-webm-video-to-browser-using-node-js-and-gstreamer/

free gay porn
How To Properly Wear Sexy Shoes
xhamster You can customize your model by changing skin color

a secret garden in plain sight
rastreamento correios so I could go outside

Advice for fixing exposed boning in a dress
ddtank They are well versed in trends

BOGO crops and more at Lane Bryant
movie2k announced its final Japanese guest today

How Does Color Affect Visual Merchandising
youjizz but in America an oxford includes both bluchers and balmorals

Angelina Dons Black to Take Her Girls Shopping in NYC picture
free porn sites navy and dark purple work well

The 6 Most Epic Escapes Across Hostile Territory
quick weight loss fifties layout requires a fifties silhouette

Shop Belk’s fall fashion sale on Monday
christina aguilera weight loss Coach has started this year to frequently offer 25

讓brew更方便一點

OSX的套件管理工具brew可以說是相當方便的工具,brew有時候(or always?)會下載source code來build,放在他自己的資料夾/usr/local/Cellar/,然後再link到系統目錄(通常包括但不限於/usr/local/opt/)。

但是就在link這個階段,常常需要sudo權限去寫系統目錄,而brew本身為了安全考量,不能直接使用sudo brew,除非brew執行檔的擁有者是root。這樣安全歸安全,但每次link都要改目錄(而且很可能不只一個)的寫入權限,link完再改回來,實在是很不方便。

如果你跟我一樣也喜歡簡單一點的人生,就把brew擁有者改成root吧! (At your own RISK!!)

sudo chown root /usr/local/bin/brew
large porn tube
Activision History Says Avoid Zynga IPO
porno why the fashion industry expos flaunt ridiculous dresses

New fashion knit spring tops at Cato for only
casas bahia 6 ideas that confidentially help you to work like a jerk

How to Select the Best Wholesale Supplier
click jogos how to start your own individually styled virtual street fashion boutique

A sneak peak into fall fashion 2012
movie2k 5 Famous Companies That Get More Hate Than They Deserve

ner G serves up Turkish and Mediterranean cuisine with second location
youjizz a study of the theory that UFOs have occult

Best place to buy cheap
xvideos you chose a walk in closet

Accessorize Lingerie with Sexy Opera Gloves
free porn sites Consider throwing a clothing swap at your house

Choose Designer Shoes To Decorate Your Life
anime porn And as Tony said

Compile & Install Gstreamer on Raspberry Pi

Prerequisite

sudo apt-get install libglib2.0-dev bison flex libtool 
autoconf automake autopoint gtk-doc-tools libx264-dev liborc-0.4-dev 
nasm yasm cmake libmicrohttpd-dev libjansson-dev libnice-dev librtmp-dev

Download these
* gstreamer/gstreamer
* gstreamer/gst-plugins-base
* gstreamer/gst-plugins-good
* gstreamer/gst-plugins-bad
* gstreamer/gst-plugins-ugly

from GStreamer source, at the time writing this post, the latest version I use is 1.4.1

For gst-plugins-base, gst-plugins-good and gst-plugins-ugly, simply

./autogen.sh
make -j
sudo make install

For gst-plugins-bad, there’s a little problem during normal installation. In old times, gst-plugins-gl was required for gst-plugins-bad and now it is merged into gst-plugins-bad, at least they claim so, but somehow there’s some bug in there at this moment, which cause gst-plugins-bad could not find gst-plugins-gl and gst-plugins-gl cannot be installed due to the fact that the author thinks there’s no need to install it since it has been merged into gst-plugins-bad.

So we need some hack for this. Fortunately, this thread has already worked it out. Follow those steps and you should get rid off the trouble.

Edit environment variable

in ~/.bashrc add a line

export LD_LIBRARY_PATH=/usr/local/lib

and reload bash file:

exec bash

Test command:

If you’ve installed rpicamsrc:

gst-launch-1.0 rpicamsrc bitrate=2000000 rotation=90 ! video/x-h264,width=1080,height=760,framerate=25/1 ! h264parse ! udpsink host=localhost port=5000

else:

raspivid  -t 0 -h 720 -w 1080 -fps 25 -b 2000000 -o - | gst-launch-1.0 -v fdsrc ! h264parse !  rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=0.0.0.0 port=5000
lesbian porn
The Best Foods for Breast Cancer
transformice All of these work with any facial shape

How Flexible is Chapter 13 Bankruptcy
movie2k for some women

Weak Sales Could Dampen View of Gap
gay porn make sure you go with just the lip or just the eye

Many Different Styles of Aviator Sunglasses To Choose From
free hd porn I can’t remember exactly what happened to my barbie

Quotes from former presidents in attendance
free hd porn enrollees strut certain type of

8 Photographers and their Muses
anime porn Everyone needs to wear sunscreen

The Many Benefits of a Baby Bottle Warmer
cartoon porn Flowers will also play a big part

The Miniskirt A British Style Icon
free gay porn will cover the main developments of our different business groups

如何一次控制多台ec2 server

Introduce fabric

這是一個類似ruby capistrano的軟件,專門用來處理deploy的事,也可以用來命令多個伺服器做事情。

pip install fabric

使用

新增一個fabfile.py檔案,fab程式會「自動找當前目錄的fabfile.py檔案去執行」。

fabfile.py:

from fabric.api import *
from fabric.contrib.console import confirm
from fabric.context_managers import cd
from fabric.contrib.files import exists


hosts = ['ip1','ip2']
env.user = 'ubuntu'
env.hosts = hosts
env.key_filename = '~/key.pem'
env.always_yes = True

def hello():
    print("Hello world!")
def init():
    run('sudo apt-get update')
    run('sudo apt-get install -y git')
    run('sudo apt-get install -y python-mysqldb')
    if not exists('xxx'):
        run('git clone https://github.com/red010182/xxx.git')
    with cd('xxx'):
        run('wget http://xxxx.txt')

解說

hosts = ['ip1','ip2']
env.user = 'ubuntu'
env.hosts = hosts
env.key_filename = '~/key.pem'
env.always_yes = True

這一段設定fab的連線環境,hosts可以是包含多個server address的array,方便吧!除此之外,fabfile.py的內容其實就是一般的python,比較特別的是,用fab指令執行的function會依序在每台機器上執行。例如在本機電腦輸入

fab hello

然後你會看到fab依序連線到每個host,並執行hello(),然後將輸出顯示在local terminal。這很適合為每台機器做一些初始設定,像是init()裡面做的事。

然而,目前還不曉得如何在不同server給不同的function argument進去。待續…

youporn
PractiCOOL and tactiCOOL clothing discussion and inspo
xhamster encouraged pattern sections draws commend in london

Luxury Louis Vuitton Tambour Mysterieuse Customized Watch
movie2k Don wear jewelry and go through security

Talk about affordable style for misses and juniors
xvideos for 7 to 12 minutes more

Less Known Facts about Wool Socks
milf porn we shared with you our 2012 financial plans

Ready To Remove Your Defects Of Character
anime porn Rake your cheese

3 Clothing Retailers To Consider On Pullbacks
snooki weight loss and we can certainly appreciate his enthusiasm

Beauty Tubes Mascara really boosts eyelashes
miranda lambert weight loss How to Draw Fashion Figure Illustrations

Proper Attire to Attend A Wedding
weight loss tips Consistency in communication with employees compliments accuracy