2016年1月7日 星期四

Adding the "ll" command to OSX bash

在 Linux 系列都有 ll 指令可以用,用的太習慣,Mac OSX 預設是沒有,加入的方法如下:

網路上查到有的寫是 "~/.bash_profile",我是用 "~/.profile" 這個檔案。

我覺得 ls -lG 就夠了,有需要看隱藏檔,才多一個 -a 即可。



=============

I have been spending a lot of time recently, working in Bash on Fedora. I got to liking the "ll" command and wanted to bring it to my mac. Turns out it is very easy to do. Here are the steps:

Create a file named "~/.profile" and add the following line to it:

alias ll='ls -lG'

Download
Restart your terminal session and you are good to go.

===========

In OS X 10.9.5 Mavericks you have to add an alias command to your bash profile file in your home folder:
~/.bash_profile
which is equivalent to your user path at
/Users/YOUR_USER_NAME/.bash_profile
To see that file in finder you have to activate the display of hidden files (e.g. using the app InVisible). Otherwise you can simply use your terminal to locate it and edit it with nano:
nano ~/.bash_profile
Then add an alias command to the end of that file. The standard ll alias would be
alias ll='ls -lG'
but I prefer
alias ll='ls -lGaf'
which also shows all hidden files (starting with a dot) and sorts the output case-insensitive

2015年11月30日 星期一

How to Easily Batch Resize Images on Mac

WOW, 有這個功能真方便,而且居然是Mac 內建的 App.


1. Drag and drop all these selected files on the Preview icon in Dock.  Alternatively, you can right-click and select Open With -> Preview.app
<== Max覺得用 control + space 叫出 spotlight 來開啟 preview app 比較快。

2. 在 Preview App 裡挑選要 preview 的 檔案清單

3. Select all thumbnails by either pressing [command + A]  to Select All.
<== 全選

4. Select "Tools" -> "Adjust Size" from the menu.  Choose your desired image size and you are done!  The resized images are auto-saved and, by default, the image files are overwritten.
<== "Tools" -> "Adjust Size"

用這個功能來批次 resize android 需要的 hdpi/mdip/xhdpi/xxhdpi 的圖檔。如果有指令可以下的話就更好了,醬子點2下就都做完了,應該來研究一下 imagemagicK.



2015年11月15日 星期日

Disabling smart quotes in Mavericks (OS X 10.9+)

這個真的讓我很困擾,就是 OS X 預設是太貼心了,啟用了 smart quotes and dashes. default 啟用的結果是,寫出來的 curl command 會變成:
curl -v -k -X POST -H MyHeader: 1234 -d ‘{“id“:“max123“}’ https://127.0.0.1:443/myapi
關掉後,才是我所預期的:
curl -v -k -X POST -H "X-Device_ID:1234" -d '{"line_id":"max123"}' https://127.0.0.1:443/myapi


關掉的方法:
OS X 10.11


OS X 10.9




2015年11月4日 星期三

CocoaHTTPServer 研究

本來是要用這個 proxy 來解決 AVPlayer 無法播放 https 的問題, 但後來解決了, 解法在: http://ios-imaxlive.blogspot.com/2015/11/use-avplayer-to-play-audio-video-with.html


研究到一半的 HttpServer...

CocoaHTTPServer github source code:
https://github.com/robbiehanson/CocoaHTTPServer

YourProxy github source code:
https://github.com/akisute/YourProxy

教學 from URL:

CocoaHTTPServer を利用して iOS アプリにブラウザからアクセスする
http://dev.classmethod.jp/smartphone/ios-cocoahttpserver-1/


cocoahttpserver使用详解(一)
http://blog.csdn.net/wjsxiaoweige/article/details/25902293


How to make an proxy



==================================
HTTPProxyResponse

SamQuest commented on 3 May 2013
Hello Robbiehanson,
To start, I am really really new to IOS / Objective C.
I am given a project which already uses your server. The enhancement needed to decrypt a progressive download video. In my research a couple of people have asked you and implemented this, but I could not find any code.
So I went on and mucked HTTPAsyncFileResponse myself. Now while waiting for my hairs to grow back,the code works fine. At this state (my knowledge about the language and framework is almost nil) I am satisfied with this code.
This code is for anyone who don't want to start clean. and over the top of your head if anyone see any big issues/leaks please comment.

HTTPConnection.m

- (void)sendResponseHeadersAndBody
{
...
        if ([ranges count] == 1)
        {
            if(remote){
            HTTPProxyResponse * proxyResponse = (HTTPProxyResponse *)httpResponse;
            response = [proxyResponse remoteResponse];
            } 
            else 
            {
            response = [self newUniRangeResponse:contentLength];
            }
        }
        else
        {
            response = [self newMultiRangeResponse:contentLength];
        }
...
}

HTTPProxyResponse.h

#import <Foundation/Foundation.h>
#import "HTTPConnection.h"
#import "HTTPResponse.h"
#import "HTTPMessage.h"
#import "GCDAsyncSocket.h"

@class HTTPConnection;
@class GCDAsyncSocket;

@interface HTTPProxyResponse : NSObject <HTTPResponse>
{
    dispatch_queue_t socketQueue;
    GCDAsyncSocket *asyncSocket;

    HTTPMessage *localRequest;
    HTTPMessage __strong *remoteResponse;
    unsigned int numHeaderLines;

    HTTPConnection *connection;

    UInt64 fileLength;  // Actual lwngth of the file
    UInt64 fileOffset;  // File offset as pertains to data given to connection
    UInt64 readOffset;  // File offset as pertains to data read from file (but maybe not returned to connection)

    BOOL connected;
    BOOL aborted;

    NSMutableData __strong *buffer;
    NSData __strong *data;

    void *readBuffer;
    NSUInteger readBufferSize;     // Malloced size of readBuffer
    NSUInteger readBufferOffset;   // Offset within readBuffer where the end of existing data is
    NSUInteger readRequestLength;
}

@property (nonatomic, strong) HTTPMessage *remoteResponse;

- (id)initWithLocalRequest:(HTTPMessage *)request forConnection:(HTTPConnection *)connection;

@end

HTTPProxyResponse.m

#import "HTTPProxyResponse.h"
#import "MyAppDelegate.h"
#import "HTTPLogging.h"

#import <unistd.h>
#import <fcntl.h>

#import <CommonCrypto/CommonCryptor.h>
#import <CommonCrypto/CommonDigest.h>

// Log levels : off, error, warn, info, verbose
// Other flags: trace
static const int httpLogLevel = HTTP_LOG_FLAG_TRACE;

// Define chunk size used to read in data for responses
// This is how much data will be read from disk into RAM at a time
#if TARGET_OS_IPHONE
    #define READ_CHUNKSIZE  (1024 * 128)
#else
    #define READ_CHUNKSIZE  (1024 * 512)
#endif

// Define the various timeouts (in seconds) for various parts of the HTTP process
#define TIMEOUT_READ_FIRST_HEADER_LINE       30
#define TIMEOUT_READ_SUBSEQUENT_HEADER_LINE  30
#define TIMEOUT_READ_BODY                    -1
#define TIMEOUT_WRITE_HEAD                   30
#define TIMEOUT_WRITE_ERROR                  30

// Define the various limits
// LIMIT_MAX_HEADER_LINE_LENGTH: Max length (in bytes) of any single line in a header (including \r\n)
// LIMIT_MAX_HEADER_LINES      : Max number of lines in a single header (including first GET line)
#define LIMIT_MAX_HEADER_LINE_LENGTH  8190
#define LIMIT_MAX_HEADER_LINES         100

// Define the various tags we'll use to differentiate what it is we're currently doing
#define HTTP_REQUEST_HEADER                10

#define HTTP_RESPONSE_HEADER                 92
#define HTTP_RESPONSE_BODY                   93
#define HTTP_FINAL_RESPONSE                  91

@implementation HTTPProxyResponse

@synthesize remoteResponse;

- (NSURL *)remoteRequestURI
{
    return [[NSURL alloc] initWithString:@"http://www.example.com/path/to/my/video.mp4"];
}

- (id)initWithLocalRequest:(HTTPMessage *)request forConnection:(HTTPConnection *)parent
{
    if ((self = [super init]))
    {
        HTTPLogTrace();

        connection = parent; // Parents retain children, children do NOT retain parents
        localRequest = request;

        NSURL *remoteURI = [self remoteRequestURI];

        MyAppDelegate * appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
        fileLength = [appDelegate currentVideoLength];

        fileOffset = 0;

        socketQueue = dispatch_queue_create("AsyncSocket", NULL);
        asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:socketQueue];

        uint16_t port = [[remoteURI port] unsignedLongLongValue];
        if(port==0) port = 80;

        NSError *error = nil;
        bool res = [asyncSocket connectToHost:[remoteURI host] onPort:port error:&error];
        if(!res || error) return nil;

        connected = NO;
        aborted = NO;
    }
    return self;
}

- (void)abort
{
    HTTPLogTrace();
    [asyncSocket disconnect];
    [connection responseDidAbort:self];
    aborted = YES;
}

- (BOOL)delayResponseHeaders
{
    return !(connected && [remoteResponse isHeaderComplete]);
}

- (void)processReadBuffer:(int)read
{
    // This method is here to allow superclasses to perform post-processing of the data.
    // For an example, see the HTTPDynamicFileResponse class.
    //
    // At this point, the readBuffer has readBufferOffset bytes available.
    // This method is in charge of updating the readBufferOffset.
    // Failure to do so will cause the readBuffer to grow to fileLength. (Imagine a 1 GB file...)

    // Copy the data out of the temporary readBuffer.
    data = [[NSData alloc] initWithBytes:readBuffer length:readBufferOffset];

    // Reset the read buffer.
    readBufferOffset = 0;

    // Notify the connection that we have data available for it.
    [connection responseHasAvailableData:self];
}


- (BOOL)canContinue
{
    if (aborted || asyncSocket == nil || [remoteResponse statusCode] == 304)
    {
        return NO;
    }
    return [asyncSocket isConnected];
}

- (UInt64)contentLength
{
    HTTPLogTrace2(@"%@[%p]: contentLength - %llu", THIS_FILE, self, fileLength);
    return fileLength;
}

- (UInt64)offset
{
    HTTPLogTrace();
    return fileOffset;
}

- (void)setOffset:(UInt64)offset
{
    HTTPLogTrace2(@"%@[%p]: setOffset:%llu", THIS_FILE, self, offset);
    fileOffset = offset;
    readOffset = offset;
}


- (void)startHeadRequest
{
    HTTPLogTrace();

    NSURL *remoteUrl = [self remoteRequestURI];

    HTTPMessage *remoteRequest = [[HTTPMessage alloc] initRequestWithMethod:@"HEAD" URL:remoteUrl version:HTTPVersion1_1];
    // Add HOST headers¸
    [remoteRequest setHeaderField:@"HOST" value:[remoteUrl host]];
    [remoteRequest setHeaderField:@"User-Agent" value:[localRequest headerField:@"User-Agent"]];
    [remoteRequest setHeaderField:@"Range" value:[NSString stringWithFormat:@"%lld-",fileOffset]];
    [remoteRequest setHeaderField:@"Connection" value:@"Keep-Alive"];

    NSData *requestData = [remoteRequest messageData];
    [asyncSocket writeData:requestData withTimeout:TIMEOUT_WRITE_HEAD tag:HTTP_REQUEST_HEADER];
}
- (void)startContentRequest
{
    HTTPLogTrace();

    NSURL *remoteUrl = [self remoteRequestURI];

    HTTPMessage *remoteRequest = [[HTTPMessage alloc] initRequestWithMethod:[localRequest method] URL:remoteUrl version:HTTPVersion1_1];
    // Add HOST headers¸
    [remoteRequest setHeaderField:@"HOST" value:[remoteUrl host]];

    // Add standart headers from orignal request
    NSMutableDictionary *requestHeaders = [[localRequest allHeaderFields] mutableCopy];
    [requestHeaders removeObjectForKey:@"HOST"];

    NSEnumerator *keyEnumerator = [requestHeaders keyEnumerator];
    NSString *key;

    while ((key = [keyEnumerator nextObject]))
    {
        NSString *value = [requestHeaders objectForKey:key];
        [remoteRequest setHeaderField:key value:value];
    }

    NSData *requestData = [remoteRequest messageData];
    [asyncSocket writeData:requestData withTimeout:TIMEOUT_WRITE_HEAD tag:HTTP_REQUEST_HEADER];
}
- (NSData *)readDataOfLength:(NSUInteger)length
{
    if (data)
    {
        NSUInteger dataLength = [data length];
        fileOffset += dataLength;
        NSData *result = data;
        data = nil;
        return result;
    }
    else
    {
        if(!connected){
            return nil;
        }
        if (![self canContinue])
        {
            [self abort];
            return nil;
        }
        HTTPLogVerbose(@"%@[%p]: Reading data of length %d", THIS_FILE, self, length);
        [asyncSocket readDataToLength:length withTimeout:TIMEOUT_READ_BODY buffer:buffer bufferOffset:readBufferOffset tag:HTTP_RESPONSE_BODY];
        return nil;
    }
}

- (BOOL)isDone
{
    BOOL result = (fileOffset == fileLength);
    HTTPLogTrace2(@"%@[%p]: isDone - %@", THIS_FILE, self, (result ? @"YES" : @"NO"));
    return result;
}

- (BOOL)isAsynchronous
{
    HTTPLogTrace();
    return YES;
}

- (void)connectionDidClose
{
    HTTPLogTrace();
    [asyncSocket  disconnect];
}


- (void)dealloc
{
    HTTPLogTrace();
    //if (readBuffer)
    //  free(readBuffer);
    if(socketQueue)
        dispatch_release(socketQueue);
    //[super dealloc];
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark GCDAsyncSocket Delegate
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
    connected = true;
    if(fileLength >0)
    {
        [self startContentRequest];
    } else {
        [self startHeadRequest];
    }
}
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
    connected = false;
    if(err) {
        HTTPLogTrace2(@"%@[%p]: socketDidDisconnect:\n %@", THIS_FILE, self, err);
    }
}
/**
 * This method is called after the socket has successfully written data to the stream.
 **/
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
    if (tag == HTTP_REQUEST_HEADER)
    {
        remoteResponse = [[HTTPMessage alloc] initEmptyResponse];

        [asyncSocket readDataToData:[GCDAsyncSocket CRLFData]
                        withTimeout:TIMEOUT_READ_FIRST_HEADER_LINE
                          maxLength:LIMIT_MAX_HEADER_LINE_LENGTH
                                tag:HTTP_RESPONSE_HEADER];
    }
}
/**
 * This method is called after the socket has successfully read data from the stream.
 * Remember that this method will only be called after the socket reaches a CRLF, or after it's read the proper length.
 **/
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData*)dat withTag:(long)tag
{
    if (tag == HTTP_RESPONSE_HEADER)
    {
        NSString *log = [[NSString alloc]initWithData:dat encoding:NSUTF8StringEncoding];
        HTTPLogTrace2(@"%@[%p]: didReadData\n %@", THIS_FILE, self, log);

        // Append the header line to the http message
        BOOL result = [remoteResponse appendData:dat];

        if (!result)
        {
            HTTPLogWarn(@"%@[%p]: Malformed request", THIS_FILE, self);
            [self abort];
        }
        else if (![remoteResponse isHeaderComplete])
        {
            // We don't have a complete header yet
            // That is, we haven't yet received a CRLF on a line by itself, indicating the end of the header
            if (++numHeaderLines > LIMIT_MAX_HEADER_LINES)
            {
                // Reached the maximum amount of header lines in a single HTTP request
                // This could be an attempted DOS attack
                [self abort];

                // Explictly return to ensure we don't do anything after the socket disconnect
                return;
            }
            else
            {
                [asyncSocket readDataToData:[GCDAsyncSocket CRLFData]
                                withTimeout:TIMEOUT_READ_SUBSEQUENT_HEADER_LINE
                                  maxLength:LIMIT_MAX_HEADER_LINE_LENGTH
                                        tag:HTTP_RESPONSE_HEADER];
            }
        }
        else 
        {
            // We have an entire HTTP request header from the client

            //NSRange isHeadRequest = [[remoteResponse method] rangeOfString:@"HEAD" options:NSCaseInsensitiveSearch];
            //if(isHeadRequest.location == NSNotFound)
            if(fileLength > 0)
            {
                // Now we need to reply to the local request
                // Not able to pass my buffer dont know why
                //buffer = [[NSMutableData alloc] initWithCapacity:READ_CHUNKSIZE];
                //Kick start reading the body from the connections getDataOfLength
                [connection responseHasAvailableData:self];
            }
            else
            {
                NSString *fLength = [remoteResponse headerField:@"Content-Length"];
                fileLength = [fLength longLongValue];
                if(fileLength > 0)
                {
                    MyAppDelegate * appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
                    appDelegate.currentVideoLength = fileLength;

                    [self startContentRequest];
                }
                else
                {
                    [self abort];
                }
            }
        }
    }
    else if (tag == HTTP_RESPONSE_BODY)
    {
        // Handle a chunk of data from the remote response body
        NSUInteger read = [dat length];
        readBuffer = (void *)[dat bytes];
        readOffset += read;
        readBufferOffset += read;

        [self processReadBuffer:read];
    }
}

@end



use AVPlayer to play audio, video with untrusted certificate.

要讓 AVPlayer 可以播自發憑證的SSL, 首先, 要限定 target App 在 iOS8 以上.


here is my code, works fine
- (IBAction)clickPlayBtn:(id)sender
{

    NSURL *sourceMovieURL = [[NSURL alloc]initWithString:@"https//:xxxxxxx"];

    AVURLAsset *movieAsset = [AVURLAsset URLAssetWithURL:sourceMovieURL options:nil];
    [movieAsset.resourceLoader setDelegate:self queue:dispatch_get_main_queue()];

    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:movieAsset];
    AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];
    AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
    playerLayer.frame = self.view.layer.bounds;
    playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;

    [self.view.layer addSublayer:playerLayer];
    [player play];
}

// AVAssetResourceLoaderDelegate
- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader
shouldWaitForResponseToAuthenticationChallenge:(NSURLAuthenticationChallenge *)authenticationChallenge
{
    //server trust
    NSURLProtectionSpace *protectionSpace = authenticationChallenge.protectionSpace;
    if ([protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        [authenticationChallenge.sender useCredential:[NSURLCredential credentialForTrust:authenticationChallenge.protectionSpace.serverTrust] forAuthenticationChallenge:authenticationChallenge];
        [authenticationChallenge.sender continueWithoutCredentialForAuthenticationChallenge:authenticationChallenge];

    }
    else{ // other type: username password, client trust..
    }
    return YES;
}



URL:
https://developer.apple.com/library/prerelease/ios/documentation/AVFoundation/Reference/AVAssetResourceLoaderDelegate_Protocol/index.html#//apple_ref/occ/intfm/AVAssetResourceLoaderDelegate/resourceLoader:didCancelAuthenticationChallenge:



Informs the delegate that a prior authentication challenge has been cancelled.

Declaration

SWIFT
     optional func resourceLoader(_ resourceLoaderAVAssetResourceLoader,
didCancelAuthenticationChallenge authenticationChallenge:NSURLAuthenticationChallenge)
OBJECTIVE-C
- (void)resourceLoader:(AVAssetResourceLoader *)resourceLoaderdidCancelAuthenticationChallenge:(NSURLAuthenticationChallenge*)authenticationChallenge

Parameters

resourceLoader
The resource loader.
authenticationChallenge
The authentication challenge that has been cancelled.

Availability

Available in iOS 8.0 and later.
=========================================

Facebook 留言