Linear Regression using Gradient Descent

For detailed explanation

import numpy as np

x = np.array([1, 2, 3, 4, 5])
y = np.array([1, 4, 9, 16, 25])
learningRate = 0.0001
iterations = 200000

def gradient(m, b):
  m_gradient = 0
  b_gradient = 0
  
  #summation
  for i in range(x.size):
    h = (m * x[i] + b)
    m_gradient += x[i] * (h - y[i])
    b_gradient += (h - y[i])

  m_gradient *= (2.0/x.size)
  b_gradient *= (2.0/x.size)

  m_new = m - (learningRate * m_gradient)
  b_new = b - (learningRate * b_gradient)

  return [m_new, b_new]

def gradient_iterations(m, b):
  for i in range(iterations):
    [m, b] = gradient(m, b)

  return [m, b]

def computeError(m, b):
  error = 0.0
  for i in range(x.size):
    error += (y[i] - (m * x[i] + b)) ** 2

  return error

m = 0
b = 0
[m, b] = gradient_iterations(m, b)
error = computeError(m, b)
print "slope m:", m
print "intercept b:", b
print "error:", error

Link to gist

Longest Common Subsequence

import java.util.HashSet;

public class LCS {
    private int [][] LCS_Matrix(String oldStr, String newStr) {
        int m[][] = new int[oldStr.length() + 1][newStr.length() + 1];
        for (int i = 1; i <= oldStr.length(); i++) {
            for (int j = 1; j <= newStr.length(); j++) {
                char c1 = oldStr.charAt(i - 1);
                char c2 = newStr.charAt(j - 1);
                if (c1 == c2) {
                    m[i][j] = m[i - 1][j - 1] + 1;
                } else {
                    m[i][j] = Math.max(m[i - 1][j], m[i][j - 1]);
                }
            }
        }
        return m;
    }

    private HashSet<String> backTraceAll(int[][] m, String oldStr, String newStr, int i, int j) {
        if (i == 0 || j == 0) {
            HashSet<String> a = new HashSet<>();
            a.add("");
            return a;
        } else if (oldStr.charAt(i - 1) == newStr.charAt(j - 1)) {
            HashSet<String> a = new HashSet<>();
            HashSet<String> b = backTraceAll(m, oldStr, newStr, i - 1, j - 1);
            for (String g : b) {
                a.add(g + oldStr.charAt(i - 1));
            }
            return a;
        } else {
            HashSet<String> a = new HashSet<>();
            if (m[i][j - 1] >= m[i - 1][j])
                a.addAll(backTraceAll(m, oldStr, newStr, i, j - 1));
            if (m[i - 1][j] >= m[i][j - 1])
                a.addAll(backTraceAll(m, oldStr, newStr, i - 1, j));
            return a;
        }
    }

    public void process(String oldStr, String newStr) {
        int [][] LCSMatrix = LCS_Matrix(oldStr, newStr);
        HashSet<String> hs = backTraceAll(LCSMatrix, oldStr, newStr, oldStr.length(), newStr.length());
        System.out.println("List of Longest Common Subsequence:");
        for(String s : hs)
            System.out.println(s);
    }

    public static void main(String[] args) {
        new LCS().process("abc512238gh", "abc523278gh");
    }
}

Kubernetes

Setup
Get Dockers

  1. Download and install Dockers

Get and compile Kubernetes

  1. git clone https://github.com/kubernetes/kubernetes.git
  2. cd kubernetes
  3. make

Start up the cluster

sudo hack/local-up-cluster.sh

Start a new terminal and get this tutorial

  1. git clone https://github.com/randcode-generator/kubernetes_tutorial_1.git
  2. cd kubernetes_tutorial_1
  3. git submodule init
  4. git submodule update

Build a new docker image for the negative number generator project

cd neg-num-generator
sudo docker build -t neg-num-gen:v1 .

Build a new docker image for the positive number generator project

cd ../pos-num-generator
sudo docker build -t pos-num-gen:v1 .

Run the following commands to create pods

kubectl create -f pos-num-pod.yaml
kubectl create -f neg-num-pod.yaml

Run the following commands to create services

kubectl create -f num-service.yaml

How to use
Get a list of services

kubectl get service

Look for the cluster ip and port for the service named num-service.

Open http://<cluster ip>:<port>

For example:
http://10.0.0.39:8082

You will a positive number. If you refresh, you will get another positive random number

To get negative numbers,

kubectl edit service num-service

Find the field called component. Change the pos-num to neg-num. Save and quit.

Restart your browser and open up http://<cluster ip>:<port>, you should see random negative numbers

BTree in Java

btreeNode.java

import java.util.Vector;

public class btreeNode {
    private Vector<Integer> values = new Vector<>();
    private Vector<btreeNode> nodes = new Vector<>();
    private btreeNode parent = null;

    public btreeNode() {

    }
    
    public btreeNode(btreeNode p, Vector<Integer> v, Vector<btreeNode> vb) {
        parent = p;
        values = v;
        nodes = vb;
        vb.forEach(x -> x.parent = this);
    }

    btreeNode findNodeToInsert(int v) {
        if (isNodeALeaf())
            return this;

        if (nodes.size() > 0) {
            if (v < values.firstElement()) {
                return nodes.firstElement().findNodeToInsert(v);
            } else if (v > values.lastElement()) {
                return nodes.lastElement().findNodeToInsert(v);
            } else {
                for (int i = 0; i < values.size() - 1; i++) {
                    if (v > values.elementAt(i) && v < values.elementAt(i + 1)) {
                        return nodes.elementAt(i + 1).findNodeToInsert(v);
                    }
                }
            }
        }
        return null;
    }

    btreeNode traverseRight() {
        if(isNodeALeaf()) {
            return this;
        }
        return nodes.lastElement().traverseRight();
    }

    btreeNode findNodeValue(int v) {
        for (int i = 0; i < values.size(); i++) {
            if (v == values.elementAt(i))
                return this;
            if (isNodeALeaf())
                continue;
            if (v < values.firstElement()) {
                return nodes.firstElement().findNodeValue(v);
            } else if (v > values.lastElement()) {
                return nodes.lastElement().findNodeValue(v);
            } else if (i + 1 < values.size() &&
                    v > values.elementAt(i) &&
                    v < values.elementAt(i + 1)) {
                return nodes.elementAt(i + 1).findNodeValue(v);
            }
        }
        return null;
    }

    public boolean findValue(int v) {
        return findNodeValue(v) != null ? true : false;
    }

    void overflow() throws Exception {
        if (values.size() < 5)
            return;

        if (values.size() >= 5) {
            splitNode();
            if (parent != null) {
                parent.insert(values.firstElement());
                int index = parent.getIndexOfNode(this);
                if (index < 0)
                    throw new Exception("Index is out of bound");
                parent.removeNode(index);
                parent.addAllNodes(index, nodes);
                nodes.forEach(x -> x.parent = parent);
            }
        }
        if (parent != null) {
            parent.overflow();
        }
    }

    void transferNodeFromLeft(int i, btreeNode leftNode) {
        int val1 = parent.valueAt(i - 1);
        values.add(0, val1);
        int val2 = leftNode.getLastValue();
        leftNode.removeLastValue();
        parent.setValueAt(i - 1, val2);
        if(parent.nodeAt(i - 1).isNodeALeaf() == false) {
            btreeNode node1 = parent.nodeAt(i - 1).removeLastNode();
            nodes.add(0, node1);
            node1.parent = this;
        }
    }

    void transferNodeFromRight(int i, btreeNode rightNode) {
        int val1 = parent.valueAt(i);
        values.add(val1);
        int val2 = rightNode.removeFirstValue();
        parent.setValueAt(i, val2);
        if(parent.nodeAt(i + 1).isNodeALeaf() == false) {
            btreeNode node1 = parent.nodeAt(i + 1).removeFirstNode();
            nodes.add(node1);
            node1.parent = this;
        }
    }

    void mergeNodeToLeft(int i, btreeNode leftNode) {
        int val = parent.removeValue(i - 1);
        parent.removeNode(this);
        values.add(0, val);
        leftNode.mergeNodes(this);
    }

    void mergeNodeToRight(int i, btreeNode rightNode) {
        int val = parent.removeValue(i);
        parent.removeNode(rightNode);
        values.add(val);
        mergeNodes(rightNode);
    }

    void underflow() throws Exception {
        if(parent == null)
            return;
        if(values.size() > 1)
            return;

        int i = parent.getIndexOfNode(this);
        if (i < 0)
            throw new Exception("Index is out of bound");
        if (i == 0) {
            btreeNode rightNode = parent.nodeAt(i + 1);
            int rightSize = rightNode.valueSize();
            if(rightSize == 2) {
                mergeNodeToRight(i, rightNode);
                setRoot();
            }
            else {
                transferNodeFromRight(i, rightNode);
            }
        }
        else if(i == parent.nodeSize() - 1) {
            btreeNode leftNode = parent.nodeAt(i - 1);
            int leftSize = leftNode.valueSize();
            if(leftSize == 2) {
                mergeNodeToLeft(i, leftNode);
                leftNode.setRoot();
            }
            else {
                transferNodeFromLeft(i, leftNode);
            }
        }
        else {
            btreeNode leftNode = parent.nodeAt(i - 1);
            btreeNode rightNode = parent.nodeAt(i + 1);
            int leftSize = leftNode.valueSize();
            int rightSize = rightNode.valueSize();

            if (leftSize > rightSize) {
                transferNodeFromLeft(i, leftNode);
            } else if (leftSize < rightSize) {
                transferNodeFromRight(i, rightNode);
            } else {
                mergeNodeToLeft(i, leftNode);
            }
        }

        if(parent != null && parent.valueSize() == 1)
            parent.underflow();
    }

    void setRoot() {
        if(parent.valueSize() == 0) {
            parent.values = values;
            parent.nodes = nodes;
            nodes.forEach(x -> x.parent = parent);
            parent.parent = null;
        }
    }

    void mergeNodes(btreeNode n2) {
        values.addAll(n2.values);
        nodes.addAll(n2.nodes);
        nodes.forEach(x -> x.parent = this);
    }

    public void insert(int v) {
        int i = 0;
        for (; i < values.size(); i++) {
            if (values.elementAt(i) > v) {
                break;
            }
        }

        values.add(i, v);
    }

    public void splitNode() {
        Vector<Integer> leftValues = new Vector<>(values.subList(0, values.size() / 2));
        Vector<Integer> rightValues = new Vector<>(values.subList(values.size() / 2 + 1, values.size()));
        Vector<btreeNode> leftNodes = new Vector<>(nodes.subList(0, nodes.size() / 2));
        Vector<btreeNode> rightNodes = new Vector<>(nodes.subList(nodes.size() / 2, nodes.size()));

        int midVal = values.elementAt(values.size() / 2);
        btreeNode leftNode = new btreeNode(this, leftValues, leftNodes);
        btreeNode rightNode = new btreeNode(this, rightValues, rightNodes);

        values.clear();
        nodes.clear();
        values.add(midVal);
        nodes.add(leftNode);
        nodes.add(rightNode);
    }

    Vector<btreeNode> getNodes() {
        return nodes;
    }

    int getIndexOfNode(btreeNode n) {
        return nodes.indexOf(n);
    }

    int getIndexOfValue(int n) {
        return values.indexOf(n);
    }

    int removeValue(int index) {
        return values.remove(index);
    }

    int removeLastValue() {
        return values.remove(values.size() - 1);
    }

    int removeFirstValue() {
        return values.remove(0);
    }

    btreeNode removeNode(int index) {
        return nodes.remove(index);
    }

    void removeNode(btreeNode n) {
        nodes.remove(n);
    }

    btreeNode removeLastNode() {
        return nodes.remove(nodes.size() - 1);
    }

    btreeNode removeFirstNode() {
        return nodes.remove(0);
    }

    void addAllNodes(int index, Vector<btreeNode> n) {
        nodes.addAll(index, n);
    }

    btreeNode nodeAt(int index) {
        return nodes.elementAt(index);
    }

    int valueAt(int index) {
        return values.elementAt(index);
    }

    void setValueAt(int index, int n) {
        values.set(index, n);
    }

    int valueSize() {
        return values.size();
    }

    int nodeSize() {
        return nodes.size();
    }

    int getLastValue() {
        return values.lastElement();
    }

    btreeNode getParent() {
        return parent;
    }

    boolean isNodeALeaf() {
        return nodes.isEmpty();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < values.size(); i++)
            sb.append(values.elementAt(i) + ", ");
        sb.deleteCharAt(sb.length() - 1);
        sb.deleteCharAt(sb.length() - 1);
        return sb.toString();
    }
}

btree.java

import java.util.HashMap;
import java.util.Set;
import java.util.Vector;

public class btree {
    btreeNode root = new btreeNode();

    void insert(int v) throws Exception {
        btreeNode node = root.findNodeToInsert(v);
        node.insert(v);
        node.overflow();
    }

    boolean find(int v) {
        return root.findValue(v);
    }

    void delete(int v) throws Exception {
        btreeNode n = root.findNodeValue(v);
        if(n == null)
            return;
        int i = n.getIndexOfValue(v);
        if(n.isNodeALeaf()) {
            n.removeValue(i);
            n.underflow();
        }
        else {
            btreeNode lastRight = n.nodeAt(i).traverseRight();
            int lastRightVal = lastRight.getLastValue();
            lastRight.removeLastValue();
            n.setValueAt(i, lastRightVal);
            lastRight.underflow();
        }
    }

    void debugStr(int level, btreeNode n, HashMap<Integer, Vector<String>> h) {
        Vector<String> s1 = h.get(level);
        if (s1 == null) {
            s1 = new Vector<>();
            h.put(level, s1);
        }
        s1.add(n.toString() + " (" + n.getParent() + ")");

        for (int i = 0; i < n.getNodes().size(); i++) {
            debugStr(level + 1, n.getNodes().elementAt(i), h);
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        HashMap<Integer, Vector<String>> disp1 = new HashMap<>();
        debugStr(1, root, disp1);
        Set<Integer> keys = disp1.keySet();
        for (Integer i : keys) {
            Vector<String> v = disp1.get(i);
            v.forEach((String str) -> sb.append(str + " | "));
            sb.append("\n");
        }
        return sb.toString();
    }
}

Async NSURLConnection in iOS

ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
{
    dispatch_semaphore_t sem;
    NSMutableData *alldata;
}

@end

ViewController.m

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    sem = dispatch_semaphore_create(0);
    alldata = [[NSMutableData alloc] init];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    
    [alldata appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    dispatch_semaphore_signal(sem);
}

- (IBAction)clicked:(id)sender {
    //run clickThread function in a separate thread
    [self performSelectorInBackground:@selector(clickThread) withObject:nil];
}

- (void) makeconnection:(NSString*)url {
    NSURLRequest *request = [NSURLRequest requestWithURL: [NSURL URLWithString:url]];
    [NSURLConnection connectionWithRequest:request delegate:self];
}

- (void) clickThread {
    NSLog(@"making connection with google");
    //NSURLConnection will only work if it is run on the main thread
    [self performSelectorOnMainThread:@selector(makeconnection:) withObject:@"http://www.google.com" waitUntilDone:NO];
    
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    NSLog(@"google done");
    NSLog(@"%@", [[NSString alloc] initWithData:alldata encoding:NSUTF8StringEncoding]);
    
    NSLog(@"making connection with yahoo");
    sem = dispatch_semaphore_create(0);
    alldata = [[NSMutableData alloc] init];
    [self performSelectorOnMainThread:@selector(makeconnection:) withObject:@"http://www.yahoo.com" waitUntilDone:NO];
    
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    NSLog(@"yahoo done");
    NSLog(@"%@", [[NSString alloc] initWithData:alldata encoding:NSUTF8StringEncoding]);
}
@end

Parsing address using Regular Expressions

Objective-C

    NSString *address = @"123 Main Street, New York, NY 10001";
    NSError *error;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^[0-9]+[A-Za-z\\s]+," options:NSRegularExpressionCaseInsensitive error:&error];
    [regex enumerateMatchesInString:address options:0 range:NSMakeRange(0, address.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop){
        NSString *street = [address substringWithRange:result.range];
        street = [street stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]];
        NSLog(@"street: %@", street);
    }];
    
    regex = [NSRegularExpression regularExpressionWithPattern:@",[A-Za-z\\s]+," options:NSRegularExpressionCaseInsensitive error:&error];
    [regex enumerateMatchesInString:address options:0 range:NSMakeRange(0, address.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop){
        NSString *city = [address substringWithRange:result.range];
        city = [city stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@", "]];
        NSLog(@"city: %@", city);
    }];
    
    regex = [NSRegularExpression regularExpressionWithPattern:@",[\\s]*[A-Z]{2}[\\s]" options:NSRegularExpressionCaseInsensitive error:&error];
    [regex enumerateMatchesInString:address options:0 range:NSMakeRange(0, address.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop){
        NSString *state = [address substringWithRange:result.range];
        state = [state stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@", "]];
        NSLog(@"state: %@", state);
    }];
    
    regex = [NSRegularExpression regularExpressionWithPattern:@"[\\s][0-9]{5}" options:NSRegularExpressionCaseInsensitive error:&error];
    [regex enumerateMatchesInString:address options:0 range:NSMakeRange(0, address.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop){
        NSString *zip = [address substringWithRange:result.range];
        zip = [zip stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@", "]];
        NSLog(@"zip: %@", zip);
    }];

Swift

var error:NSError?
let address:NSString = "123 Main Street, New York, NY 10001"
var regex = NSRegularExpression(pattern: "^[0-9]+[A-Za-z\\s]+,", options:.CaseInsensitive, error: &error)
regex?.enumerateMatchesInString(address, options: .WithTransparentBounds, range: NSMakeRange(0, address.length)) {
    (result: NSTextCheckingResult! , _, _) in
    var street:NSString = address.substringWithRange(result.range)
    street = street.stringByTrimmingCharactersInSet(NSCharacterSet(charactersInString: ","))
    NSLog("street: %@",street);
}

regex = NSRegularExpression(pattern: ",[A-Za-z\\s]+,", options:.CaseInsensitive, error: &error)
regex?.enumerateMatchesInString(address, options: .WithTransparentBounds, range: NSMakeRange(0, address.length)) {
    (result: NSTextCheckingResult! , _, _) in
    var city:NSString = address.substringWithRange(result.range)
    city = city.stringByTrimmingCharactersInSet(NSCharacterSet(charactersInString: ", "))
    NSLog("city: %@",city);
}

regex = NSRegularExpression(pattern: ",[\\s]*[A-Z]{2}[\\s]", options:.CaseInsensitive, error: &error)
regex?.enumerateMatchesInString(address, options: .WithTransparentBounds, range: NSMakeRange(0, address.length)) {
    (result: NSTextCheckingResult! , _, _) in
    var state:NSString = address.substringWithRange(result.range)
    state = state.stringByTrimmingCharactersInSet(NSCharacterSet(charactersInString: ", "))
    NSLog("state: %@",state);
}

regex = NSRegularExpression(pattern: "[\\s][0-9]{5}", options:.CaseInsensitive, error: &error)
regex?.enumerateMatchesInString(address, options: .WithTransparentBounds, range: NSMakeRange(0, address.length)) {
    (result: NSTextCheckingResult! , _, _) in
    var zip:NSString = address.substringWithRange(result.range)
    zip = zip.stringByTrimmingCharactersInSet(NSCharacterSet(charactersInString: ", "))
    NSLog("zip: %@",zip);
}

NSAttributedString in Swift

        var mainString: NSMutableAttributedString = NSMutableAttributedString();
        
        var str1: NSMutableAttributedString = NSMutableAttributedString(string: &quot;My Car! &quot;);
        str1.addAttribute(NSForegroundColorAttributeName, value: UIColor.greenColor(), range: NSMakeRange(0, 2));
        var fonts: UIFont? = UIFont(name: &quot;Verdana&quot;, size: 40);
        str1.addAttribute(NSFontAttributeName, value: fonts!, range: NSMakeRange(3, 3));
        
        var textAttachment: NSTextAttachment = NSTextAttachment();
        textAttachment.image = UIImage(named: &quot;car&quot;);
        var rects: CGRect = textAttachment.bounds;
        rects.size.height = 33;
        rects.size.width = 100;
        var img1: NSAttributedString = NSAttributedString(attachment: textAttachment);
        
        mainString.appendAttributedString(str1)
        mainString.appendAttributedString(img1)
        
        label1.attributedText = mainString

https://github.com/randcode-generator/attributedString/blob/master/attributedString/ViewController.swift

C# Multithreaded and Parallel Programming – Book Review

If you are a C# developer who is serious about developing high performance multithreaded applications, then this is the book for you. This book goes in-depth on how to develop multithreaded applications that will take advantage of today’s multicore processors.

Chapter 1 – Explains the history of processors in-depth from single core to multicore. The book also explains, with images, how the (Windows) operating system manages threads on a multicore system.

Chapter 2 – Discusses how to create a simple WPF (Windows Presentation Foundation) application using BackgroundWorker class to demonstrate a non-blocking application.

Chapter 3 & 4 – Discusses Thread class from beginner to advanced such as how to share data between threads to locking, deadlocks, and error handling.

Chapter 5, 6 & 7 – Introduction to Task Parallel Library (TPL). These chapters discusses how to use Parallel class and when to use it instead of the Thread class. The main take away from these chapters (and TPL) is to let .NET handle the thread coordination while the developer focus on the logic of the application.

Chapter 8 – How to take advantage of the tools in Visual Studio to help the developer debug multithreaded application.

Chapter 9 – Introduction to pipeline and producer-consumer design pattern. Discusses how to coordinate efficiently between threads where order matters. For example, thread A reads a frame of video file into a buffer, thread B immediately processes the frame, and thread C writes the frame to file. This process continues until all of the frame has been read from the video file.

Chapter 10 – Introduction of PLINQ. Discusses when and how to use PLINQ to process a LINQ query in parallel.

Chapter 11 – Introduction of async programming. Discusses the newest technique to create non-blocking applications such using async and await.

Overall, great book with examples and images to help the reader understand and apply multithreading features in .NET framework to their application. I highly recommend this book to anyone that wants in-depth practical understanding of multithreaded application in C#.

To findout more about this book, visit the Packt website:
https://www.packtpub.com/application-development/c-multithreaded-and-parallel-programming

NSPredicate in Objective-C

    NSMutableArray *arr = [[NSMutableArray alloc]init];
    NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
    [dict setValue:@"JFK Airport" forKey:@"airport"];
    [dict setValue:@"Queens" forKey:@"location"];
    [arr addObject:dict];
    
    dict = [[NSMutableDictionary alloc]init];
    [dict setValue:@"LGA Airport" forKey:@"airport"];
    [dict setValue:@"Queens" forKey:@"location"];
    [arr addObject:dict];
    
    dict = [[NSMutableDictionary alloc]init];
    [dict setValue:@"Empire State Building" forKey:@"building"];
    [dict setValue:@"Manhattan" forKey:@"location"];
    [arr addObject:dict];
    
    dict = [[NSMutableDictionary alloc]init];
    [dict setValue:@"Coney Island" forKey:@"landmark"];
    [dict setValue:@"Brooklyn" forKey:@"location"];
    [arr addObject:dict];
    
    NSPredicate *p = [NSPredicate predicateWithFormat:@"airport endswith 'Airport'"];
    NSArray *filtered = [arr filteredArrayUsingPredicate:p];
    NSLog(@"%@\n", filtered);
    
    p = [NSPredicate predicateWithFormat:@"location = 'Manhattan'"];
    filtered = [arr filteredArrayUsingPredicate:p];
    NSLog(@"%@\n", filtered);
    
    p = [NSPredicate predicateWithFormat:@"building contains 'State'"];
    filtered = [arr filteredArrayUsingPredicate:p];
    NSLog(@"%@\n", filtered);
    
    p = [NSPredicate predicateWithFormat:@"location = 'Manhattan' OR location = 'Brooklyn'"];
    filtered = [arr filteredArrayUsingPredicate:p];
    NSLog(@"%@\n", filtered);