2015年4月14日 星期二

與大老闆有約

最近跟幾位大老闆聊天,也回顧起前老闆的互動,有些經驗真的是自己親身體驗的,所以特別有感觸,有些則是像看著書看電影,不如聽人親口說出來:

  • 所謂的 startup 是個生活的方式,若是以音樂圈舉例,大概出門都想比個 rock 手勢 XD 整體上就一種工作生活的模式,並非 startup 就過得比較好、比較爽。
  • 有錢出錢,沒錢想出技術、時間,但是,所有的技術股本質上都是有對等的錢,有些工程師會想拿很大比例的股票,用的是技術股而非自己的錢去買,但技術股一開始規劃太多會讓投資人不敢投資。而技術股本身就是有等值的金錢價值,無論有沒有成功上市還是一張壁紙,在當下就是有對等價值。所以,有機會拿到技術股時,要想想這些股票其實是 co-founder 的錢,他們為了打造團隊忍痛分出來的
  • 有些新創會讓你把年薪的幾趴用技術股,但真正有價值的公司,股票是很貴的,能給錢就給錢,不會想給技術股,因為通常每一輪增資時,股價是飛快地成長,小則幾十倍,大則百倍、千倍 XD 你想想 co-founder 一開始手上的 1 萬,經過一輪變成一百萬時,你覺得他會想給你股票嗎?
  • 團隊永遠優於題目,對天使來說,投資的是你的團隊,而不是你的題目
  • 搞 startup 的方向有很多種,有人想要長期持有,也有人想要短期翻百倍、千倍脫手,並沒有不好之處
  • 公司願意給人高薪時,某個角度是資金狀況達到一個水準,某個角度是為了打造明星戰隊,好讓下一輪募資有更佳的價值,其實都是好事。當公司給高薪卻不給股票時,有時不要太貪心,至少拿到高薪了!換個角度來說,這可是 co-founder 早期的投資成果呢!不然你連高薪的機會都沒有。
  • 對天使來說,大概投資 25 間才會有一間成功,若早期報酬率有25倍,那只是剛好打平而已

至於進 startup 到底要幹嘛?基本上選擇當 co-founder 後,已經是一條不歸路了,無論成功或失敗,自身都是很有價值的,要記得最重要的永遠是人脈圈,練人脈等同練信任感,失敗並不會怎樣,至少天使會知道你下次不會再犯一樣的錯了。

不過,有一個非常現實的問題...連續創業可以創造價值沒錯,但是 co-founder 的股份初期再怎樣還是用等價的錢打造的,所以想連續創業...還是要有一些錢錢才可以進行。別忘了 co-founder 還是要盡量保持大量持股,因為每一輪的角色會稀釋,甚至最後要找專業經理人時,必須自己拿股份出來吸引專業經理人。這筆股份/錢,我想任何投資人都不想出的。

最後一提,若30歲了加入公司的角度還是想著練功,那永遠都無法跳脫員工的角度。30歲這個年紀,已經該去指揮別人了。

2015年4月13日 星期一

iOS 開發筆記 - 使用 Facebook SDK 4.0 分享至塗鴉牆與簡易的 publish_actions 權限判斷流程

大概都遵循 Facebook 文件,這邊指紀錄在一個 ViewController 中,啟動分享至使用者塗鴉牆的流程,包括判斷使用者是否安裝過 Facebook app、是否授權 publish_actions 等,以及選擇用 Facebook app 分享或是用 Facebook SDK 分享等。

#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <FBSDKShareKit/FBSDKShareLinkContent.h>
#import <FBSDKShareKit/FBSDKShareDialog.h>
#import <FBSDKShareKit/FBSDKShareAPI.h>
#import <FBSDKShareKit/FBSDKShareOpenGraphAction.h>

#import <FBSDKLoginKit/FBSDKLoginManager.h>
#import <FBSDKLoginKit/FBSDKLoginManagerLoginResult.h>

@interface ViewController () <FBSDKSharingDelegate>
@property (nonatomic, strong) NSString *url;
@end

@implementation ViewController

#pragma mark - FBSDKSharingDelegate

- (void)sharer:(id<FBSDKSharing>)sharer didCompleteWithResults:(NSDictionary *)results {
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"INFO" message:@"done" delegate:nil cancelButtonTitle:@"ok" otherButtonTitles: nil];
    [alertView show];
}

- (void)sharer:(id<FBSDKSharing>)sharer didFailWithError:(NSError *)error {
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"INFO" message:@"error" delegate:nil cancelButtonTitle:@"ok" otherButtonTitles: nil];
    [alertView show];
}

- (void)sharerDidCancel:(id<FBSDKSharing>)sharer {
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"INFO" message:@"cancel" delegate:nil cancelButtonTitle:@"ok" otherButtonTitles: nil];
    [alertView show];
}

#pragma mark - share methods

- (void)useFacebookApp {
    FBSDKShareLinkContent *content = [[FBSDKShareLinkContent alloc] init];
    content.contentURL = [NSURL URLWithString:self.url];
    [FBSDKShareDialog showFromViewController:self
                                 withContent:content
                                    delegate:nil];
}

- (void)useFacebookSDK {
    FBSDKShareLinkContent *content = [[FBSDKShareLinkContent alloc] init];
    content.contentURL = [NSURL URLWithString:self.url];
    [FBSDKShareAPI shareWithContent:content delegate:self];
}

#pragma mark - init action

- (void)doShare
{
    if (![FBSDKAccessToken currentAccessToken]) {
        FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
        [login logInWithPublishPermissions:@[@"publish_actions"] handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
            if (error) {
                // Process error
                NSLog(@"Process error");
            } else if (result.isCancelled) {
                // Handle cancellations
            } else {
                if ([result.grantedPermissions containsObject:@"publish_actions"]) {
                    [self useFacebookSDK];
                } else {
                    [self useFacebookApp];
                }
            }
        }];
        return;
    } else if ([[FBSDKAccessToken currentAccessToken] hasGranted:@"publish_actions"]) {
        [self useFacebookSDK];
    } else {
        [self useFacebookApp];
    }
    return;
}

@end

2015年4月12日 星期日

16個夏天

去年就留意到這個劇名,跟自己的 blog 高度相似 XD 要不是 Yahoo! 首頁正在推某家免費看台灣戲劇,我應該也不會去看吧!就這樣開心地線上看著免錢的正版戲劇,每次在家運動就看一集,好像也超過一個月了?!今天很悶不想寫程式,就坐在電視前面,一口氣連看了六集,不知不覺也就快看完了,果然好看的戲,應該靜靜地享受情感流串啊,這才是尊重導演、編劇啊。

原先被一開始的學生情懷牽動,直到有一天跑去看 wiki 才發現案情不單純 XDD 之後反而就沒那麼有興趣,因為這個年代對愛情議題比就無感 XD 但這部戲劇情編排不錯,戲中點滴牽動著台灣相關事件,像 921 大地震、SARS、金融海嘯,甚至hTC、無名小站、臉書等有,反而很對味,也想起周邊一些人、事、物。

想想看周邊人在幹嘛?有換工作的、有結婚的、有生小孩的,也有遲疑著人生的,也有挑戰人生的,更有剛裝潢好辦公室準備創業的,不過聊聊最貼切自己的資訊產業,真的有種說不出的微妙感。不知是不是 open source 使得門檻降低?不知道是不是慾望還貪念,不少人都在進行所謂的 side project 呢。大家還是常說台灣資訊業的不是,或是拿著過去台灣經濟起飛的時代評論著現在,轉個彎來想想:當時的人會知道那時將經濟起飛嗎?有一件事仍是不變的,大家都不想錯過什麼吧?就這樣繼續讓生命更加豐富吧!

如同 16 個夏天一樣,沒有過去,哪有現在,更別害怕失敗而止步啦。

2015年4月9日 星期四

iOS 開發筆記 - Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]'

閒暇時,追了這個 bug 很久...

主因是 source code 又沒看到 NSPlaceholderArray 關鍵字,最後才發現這是只是單純的 NSArray 相關更動事件。

要找的關鍵處有幾個:
  • [arrayObject addObject:object];
  • [arrayObject addObjectsFromArray:arrayObject];
  • [NSArray arrayWithObject:object];
  • ...
結果漏了一個生成 NSArray 很好用的語法:
  • @[]
出包之處就是 @[] 相關動作啦,例如 @[obj1, obj2, obj3]; 其中有個 object 是 nil 啦

2015年4月8日 星期三

PHP CodeIgniter - 透過 Apache RewriteRule 限制 CGI 功能

基於一些開發需求,想要侷限網站的功能。剛好這個網站服務是用 PHP CodeIgniter 開發的,整套都是走 RewriteRule 來進行,例如一個 URL 位置,都一律導向到 PHP CodeIgniter Project 的 index.php?/path 來分析。

假設原本網站有 3 個主要網址,分別是 /api, /shopping, / 等,假設想要讓此網站只開啟 /api 時,這時就可以透過 Apache RewriteRule 來限制:

<VirtualHost *:80>
DocumentRoot /ci-project/
DirectoryIndex index.html index.php index.htm

# empty page
Alias /empty     /var/www/html/

<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>

<Directory /var/www/html/>
Options FollowSymLinks
AllowOverride None
DirectoryIndex index.html index.php index.htm
Require all granted
Satisfy Any
</Directory>

<Directory /ci-project>
Options FollowSymLinks
DirectoryIndex index.php
AllowOverride None
#AllowOverride All
Require all granted
Satisfy Any

<IfModule mod_rewrite.c>
RewriteEngine On
#LogLevel alert rewrite:trace6
RewriteBase /

# disable index.php with empty QUERY_STRING
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^index\.php$ /empty/ [L]

RewriteCond $1 !^(index\.php|images|css|js|favicon\.ico)
# enable /api only
RewriteCond $1 ^api.*$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ ./index.php?/$1 [L,QSA]
</IfModule>
</Directory>
</VirtualHost>


如此一來,只要使用者逛 / 位置,則會顯示 /var/www/html 的資料,而逛 /api 系列時,則是可以正常引導到 PHP CodeIgniter 相關程式碼來處理。