Tutorials

Tutorial List


Disqus for Google Sites


Vue Js Tutorial

posted Mar 30, 2017, 4:24 AM by Denny Angkasa

Setting Up and Installing Dependencies

 

Create a folder that we are going to use for our project. Open a command window inside the folder and use the command “npm init” to create a package.json file for our project.

 

Now we are going to install the dependencies for our project. Use the command

npm install vue vue-resource bootstrap --save

 

Now our dependencies should be installed and we are ready to code our application.

 

The Application

 

Initialization

Create the files index.html and app.js. We will use index.html as our view and app.js as the base for our Vue application. The goal of this tutorial is to help readers understand Vue.js basics, data binding, and components. By the end of the tutorial we would have a very simple application for product management.

 

Let’s start with index.html. The base of our Vue application is going to be very simple. We are going to use a div with a specific ID and bind it to our Vue Javascript. Let’s use a div with id=products for that.

1.   <!DOCTYPE html>  

2.   <html>  

3.   <head>  

4.       <title>Vue Test</title>  

5.       <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">  

6.   </head>  

7.   <body>  

8.       <div id="products">  

9.         

10.     </div>  

11.   

12.     <script src="node_modules/vue/dist/vue.js"></script>  

13.     <script src="node_modules/vue-resource/dist/vue-resource.js"></script>  

14.     <script src="app.js"></script>  

15. </body>  

16. </html>  

 

Hello World

Now we’re going to app.js to set up our Vue Application.

1.   new Vue({  

2.       el: '#products',  

3.       data: {  

4.           text: 'Hello World'  

5.       }  

6.   });  

 

As you may have noticed, we initialize the application by creating a new Vue object. The el attribute refers to the id of element in the view, and data attribute is used to contain the data for our application. In the above example, we have a data with the name of “text” and the value of “Hello World”. Now we are going to use the text data in our view. To print out data in view is a very simple task. We use the syntax {{ DATA_NAME }}.

1.   <!DOCTYPE html>  

2.   <html>  

3.   <head>  

4.       <title>Vue Test</title>  

5.       <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">  

6.   </head>  

7.   <body>  

8.       <div id="products">  

9.           {{text}}  

10.     </div>  

11.   

12.     <script src="node_modules/vue/dist/vue.js"></script>  

13.     <script src="node_modules/vue-resource/dist/vue-resource.js"></script>  

14.     <script src="app2.js"></script>  

15. </body>  

16. </html>  

 

 

Components

We can use components for reusability and modularize our application. Let’s try creating a component.

1.   Vue.component('test-component', {  

2.       props: ['text'],  

3.       template: `  

4.           <div>  

5.               {{text}}  

6.           </div>  

7.       `  

8.   });  

9.     

10. new Vue({  

11.     el: '#products',  

12.     data: {  

13.         text: 'Hello World'  

14.     }  

15. });  

 

And use it in our view

1.   <!DOCTYPE html>  

2.   <html>  

3.   <head>  

4.       <title>Vue Test</title>  

5.       <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">  

6.   </head>  

7.   <body>  

8.       <div id="products">  

9.           <test-component :text="text">  

10.         </test-component>  

11.     </div>  

12.   

13.     <script src="node_modules/vue/dist/vue.js"></script>  

14.     <script src="node_modules/vue-resource/dist/vue-resource.js"></script>  

15.     <script src="app2.js"></script>  

16. </body>  

17. </html>  

 

As you may notice, we passed the text property to the child component, and use it as output in the child component.

 

Insert Product Component

We are going to create a component that we will use to insert a new product.

1.   Vue.component('insert-product-component', {  

2.       props: ['products'],  

3.       data: function() {  

4.           return {  

5.               previousId: 3,  

6.               product: {  

7.                   name: '',  

8.                   stock: 0,  

9.                   price: 0  

10.             }  

11.         };  

12.     },  

13.     methods: {  

14.         addProduct: function() {  

15.             this.product.id = ++this.previousId;  

16.             this.product.price = parseInt(this.product.price);  

17.             this.product.stock = parseInt(this.product.stock);  

18.             this.products.push(this.product);  

19.   

20.             this.product = {  

21.                 name: '',  

22.                 price: 0,  

23.                 stock: 0  

24.             };  

25.         }  

26.     },  

27.     template: `  

28.         <div class="container">  

29.             <form v-on:submit.prevent="addProduct">  

30.                 <div class="page-header">  

31.                     <h1>Insert</h1>  

32.                 </div>  

33.                 <div class="form-group">  

34.                     <label>Name</label>  

35.                     <input type="text" class="form-control" v-model="product.name"/>  

36.                 </div>  

37.                 <div class="form-group">  

38.                     <label>Price</label>  

39.                     <input type="number" class="form-control" min="0" v-model="product.price"/>  

40.                 </div>  

41.                 <div class="form-group">  

42.                     <label>Stock</label>  

43.                     <input type="number" class="form-control" min="0" v-model="product.stock"/>  

44.                 </div>  

45.                 <button class="btn btn-primary">Save</button>  

46.             </form>  

47.         </div>  

48.     `  

49. });  

 

The Main Vue Application

The main Vue application will be used to store our data, with the insert product component as its child. We are also going to put in 3 dummy data as starting data.

1.   new Vue({  

2.       el: '#products',  

3.       data: {  

4.           product: {  

5.               name: '',  

6.               price: 0,  

7.               stock: 0  

8.           },  

9.           products: []  

10.     },  

11.     mounted: function() {  

12.         this.fetchProducts();  

13.     },  

14.     methods: {  

15.         fetchProducts: function() {  

16.             var products = [  

17.                 {  

18.                     id: 1,  

19.                     name: 'Test',  

20.                     price: 15000,  

21.                     stock: 50  

22.                 },  

23.                 {  

24.                     id: 2,  

25.                     name: 'Test2',  

26.                     price: 13000,  

27.                     stock: 67  

28.                 },  

29.                 {  

30.                     id: 3,  

31.                     name: 'Test3',  

32.                     price: 25000,  

33.                     stock: 40  

34.                 }  

35.             ];  

36.   

37.             this.$set(this'products', products);  

38.         }  

39.     }  

40. });  

 

Now we will adjust our index.html

1.   <!DOCTYPE html>  

2.   <html>  

3.   <head>  

4.       <title>Vue Test</title>  

5.       <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">  

6.   </head>  

7.   <body>  

8.       <div id="products">  

9.           <insert-product-component :products="products">  

10.         </insert-product-component>  

11.         <table class="table table-striped table-hover" style="margin-top: 20px;">  

12.             <tr>  

13.                 <th>Id</th>  

14.                 <th>Name</th>  

15.                 <th>Price</th>  

16.                 <th>Stock</th>  

17.             </tr>  

18.             <tr v-for="product in products">  

19.                 <td>{{ product.id }}</td>  

20.                 <td>{{ product.name }}</td>  

21.                 <td>{{ product.price }}</td>  

22.                 <td>{{ product.stock }}</td>  

23.             </tr>  

24.         </table>  

25.     </div>  

26.   

27.     <script src="node_modules/vue/dist/vue.js"></script>  

28.     <script src="node_modules/vue-resource/dist/vue-resource.js"></script>  

29.     <script src="app.js"></script>  

30. </body>  

31. </html>  

 

The Result



[JavaScript] MVVM Implementation Using Knockout.js

posted Mar 15, 2017, 5:37 AM by Benedictus Jason Reinhart

Introduction

MVVM consists of 3 layers, the Model, View and ViewModel. The model layer represents the data of your application, the view layer represents the UI (user interface) or what users see on your application, and lastly the view model does not represent anything in particular, it handles your data binding (model) to your application view. Designing application using the MVVM pattern is great when your application requirement is not really big. Binding data model to your view makes your code more readable, but does not scale really well on a bigger system. It becomes more confusing on which bind on what. It also is an "overkill" for a simple UI or application operation logic when the operation can actually be executed in a simple steps.

Knockout.js is a simple library that helps developers to build a simple page with MVVM structure. With only 25 kb (min+gz), Knockout.js able to do data bindings to make your UI automatically refreshes as your data change while maintaining dependencies by tracking it with chains of relationships between model data. Additionally, Knockout.js does not have any dependency. That means you can use Knockout.js without worrying if it will interfere with your existing libraries, e.g. using Knockout.js with jQuery.

You can download Knockout.js in their official site.

Getting Started

Suppose that we want to build a "Product page" with a shopping cart in it. In order to show the products, we need to pull the data from a server, usually using AJAX request. Knockout.js does not handle these kind of things as it is not the part of the presentation layer, so you probably want to handle these tasks using things like Fetch, jQuery AJAX, etc. The main focus of using Knockout is building your view to present data and while handling any changes that may occur while user interacts with your application.

To start, let's build a simple plain HTML page. Make sure you have downloaded Knockout.js (or install it via npm, whichever way you like the most).
index.html:
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4.     <title></title>  
  5.     <script src="knockout-3.4.1.js"></script>  
  6.     <script src="script.js"></script>  
  7. </head>  
  8. <body>  
  9.     <div align="center">  
  10.         <h1>MVVM Shop</h1>  
  11.         <table border="1" cellspacing="0" cellpadding="10">  
  12.             <tr>  
  13.                 <th>Product Name</th>  
  14.                 <th>Product Price</th>  
  15.                 <th>Add to Cart</th>  
  16.             </tr>  
  17.         </table>  
  18.   
  19.         <br><br>  
  20.   
  21.         <h2>My Cart</h2>  
  22.         <table border="1" cellspacing="0" cellpadding="5">  
  23.             <tr>  
  24.                 <th>Name</th>  
  25.                 <th>Price</th>  
  26.                 <th>Quantity</th>  
  27.                 <th>Subtotal</th>  
  28.                 <th>Action</th>  
  29.             </tr>  
  30.             <tr>  
  31.                 <td colspan="3" align="right"><b>Grand Total</b></td>  
  32.                 <td colspan="1" align="right"></td>  
  33.                 <td></td>  
  34.             </tr>  
  35.             <tr>  
  36.                 <td colspan="5" align="center">  
  37.                     <button>Checkout / Clear Cart</button>  
  38.                 </td>  
  39.             </tr>  
  40.         </table>  
  41.     </div>  
  42. </body>  
  43. </html>  


First, we load the Knockout.js library and a script file for our code. We create a table as a container for our products and a cart to store items that users choose. User can choose the quantity of an item they wish to add to the cart, and the cart will dynamically refresh as the user interacts with it. The checkout button is used to clear the cart only, nothing special will happen (no sending data, as it is not our main topic here).

Moving to script.js, we will code everything in our onload function to make sure our DOM is ready. Here, I make a Product "class" to wrap what each of our product has.
  1. window.onload = function() {  
  2.     var Product = function Product(name, price) {  
  3.         this.name = name;  
  4.         this.price = price;  
  5.         this.quantity = 0;  
  6.     }  


We will use the quantity attribute to keep track the number of the product inserted into the cart. 

Bindings

In Knockout.js, we need to make a ViewModel (the VM in MVVM) as the representation of our UI model. The view model will hold our product data, which we will later bind it to the UI using data-bind attribute in HTML and let Knockout.js do the rest. Add the ViewModel, then immediately bind it to our view:
  1. var ViewModel = function ViewModel(name) {    
  2.     this.products = ko.observableArray([    
  3.         new Product('Potato', 50),    
  4.         new Product('Carrot', 40),    
  5.         new Product('Broccoli', 55),    
  6.         new Product('Tomato', 53),    
  7.     ]);    
  8. };    
  9.   
  10. var viewModel = new ViewModel();  
  11. ko.applyBindings(viewModel);  

Our ViewModel will have products (an observable array, special type that lets Knockout.js to bind data to view) with 4 items. To show the products array, modify your code in your HTML:
  1. <table border="1" cellspacing="0" cellpadding="10">  
  2.     <tr>  
  3.         <th>Product Name</th>  
  4.         <th>Product Price</th>  
  5.         <th>Add to Cart</th>  
  6.     </tr>  
  7.     <!-- ko foreach: products -->  
  8.     <tr>  
  9.         <td><span data-bind="text: name"></span></td>  
  10.         <td><span data-bind="text: price"></span></td>  
  11.         <td>  
  12.             <input style="width: 40px;" type="number" data-bind="value: $data.quantity">  
  13.             <button data-bind="click: $parent.addToCart.bind($data)">Add to Cart</button>  
  14.         </td>  
  15.     </tr>  
  16.     <!-- /ko -->  
  17. </table>


To loop in your observable array Knockout.js does it in a special syntax, comment:
<!-- ko foreach: products -->
will loop the products attribute in our ViewModel (which currently has 4 elements). The loop will repeat everything inside the <!-- ko ... --> until it meets <!-- /ko -->. We bind the name of the current element in the products to the span. User will see the value of the name and price attribute inside the product, because we bind it to the text.

Notice the input of the cart: 
<input style="width: 40px;" type="number" data-bind="value: $data.quantity">

We want to make sure that every time the input element changes, the value of quantity inside the product will also change. We can use the data-bind attribute to bind the value of quantity of the product to the value of the input element.

On the button element, we have something different:
<button data-bind="click: $parent.addToCart.bind($data)">Add to Cart</button> 

We can bind events like click event on a button to the ViewModel. In this case, we bind the click event to the parent of the product, which is the ViewModel itself. Simply said, products is a child of ViewModel, so if we access the parent of products, we would get ViewModel. In the code above, the context of the event binding is still in products, so calling $parent will give us access to ViewModel. Now, when we click on the button, the addToCart function of the ViewModel will be called within the context of $data, the product itself. However, we still do not have the addToCart function so we need to create it:
  1. var ViewModel = function ViewModel(name) {  
  2.     // ...  
  3.     // ...  
  4.     this.cart = ko.observableArray([]);  
  5.   
  6.     this.addToCart = function(product) {  
  7.         var p = Object.assign({}, product);  
  8.         this.cart.push(p);  
  9.         this.calculateGrandTotal();  
  10.     }.bind(this);  
  11.   
  12.     this.grandTotal = ko.observable(0);  
  13.   
  14.     this.calculateGrandTotal = function() {  
  15.         var t = 0;  
  16.         for (var item of this.cart()) {  
  17.             t += item.price * item.quantity;  
  18.         }  
  19.         this.grandTotal(t);  
  20.     }.bind(this);  
  21. };


Now to show the content of the cart, add the following code to your HTML:
  1. <h2>My Cart</h2>  
  2. <table border="1" cellspacing="0" cellpadding="5">  
  3.     <tr>  
  4.         <th>Name</th>  
  5.         <th>Price</th>  
  6.         <th>Quantity</th>  
  7.         <th>Subtotal</th>  
  8.         <th>Action</th>  
  9.     </tr>
  10.     <!-- ko foreach: cart -->  
  11.     <tr>  
  12.         <td data-bind="text: name"></td>  
  13.         <td data-bind="text: price"></td>  
  14.         <td data-bind="text: quantity"></td>  
  15.         <td data-bind="text: (quantity * price)" align="right"></td>  
  16.         <td>  
  17.             <button data-bind="click: $parent.removeFromCart.bind($data)">Remove</button>  
  18.         </td>  
  19.     </tr>  
  20.     <!-- /ko -->  
  21.     <tr>  
  22.         <td colspan="3" align="right"><b>Grand Total</b></td>  
  23.         <td colspan="1" align="right" data-bind="text: grandTotal"></td>  
  24.         <td></td>  
  25.     </tr>  
  26.     <tr>  
  27.         <td colspan="5" align="center">  
  28.             <button data-bind="click: checkout">Checkout / Clear Cart</button>  
  29.         </td>  
  30.     </tr>  
  31. </table>


Here we show all the element inside the cart using foreach loop like how we show the products data. Note that on the checkout button, we do not need to access the parent because we are already in the context of the ViewModel while in the foreach loop, we have to access the $parent because the context is in the product.

We need to add a few more functions that are called above:
  1. this.checkout = function() {  
  2.     this.cart.removeAll();  
  3.     this.calculateGrandTotal();  
  4. }.bind(this);  
  5.   
  6. this.removeFromCart = function(product) {  
  7.     this.cart.remove(product);  
  8.     this.calculateGrandTotal();  
  9. }.bind(this);  


That's it, building an MVVM page is really easy using Knockout.js, and the result is really amazing. Data binding becomes very easy as Knockout.js handles it really nicely, making your page really dynamic and responsive to user's interaction. There are still more in Knockout.js, but this tutorial will only cover on the basic.

React hot reload & Redux (Part 2)

posted Dec 5, 2016, 1:59 AM by Andi Muqsith Ashari   [ updated Dec 5, 2016, 6:56 PM by Surya Wang ]


This is the second part of React hot reload & Redux, in this part we will learn about how to update and deleting product item that inserted using code we have built in the first tutorial, the first thing is modifying actions/index.js by adding updateProduct and deleteProduct method as action:

export const ADD_PRODUCT = 'ADD_PRODUCT';
export const UPDATE_PRODUCT = 'UPDATE_PRODUCT';
export const DELETE_PRODUCT = 'DELETE_PRODUCT';

let nextProductId = 1;

export function addProduct(product)
{
product.id = nextProductId++; 
    return {
        type: ADD_PRODUCT,
        product: product
    };
}

export function updateProduct(product){
return {
type : UPDATE_PRODUCT, 
product: product
}
}

export function deleteProduct(product){
return {
type : DELETE_PRODUCT,
product : product
}
}

Now we have 3 actions, addProduct, updateProduct, and deleteProduct, the next step is creating update and delete reducer by modifying reducer/products.js:

import { ADD_PRODUCT, UPDATE_PRODUCT, DELETE_PRODUCT } from '../actions';

const initialState = {
    products: []
};

export function crudApp(state = initialState, action) {

    switch(action.type)
    {

        case ADD_PRODUCT: {
            return Object.assign({}, state, {
                products: [
                    ...state.products,
                    action.product
                ]
            });
        }

        case UPDATE_PRODUCT:{
            state.products.forEach(function(val,key){
                if(action.product.id==val.id){
                    state.products[key] = action.product;
                }
            });
            return Object.assign({}, state, {
                products: [
                    ...state.products
                ]
            });
        }

        case DELETE_PRODUCT: {
            state.products.forEach(function(val,key){
                if(action.product.id==val.id){
                    state.products.splice(key,1);
                }
            });
            return Object.assign({}, state, {
                products: [
                    ...state.products
                ]
            });
        }

    }

    return state;
}

Our actions and reducers are ready to use, the last thing is importing our new action into our react component and use them as a functionality of our application (Insert, Update and Delete):

import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';

import { crudApp } from './reducers/products';
import { addProduct, updateProduct, deleteProduct } from './actions';

var store = createStore(crudApp);

class App extends React.Component {

    constructor(){
        super();
        this.state = {
            products: [],
            product: {
                id : '',
                name : '',
                description : ''
            }
        };
    }

    componentWillMount(){
        store.subscribe(() => {
            var state = store.getState();
            this.setState({
                products: state.products
            });
        });
    }

    handleSubmitForm(e)
    {
        e.preventDefault();
        if(this.state.product.id){
            store.dispatch(updateProduct(this.state.product));
        }else{
            store.dispatch(addProduct(this.state.product));
        }
        this.setState({
            product:{
                id:'',
                name:'',
                description:''
            }
        });
    }

    handleSelectProduct(product,e){
        this.setState({
            product:product
        });
    }

    handleDeleteProduct(product,e){
        store.dispatch(deleteProduct(product));
        this.setState({
            product:{
                id:'',
                name:'',
                description:''
            }
        });
    }

    handleProductNameChange(e){
        this.setState({
            product: {
                id : this.state.product.id,
                name : e.target.value,
                description:this.state.product.description
            },
        });
    }

    handleProductDescriptionChange(e){
        this.setState({
            product: {
                id : this.state.product.id,
                name:this.state.product.name,
                description : e.target.value
            },
        });
    }

    handleProductIdChange(e){
        this.setState({
            product: {
                id : e.target.value,
                name:this.state.product.name,
                description : this.state.product.description
            },
        });
    }   

    render () {

        var mode = "Add Product";
        if(this.state.product.id) mode = "Update Product";

        return(
            <div>
                <p>HMR is cool</p>
                <form onSubmit={this.handleSubmitForm.bind(this)}>
                    <table>
                        <tbody>
                            <tr>
                                <td>Product Id</td>
                                <td><input value={this.state.product.id} disabled="disabled" type="text" onChange={this.handleProductIdChange.bind(this)}/></td>
                            </tr>
                            <tr>
                                <td>Product Name</td>
                                <td><input value={this.state.product.name} type="text" onChange={this.handleProductNameChange.bind(this)}/></td>
                            </tr>
                            <tr>
                                <td>Product Description</td>
                                <td><input value={this.state.product.description} type="text" onChange={this.handleProductDescriptionChange.bind(this)}/></td>
                            </tr>
                        </tbody>
                    </table>
                    <input type="submit" value={mode}/>
                </form>
                <hr />
                <table width="500">
                    <thead>
                        <tr>
                            <th>Id</th>
                            <th>Name</th>
                            <th>Description</th>
                            <th>Action</th>
                        </tr>
                    </thead>
                    <tbody>
                    {
                        this.state.products.map((product,i)=>{
                            return (
                                <tr key={i}>
                                    <td>{product.id}</td>
                                    <td>{product.name}</td>
                                    <td>{product.description}</td>
                                    <td>
                                        <button onClick={this.handleSelectProduct.bind(this,product)}>Select</button>
                                        <button onClick={this.handleDeleteProduct.bind(this,product)}>Delete</button>
                                    </td>
                                </tr>
                            )
                        })
                    }
                    </tbody>
                </table>
            </div>
        );
    }
};

render(<App/>, document.getElementById('app'));

module.hot.accept();

Now we can inserting, viewing, updating, and deleting our data by using our simple React & Redux application.


Creating a Music Playlist with Visualizer Using HTML5 Web Audio API, Canvas and Node.js

posted Dec 4, 2016, 11:41 PM by Benedictus Jason Reinhart   [ updated Dec 5, 2016, 6:56 PM by Surya Wang ]


The Web Audio API provides a powerful and versatile system for controlling audio on the Web, allowing developers to choose audio sources, add effects to audio, create audio visualizations, apply spatial effects (such as panning) and much more. (Source)

The concept of the Web Audio API is simple. Your audio things are described as node. The source of audio is a node. The effects on the audio (reverb, gain, filters, etc.) is also a node. The output of your audio (speaker, headphones, line out, etc.) is a node. All these nodes are connected as a chain of processes. If we want to give filter to our music, first we need the audio source node, the music node. Then we connect the music node to the filter node, and filter node to the destination node (a speaker or headphone). 

Other than filters and reverb, there is also an AnalyserNode. AnalyserNode can be used to get the information of frequency and time-domain analysis in real-time. Using the frequency information given by the AnalyserNode, we can provide a visualizer drawn in HTML5 canvas.
In terms of code, we need to:
  • Create an AudioContext object as the context or container of all our nodes
  • Create an audio source node
  • Create an AnalyserNode object to analyse the frequency in the audio currently played
  • Connect source to AnalyserNode so it can be analysed
  • Connect AnalyserNode to AudioContext.destination
Firstly, AnalyserNode does not change any frequency in our audio but still output the audio input it takes, so we can safely assume that the input of destination is the same as the output of source. Secondly, an AudioContext has a property destination, it's usually the speaker or headphone of the user.

Before we start, make sure you have Node.js installed with Express in it. You can download Node.js in here and Express.js here.

Now, we start by setting up the server application first. The directory should look like this:
  |-- visualizer
    |-- songs
      |-- song.mp3
    |-- index.html
    |-- app.js

We'll write our server code in app.js. The server access control has to allow our origin, because streaming media files cannot be done by using file:/// URI and not all server in the internet allow cross domain origin.

app.js 
var express = require('express');
var fs = require('fs');
var app = express();

app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    next();
});
app.use(express.static('songs'));

app.get('/', function (req, res) {
    var filenames = fs.readdirSync('./songs/');
    var html = fs.readFileSync('./index.html', {encoding: 'utf-8'});
    var options = '';
    var sources = '';
    for (var i = 0; i < filenames.length; i++) {
        if (filenames[i].endsWith('.mp3')) {
            options += '<option value="'+filenames[i]+'">'+filenames[i]+'</option>';
        }
    }
    var render = html.toString().replace('#select#', '<select>'+options+'</select>');
    res.send(render);
});

app.listen(3000, function () {
    console.log('Visualizer server listening on port 3000');
});

To list all mp3 files in our directory, we need the fs (filesystem) module from Node. Then, we read all the mp3 files in directory and add it as an item in a combo box. Later in index.html we need to write #select# that will be replaced by the server with the combo box filled with mp3 file name items. As the server will send index.html as the response, we should write the index.html now.

index.html
<!DOCTYPE html>
<html>
<head>
    <title>Audio Visualizer</title>
    <style>
        html, body {
            margin: 0;
            width: 100%;
            height: 100%;
            font-family: 'consolas';
            background: #111;
            color: white;
        }
        #control, canvas {
            position: fixed;
            top: 0;
        }
        select {
            position: relative;
            top: -10px;
            padding: 3px;
        }
        #stats {
            position: fixed;
            bottom: 0;
            left: 0;
        }
    </style>
</head>
<body>
    <canvas></canvas>
    <div id="control">
        <audio controls loop autoplay>
        </audio>
        #select#
        <div id="settings">
            <div>Min. Frequency <input type="range" min="20" value="20" step="50" max="20000" name="minFrequency"></div>
            <div>Max. Frequency <input type="range" min="20" value="20000" step="50" max="20000" name="maxFrequency"></div>
            <div>Smoothing <input type="range" min="0" max="0.9" step="0.05" value="0.8"></div>
        </div>
    </div>
    <div id="stats">
    </div>

    <script>
        var control = document.querySelector('#control');

        var settings = document.querySelectorAll('#settings input');
        settings[0].addEventListener('change', changeMinMaxFrequency);
        settings[1].addEventListener('change', changeMinMaxFrequency);
        settings[2].addEventListener('change', changeSmoothness);

        function changeMinMaxFrequency() {
            minFrequency = settings[0].value;
            maxFrequency = settings[1].value;
            minIndex = Math.ceil(minFrequency / frequencyRange)|0;
            maxIndex = Math.floor(maxFrequency / frequencyRange)|0;

            // initialize balls
            balls.length = 0;
            for (var i = minIndex; i < maxIndex; i++) {
                balls[i] = new Ball(canvas.width / 2, canvas.height / 2, 360 / (maxIndex-minIndex) * i);
            }
        }

        function changeSmoothness() {
            analyser.smoothingTimeConstant = settings[2].value;
        }

        function randomBetween(min, max) {
            return (Math.random() * (max - min) + min) | 0;
        }

        class Ball {
            constructor(x, y, angle) {
                this.x = x;
                this.y = y;
                this.angle = angle;
                this.color = 'rgba('+randomBetween(60, 200)+', '+randomBetween(60, 200)+', '+randomBetween(60, 200)+', 1)';
            }
        }
        Ball.radius = 3.5;
        Ball.trailSize = 2;

        var canvas = document.querySelector('canvas'),
            ctx = canvas.getContext('2d'),
            audio = document.querySelector('audio'),
            audioContext = new AudioContext(), // "Container" for all audio nodes
            source = audioContext.createMediaElementSource(audio), // The music, we get it from <audio> element
            analyser = audioContext.createAnalyser(); // To get frequency information of source
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        analyser.fftSize = 1024; // FFT algorithm of signal processing, the size must be a power of 2
        analyser.smoothingTimeConstant = 0.8;

        var bufferLength = analyser.frequencyBinCount, // array of frequencies length, must be half of FFT size
            sampleRate = audioContext.sampleRate, // The audio context sample rate, usually 48000hz or 44100hz. The maximum frequency in the music is half of this sample rate.
            frequencyRange = sampleRate / bufferLength, // each element of the array represents a range of frequencies
            minFrequency = 20, // minimum frequency a human can hear is 20hz, so we set the minimum frequency our visualizer can draw to 20.
            maxFrequency = 20000, // maximum frequency a human can hear varies depending by its age, but normally it's 20,000hz. more information: http://hypertextbook.com/facts/2003/ChrisDAmbrose.shtml
            minIndex, // the lowest index of the minimum frequency
            maxIndex, // the highest index of the maximum frequency
            dataArray = new Uint8Array(bufferLength),
            balls = [];

        changeMinMaxFrequency(); // init balls, min and max frequency
        source.connect(analyser);
        analyser.connect(audioContext.destination);

        var lastTime = Date.now(),
            stats = document.querySelector('#stats');
            updateStatsInterval = 200; // milliseconds
            stats.updateInterval = updateStatsInterval;
        function draw() {
            requestAnimationFrame(draw);
            var now = Date.now();
            var deltaTime = now - lastTime;
            lastTime = now;

            stats.updateInterval -= deltaTime;
            if (stats.updateInterval < 0) {
                stats.innerHTML = 'FPS: ' + ((1000 / deltaTime) | 0);
                stats.updateInterval = updateStatsInterval;
            }

            analyser.getByteFrequencyData(dataArray);

            ctx.clearRect(0, 0, canvas.width, canvas.height);

            for(var i = minIndex; i < maxIndex; i++) {
                var distance = dataArray[i];
                distance *= distance / 200;
                if (distance < 5) continue;
                var angle = balls[i].angle * (Math.PI / 180);
                balls[i].x = Math.cos(angle) * distance;
                balls[i].y = Math.sin(angle) * distance;
                var gradient = ctx.createLinearGradient(canvas.width/2, canvas.height/2, balls[i].x+canvas.width/2, balls[i].y + canvas.height/2);
                gradient.addColorStop(0, "rgb(150,150,150)");
                gradient.addColorStop(1, balls[i].color);
                ctx.strokeStyle = gradient;
                ctx.fillStyle = balls[i].color;

                ctx.beginPath();
                ctx.arc(balls[i].x + canvas.width/2, balls[i].y + canvas.height/2, Ball.radius*distance/100, 0, 2 * Math.PI, false);
                ctx.fill();
                ctx.closePath();

                ctx.beginPath();
                ctx.moveTo(canvas.width/2, canvas.height/2);
                ctx.lineTo(balls[i].x + canvas.width/2, balls[i].y + canvas.height/2);
                ctx.lineWidth = Ball.trailSize * distance/300;
                ctx.stroke();
            }
        };

        draw();

        var select = document.querySelector('select');
        select.addEventListener('change', function() {
            document.querySelector('audio').remove();
            var audio = document.createElement('audio');
            audio.setAttribute('autoplay', 'autoplay');
            audio.setAttribute('loop', 'loop');
            audio.setAttribute('controls', 'controls');
            var src = document.createElement('source');
            src.setAttribute('src', this.value);

            audio.appendChild(src);
            control.prepend(audio);

            analyser.disconnect();
            source.disconnect();

            source = audioContext.createMediaElementSource(audio);
            source.connect(analyser);
            analyser.connect(audioContext.destination);
        });
    </script>
</body>
</html>

First, we need to create the context, source, and analyser.
var audio = document.querySelector('audio'),
    audioContext = new AudioContext(), // "Container" for all audio nodes
    source = audioContext.createMediaElementSource(audio), // The music, we get it from <audio> element
    analyser = audioContext.createAnalyser(); // To get frequency information of source

Then, simply connect those nodes together.
source.connect(analyser);
analyser.connect(audioContext.destination);

FYI, if we don't want any filters or analysis from another node, we can just simply connect the source and destination altogether.
source.connect(audioContext.destination);
that way the audio source output will goes directly to user's speaker/headphone without any alteration or analysis.

The analyser object has several properties. The fftSize is used to determine the FFT algorithm buffer size and it needs to be a power of 2 number.
var bufferLength = analyser.frequencyBinCount; // this will always be half of the fftSize

we use the frequencyBinCount property to get the size of the array, which will be half of the fftSize property of analyser. Knowing the array size, we can declare the unsigned integer array by doing this:
var dataArray = new Uint8Array(bufferLength);

dataArray is used to render the visualizer, it stores the frequency volume value. The visualizer is going to display the frequency volume. For example, a kick drum should be around 20-200hz, so dataArray from [0] to [3] (with a frequencyRange value around 80-90) should have high values depending on how hard the kick drum sounds.

The array will be filled every time the canvas redraw, using this method:
analyser.getByteFrequencyData(dataArray);

With the frequency information every frame, we can transform them into a visualizer. Assuming the frequency range is 80hz, by using loop we can draw a line for each frequency array that represents 80-160hz, 81-160hz, 161-240hz, and so on until it reaches the maximum frequency of 20000. Notice that we also skip the 0-80hz because our minimum frequency is 20hz, so we skip the first index of the array. Remember, each element in the array represents the volume of the frequency range. That means dataArray[20] represents the volume of 1681-1760hz.

To handle audio source change, for example when user wants to change the music, we cannot just disconnect the nodes and change the audio source. That is because the <audio> element is already bound to the context, and as far as I know there is no way (if you know how please tell me in the comment section!) to disconnect the audio element source from AudioContext. A simple solution I found was to just delete the old <audio> element and create another <audio> element with different source.

var select = document.querySelector('select');
select.addEventListener('change', function() {
    querySelector('audio').remove();
    audio = document.createElement('audio');
    audio.setAttribute('autoplay', 'autoplay');
    audio.setAttribute('loop', 'loop');
    audio.setAttribute('controls', 'controls');

    var src = document.createElement('source');
    src.setAttribute('src', this.value);

    audio.appendChild(src);
    control.prepend(audio);

    analyser.disconnect();
    source.disconnect();

    source = audioContext.createMediaElementSource(audio);
    source.connect(analyser);
    analyser.connect(audioContext.destination);
});

Your final result should be like this:



React hot reload & Redux (Part 1)

posted Nov 30, 2016, 10:45 PM by Denny Angkasa   [ updated Dec 5, 2016, 6:55 PM by Surya Wang ]


This tutorial will cover how to setup react hot reload with redux. React hot reload allows us to change the code live without the the page being refreshed, unlike webpack-dev-server that auomatically refreshes the page when the code is changed, hot reload allows the page to load the changes on the fly, preserving the state of the application. We will also set up Redux in this tutorial, using it to manage the state of the application.

We start by creating the file package.json
{
  "name": "reactest",
  "version": "1.0.0",
  "description": "this is a test application",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server.js"
  },
  "author": "Denny Angkasa",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.18.2",
    "babel-loader": "^6.2.8",
    "babel-preset-es2015": "^6.18.0",
    "babel-preset-react": "^6.16.0",
    "express": "^4.14.0",
    "react-hot-loader": "^1.3.1",
    "webpack": "^1.13.3",
    "webpack-dev-middleware": "^1.8.4",
    "webpack-hot-middleware": "^2.13.2"
  },
  "dependencies": {
    "react": "^15.4.1",
    "react-dom": "^15.4.1",
    "react-redux": "^4.4.6",
    "redux": "^3.6.0"
  }
}


We will use the file to manage our dependencies and use scripts for npm. We are dividing the dependencies into 2, devDependencies and dependencies. DevDependencies are dependencies that will be used only in development, while dependencies are needed to execute the application. Babel here will be the transpiler for our JSX & ES6 code to ES5 javascript code. Express will be used as our server to serve static files, with webpack middlewares as the API for the node server to enable hot reloading. Webpack is used to compile our javascript codes into bundles. When this package.json has been created, open a command window in the directory of the package.json file and execute npm install. The package manager will install our dependencies.


Next we will create the node server to serve our static files and hot reloading. create the file server.js. This server will listen on port 3000. As we can see in the server.js, the server needs webpack config and index.html.
var path = require('path');
var webpack = require('webpack');
var express = require('express');
var config = require('./webpack.config');

var app = express();
var compiler = webpack(config);

app.use(require('webpack-dev-middleware')(compiler, {
  publicPath: config.output.publicPath
}));

app.use(require('webpack-hot-middleware')(compiler));

app.get('*', function(req, res) {
  res.sendFile(path.join(__dirname, 'index.html'));
});

app.listen(3000, function(err) {
  if (err) {
    return console.error(err);
  }

  console.log('Listening at http://localhost:3000/');
})


Let's create the index.html file.
<html>
  <head>
    <meta charset="utf-8">
    <title>React Application</title>
  </head>
  <body>
    <div id="app" />
    <script src="static/bundle.js" type="text/javascript"></script>
  </body>
</html>
The index.html file expects only a single javascript file, which is the bundle.js in static folder bundled by webpack.


Next will be the webpack.config.js. This is the main configuration file for webpack and is very important for the hot reload to work.
var webpack = require('webpack');
var path = require('path');

var BUILD_DIR = path.resolve(__dirname, 'dist');
var APP_DIR = path.resolve(__dirname, 'src');

var config = {
    devtool: 'inline-source-map',
    entry: [
        'webpack-hot-middleware/client',
        APP_DIR + '/index.jsx'
    ],
    output: {
        path: BUILD_DIR,
        filename: 'bundle.js',
        publicPath: '/static/'
    },
    module: {
        loaders: [
            {
                test: /\.jsx?/,
                include: APP_DIR,
                loaders: ['react-hot', 'babel']
            }
        ]
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoErrorsPlugin
    ]
};

module.exports = config;
In this file we define the directories for build and development source files. We use the inline-source-map devtool to provide easy debugging. Because when javascript files are bundled it is very difficult to debug it without source maps. Inline source map allows us to easily debug our application using browser's development tools as if we are actually debugging our source code without bundling. Entries are used for the webpack entry into our application, and the webpack-hot-middleware/client is used by the server to provide our hot reload. Here we are entering our application through the file index.jsx. The output will be the target location for webpack bundling output, with the filename bundle.js. Modules are used to define which loaders we will used for each file type. Here we state using regex that *.js and *.jsx files will use react-hot loader and babel loader. To enable hot reload we have to use the plugin webpack.HotModuleReplacementPlugin(), while webpack.NoErrorsPlugin ensures that our application won't crash and need to reload when we do syntax error in our code. We then export the config for the server.js to use.


Note that above we use babel loader. We need to create the babel configuration file. Create the file .babelrc
{
    "presets": ["react", "es2015"]
}


Now we have finished configuring our application. Next we will configure our redux components. 2 of the main components of redux are actions and reducers. Actions are functions that doesn't directly alter the application's states. Reducers on the other hand will be the one that updates the state of the application using actions.
Create the folder src in our project folder. Inside the src folder create actions folder. The actions folder will contain all of our actions. In the actions folder create the file index.js.
export const ADD_PRODUCT = 'ADD_PRODUCT';
export const UPDATE_PRODUCT = 'UPDATE_PRODUCT';
export const DELETE_PRODUCT = 'DELETE_PRODUCT';

let nextProductId = 1;
export function addProduct(product)
{
    return {
        type: ADD_PRODUCT,
        product: {
            id: nextProductId++,
            name: product.name,
            description: product.description
        } 
    };
}
For now we will only implement the AddProduct functionality in the action. As you can see, this action will only return a new product with unique id each time it is called, hence not updating the state of the application.


Now we will create the reducer for products. Create the folder reducers in the same directory as actions folder. Inside it we create products.js containing the reducer for products.
import { ADD_PRODUCT, UPDATE_PRODUCT, DELETE_PRODUCT } from '../actions';

const initialState = {
    products: []
};

export function crudApp(state = initialState, action) {

    switch(action.type)
    {
        case ADD_PRODUCT: {
            return Object.assign({}, state, {
                products: [
                    ...state.products,
                    action.product
                ]
            });
        }
    }

    return state;
}
Which is the ES6 equivalent of
import { ADD_PRODUCT, UPDATE_PRODUCT, DELETE_PRODUCT } from '../actions';

const initialState = {
    products: []
};

export function crudApp(state, action) {
    
    if(typeof state === 'undefined')
        state = initialState;

    switch(action.type)
    {
        case ADD_PRODUCT: {
            return Object.assign({}, state, {
                products: [
                    ...state.products,
                    action.product
                ]
            });
        }
    }

    return state;
}


Here we import the action strings from the actions index.js file. We create an initial state of the application, containing empty array of products. This reducer will export the crudApp function that will be used to update the state of the application. When we call this function, we have to pass a state and an action string. For now we will only handle the action for adding a new product. Notice that we are returning a new state if the action is valid, without overriding the passed state.  This allows us to preserve all the state that the application has been in. An example in the ADD_PRODUCT action, we append the products with the new product created by the action.


Now we are gonna create the entry point and the main file of our application. Create the file index.jsx in the same directory as actions and reducers folder.
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';

import { crudApp } from './reducers/products';

import { addProduct } from './actions';

var store = createStore(crudApp);

class App extends React.Component {

    constructor(){
        super();
        this.state = {
            products: [],
            productName: '',
            productDescription: ''
        };
    }

    componentWillMount(){
        store.subscribe(() => {
            var state = store.getState();
            this.setState({
                products: state.products
            });
        });
    }

    handleAddProductClick()
    {
        store.dispatch(addProduct({
            name: this.state.productName,
            description: this.state.productDescription
        }));
    }

    handleProductNameChange(pn){

        this.setState({
            products: this.state.products,
            productName: pn.target.value,
            productDescription: this.state.productDescription
        });
    }

    handleProductDescriptionChange(pd){
        this.setState({
            products: this.state.products,
            productName: this.state.productName,
            productDescription: pd.target.value
        });
    }

    render () {
        return(
            <div>
                <p>HMR is cool</p>
                <table>
                    <tbody>
                        <tr>
                            <td>Product Name</td>
                            <td><input type="text" onChange={this.handleProductNameChange.bind(this)}/></td>
                        </tr>
                        <tr>
                            <td>Product Description</td>
                            <td><input type="text" onChange={this.handleProductDescriptionChange.bind(this)}/></td>
                        </tr>
                    </tbody>
                </table>
                <button onClick={this.handleAddProductClick.bind(this)}>Add product</button>
                <ul>
                {
                    this.state.products.map((product, i) => {
                        return <li key={i}>{product.name} - {product.description}</li>
                    })
                }
                </ul>
            </div>
        );
    }
};

render(<App/>, document.getElementById('app'));

module.hot.accept();
Here we create store by using the createStore method from redux, passing in our crudApp function exported by reducers/products.js. On componentWillMount we subscribe to the store and state what to do when the state is updated. When the state is updated we update the state of the component that will update the view. To run the application just open a command window in the project root folder and execute npm start.


Every time we update the code the HMR will hot reload our application, preserving the state of applications that are not in the files we changed.

Directory structure

- node_modules
- src
    - actions
        - index.js
    - reducers
        - products.js
    - index.jsx
- .babelrc
- index.html
- package.json
- server.js
- webpack.config.js

Creating Simple CRUD MySQL, ExpressJS, and ReactJS

posted Nov 1, 2016, 7:21 PM by Andi Muqsith Ashari   [ updated Dec 5, 2016, 6:55 PM by Surya Wang ]


Introduction

In this tutorial we’re going to build a simple CRUD (Create, Read, Update, and Delete) web application using ExpressJS, React, and MySQL as database.

Preparing the Database

Create database named ‘tutorial’ and create table named ‘products’ inside the database, here is the table details:

Column Name

Data Type

Length

Note

id

int

 

Auto Increment, Primary Key

name

varchar

50

 

price

Int

 

 

created_at

timestamp

 

Default : CURRENT_TIMESTAMP

 

Creating New ExpressJS Project

We need Express Generator to build our Express empty project, type this command in your command line to install Express Generator globally to your system:

npm install express-generator -g

After installing Express Generator, type this command to generate new empty project:
express tutorial

Change the “tutorial” to your project name, ExpressJS will generate a default project structure as shown below: 
 
Then install the dependencies by running this command:
npm install

After installing the dependencies your project is ready to run by running this command:

npm start

If you seeing this command result on your command line, then it’s mean your project is already running at : http://localhost:3000


Creating a Simple CRUD Web Service Using MySQL

We need to install mysql dependency to connect to mysql database, use this command to install mysql dependency:

npm install mysql --save

After install mysql dependency, import and create pool to mysql database by adding this lines of code into app.js:

var mysql = require('mysql');

//connect to mysql don't use var tomake it global

pool = mysql.createPool({

    host: 'localhost',

    user: 'root',

    password: '',

    database: 'tutorial'

});

Change the host, user, password, and database according to your mysql database environment, after creating the pool to mysql database, let’s create file named ‘products.js’ inside routes directory, we are going to create web service with details:

Method

Action

Description

GET

/products

Get list of products

POST

/products

Insert new product data

GET

/products/:id

Get product based on id

PUT

/products/:id

Update product based on id

DELETE

/products/:id

Delete product based on id

Inside the products.js file add this following code:

var express = require('express');

var router = express.Router();


//get list of product

router.get('/', function(req, res, next) {

    pool.getConnection(function(err, connection) {

        connection.query("SELECT * FROM products", function(err, rows) {

            if (!err && rows.length > 0) {

                res.json(rows);

            } else {

                res.json([]);

            }

        });

    });

});


//get product by id

router.get('/:id', function(req, res, next) {

    pool.getConnection(function(err, connection) {

        var id = req.params.id;

        connection.query("SELECT * FROM products WHERE id='" + id + "' LIMIT 1", function(err, rows) {

            if (!err && rows.length > 0) {

                res.json(rows[0]);

            } else {

                res.json([]);

            }

        });

    });

});


//add new product

router.post('/', function(req, res, next) {

    pool.getConnection(function(err, connection) {

        var postBody = req.body;

        var productName = postBody.name;

        var productPrice = postBody.price;

        connection.query("INSERT INTO products (name, price) VALUES ('" + productName + "','" + productPrice + "')", function(err, rows) {

            if (rows.affectedRows) {

                connection.query("SELECT * FROM products WHERE id='" + rows.insertId + "' LIMIT 1", function(err, rows) {

                    if (!err && rows.length > 0) {

                        res.json(rows[0]);

                    } else {

                        res.json([]);

                    }

                });

            }

        });

    });

});


//delete product

router.delete('/:id', function(req, res, next) {

    pool.getConnection(function(err, connection) {

        var id = req.params.id;

        connection.query("DELETE FROM products WHERE id='" + id + "'", function(err, rows) {

            if (!err) {

                res.json({

                    "status": true

                });

            } else {

                res.json([]);

            }

        });

    });

});


//update product

router.put('/:id', function(req, res, next) {

    pool.getConnection(function(err, connection) {

        var postBody = req.body;

        var productId = req.params.id;

        var productName = postBody.name;

        var productPrice = postBody.price;

        connection.query("UPDATE products SET name='" + productName + "', price='" + productPrice + "' WHERE id='" + productId + "'", function(err, rows) {

            if (rows.affectedRows) {

                connection.query("SELECT * FROM products WHERE id='" + productId + "' LIMIT 1", function(err, rows) {

                    if (!err && rows.length > 0) {

                        res.json(rows[0]);

                    } else {

                        res.json([]);

                    }

                });

            }

        });

    });

});


module.exports = router;

Our product service is ready to use, we need to import the products.js into app.js by adding this lines of code in app.js file:

//import the products.js

var products = require('./routes/products');

//add products to ExpressJS route

app.use('/products', products);

You can check your web service using 3rd party application like postman to make sure your web service is running well, don’t forget to restart your project by stopping the project using ctrl+c and run the project again using :

npm start

Creating the Front End Using ReactJS

Our web service is ready to use, next thing to do is installing the ReactJS into your project, we need to use Webpack and Babel dependencies to run ReactJS, use command below to install the dependencies to our project:

npm install webpack –save

npm i babel-loader babel-core babel-preset-es2015 babel-preset-react –save

npm i react react-dom –save

We need to use React Roter to route our React application and Axios to make a http request in our project:

npm install react-router –save

npm install axios --save

After all things already installed lets modify index.jade as project index page, this page will import jQuery, bootstrap, toastr, and bundle.js (application file generated by babel):

doctype html

html

  head

    link(rel="stylesheet",href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css")

    link(rel="stylesheet",href="//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/css/toastr.min.css")

    script(src="//ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js")

    script(src="//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/js/toastr.min.js")

    script(src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js")

  body

    #app

    script(src="javascripts/bundle.js")

We need to add webpack.config.js as a webpack configuration file in our root directory:

var webpack = require('webpack');

var path = require('path');


var BUILD_DIR = path.resolve(__dirname, 'public');

var APP_DIR = path.resolve(__dirname, 'app');


var config = {

    entry: APP_DIR + '/index.jsx',

    output: {

        path: BUILD_DIR + '/javascripts',

        filename: 'bundle.js'

    },

    module: {

        loaders: [{

            test: /\.jsx?/,

            include: APP_DIR,

            loader: 'babel'

        }]

    }

}


module.exports = config;

Create directory named app inside our root directory, create index.jsx file inside the app directory:

import React from 'react';

import { render } from 'react-dom';

import { Router, Route, Link, hashHistory } from 'react-router'


import HomeComponent from './components/home/HomeComponent.jsx';

import ProductComponent from './components/product/ProductComponent.jsx';

import ProductListComponent from './components/product/ProductListComponent.jsx';

import ProductNewComponent from './components/product/ProductNewComponent.jsx';

import ProductEditComponent from './components/product/ProductEditComponent.jsx';

import AboutComponent from './components/about/AboutComponent.jsx';


class App extends React.Component {

    

    render() {

        return (

            <div>

                <div className="row">

                    <div className="col-sm-8 col-sm-offset-2">

                        <nav className="navbar navbar-default">

                            <div className="container-fluid">

                                <div className="navbar-header">

                                    <a className="navbar-brand">Simple CRUD</a>

                                </div>

                                <div id="navbar" className="navbar-collapse collapse">

                                    <ul className="nav navbar-nav">

                                        <li><a href="#/">Home</a></li>

                                        <li><a href="#/product">Product Management</a></li>

                                        <li><a href="#/about">About</a></li>

                                    </ul>

                                </div>

                            </div>

                        </nav>

                        <Router history={hashHistory}>

                            <Route path="/" component={HomeComponent} />

                            <Route path="/product" component={ProductComponent}>

                                <Route path="/product/list" component={ProductListComponent} />

                                <Route path="/product/new" component={ProductNewComponent} />

                                <Route path="/product/edit/:productId" component={ProductEditComponent} />

                            </Route>

                            <Route path="/about" component={AboutComponent} />

                        </Router>

                    </div>

                </div>

            </div>

        );

    }


}


render( <App /> , document.getElementById('app'));

Create 2 directories classes and components inside app directory, and add new file named TableClass.jsx inside classes directory:

import React from 'react';


const TableClass = React.createClass({


    bindHeader:function(){

        var cols = this.props.cols;

        var elements = cols.map(function(colHeader){

            return <th key={colHeader.key}>{colHeader.label}</th>

        });

        //action column

        elements.push(<th key="dataHeaderAction">Action</th>);

        return elements;

    },


    bindData:function(){

        var data = this.props.data;

        var self = this;

        return data.map(function(colData){

            var rowElement = [];

            $.each(colData,function(key,val){

                rowElement.push(<td key={key}>{val}</td>);              

            });

            //action column

            rowElement.push(

                <td key="actionColumn">

                    <div className="col-md-2">

                        <button className="btn btn-xs btn-primary" onClick={self.props.onUpdate} data-id={colData.id}>Edit</button>

                    </div>

                    <div className="col-md-2">

                        <button className="btn btn-xs btn-danger" onClick={self.props.onDelete} data-id={colData.id}>Delete</button>

                    </div>

                </td>

            );

            return <tr className='data-row' data-id={colData.id} key={colData.id}>{rowElement}</tr>;

        });

    },


    render:function(){


        var tableHeader = this.bindHeader();

        var tableData = this.bindData();


        return (

            <table className='table table-hover table-striped table-bordered'>

                <thead>

                    <tr>{tableHeader}</tr>

                </thead>

                <tbody>

                    {tableData}

                </tbody>

            </table>

        );

    }


});


export default TableClass;

Create 3 directories about, home, and product inside components directory, add new file named AboutComponent.jsx inside about directory:

import React from 'react';


class AboutComponent extends React.Component{


    render(){

        return (

            <div className="panel panel-default">

                <div className="panel-heading">About</div>

                <div className="panel-body">

                    This is a simple CRUD tutorial result, this project using : 

                    <ul>

                        <li>NodeJS</li>

                        <li>Express JS</li>

                        <li>MySQL</li>

                        <li>Webpack</li>

                        <li>Babel</li>

                        <li>React</li>

                        <li>Axios</li>

                        <li>jQuery</li>

                        <li>Bootstrap</li>

                        <li>Toastr</li>

                    </ul>

                </div>

            </div>

        );

    }


}


export default AboutComponent;


Add new file named HomeComponent.jsx inside home directory:

import React from 'react';

class HomeComponent extends React.Component{

    render(){
        return (
            <div className="panel panel-default">
                <div className="panel-heading">Home</div>
                <div className="panel-body">Welcome to simple CRUD tutorial</div>
            </div>
        );
    }

}

export default HomeComponent;

The main part of this tutorial is we are going to create product management page inside product directory, we need to create 4 files ProductComponent.jsx, ProductEditComponent.jsx, ProductListComponent.jsx, and ProductNewComponent.jsx

ProductComponent.jsx

import React from 'react';

import { Link } from 'react-router'


class ProductComponent extends React.Component{


    render(){

        return (

            <div className="panel panel-default">

                <div className="panel-heading">Product Management</div>

                <div className="panel-body">

                    <ul className="nav nav-tabs">

                        <li><Link activeClassName="active" to="product/list">Product List</Link></li>

                        <li><Link activeClassName="active" to="product/new">Add New Product</Link></li>

                    </ul>

                    <br />

                    {this.props.children}

                </div>

            </div>

        );

    }


}


export default ProductComponent;

ProductListComponent.jsx

import React from 'react';

import axios from 'axios';


import TableClass from '../../classes/TableClass.jsx';


class ProductListComponent extends React.Component{


    constructor(props) {

        super(props);

        this.getProductList();


        this.state = {

            cols : [

                {key:'dataHeaderId',label:'Id'},

                {key:'dataHeaderName',label:'Name'},

                {key:'dataHeaderPrice',label:'Price'},

                {key:'dataHeaderCreatedAt',label:'Created At'}

            ],

            data : [

                

            ]

        };

    }


    getProductList(){

        toastr.info('Fetching product list...');

        var self = this;

        axios.get('products').then(function(response){

            toastr.clear();

            self.setState({

                cols : self.state.cols,

                data : response.data

            });

        }).catch(function(error){

            toastr.clear();

            toastr.error(error);

        });

    }


    updateProduct(data){

        var id = $(data.target).data('id');

        location.href='#/product/edit/'+id;

    }


    deleteProduct(data){

        var id = $(data.target).data('id');

        $("#deleteConfirmationModal").modal('show');

        $("#deleteButton").attr('data-id',id);

    }


    doDeleteProduct(data){

        var id = $(data.target).data('id');

        toastr.info('Deleting product...');

        axios.delete('products/'+id).then(function(response){

            toastr.clear();

            $(".data-row[data-id='"+id+"']").slideUp();

        }).catch(function(error){

            toastr.clear();

            toastr.error(error);

        });

    }


    render(){

        return (

            <div>

                <TableClass cols={this.state.cols} data={this.state.data} onDelete={this.deleteProduct} onUpdate={this.updateProduct}/>

                <div className="modal fade" id="deleteConfirmationModal" role="dialog">

                    <div className="modal-dialog">

                        <div className="modal-content">

                            <div className="modal-header">

                                <button type="button" className="close" data-dismiss="modal">&times;</button>

                                <h4 className="modal-title">Delete Item</h4>

                            </div>

                            <div className="modal-body">

                                <p>Are you sure want to delete this item?</p>

                            </div>

                            <div className="modal-footer">

                                <button type="button" className="btn btn-default" data-dismiss="modal">Cancel</button>

                                <button type="button" className="btn btn-danger" 

                                        id="deleteButton" 

                                        onClick={this.doDeleteProduct.bind(this)} 

                                        data-dismiss="modal">Delete Item</button>

                            </div>

                        </div>

                    </div>

                </div>

            </div>

        );

    }


}


export default ProductListComponent;

ProductNewComponent.jsx

import React from 'react';

import axios from 'axios';


class ProductNewComponent extends React.Component{


    constructor(props) {

        super(props);

        this.state = {

            name : null,

            price : null

        }

    }


    submitForm(event){

        event.preventDefault();

        var data = $(event.target).serialize();

        toastr.clear();

        var isError = false;

        if(this.state.name===""){

            toastr.error("Product name must be filled!");

            isError=true;

        }

        if(this.state.price===0 || this.state.price===''){

            toastr.error("Product price must be filled!");

            isError=true;

        }

        if(!isError){

            toastr.info('Inserting new product data...');

            axios.post('/products',{

                name : this.state.name,

                price : this.state.price

            }).then(function(response){

                toastr.clear();

                location.href = "#/product/list";

            }).catch(function(error){

                toastr.clear();

                toastr.error(error);

            });

        }

    }


    onProductNameChange(e){

        this.setState({

            id : this.state.id,

            name : e.target.value.trim(),

            price : this.state.price

        });

    }


    onProductPriceChange(e){

        this.setState({

            id : this.state.id,

            name : this.state.name,

            price : e.target.value

        });

    }


    render(){

        return (

            <div>

                <form className="form-horizontal" onSubmit={this.submitForm.bind(this)}>

                    <div className="form-group">

                        <label className="control-label col-sm-2" htmlFor="productEmail">Name : </label>

                        <div className="col-sm-10">

                            <input  type="text" name='productName' 

                                    onChange={this.onProductNameChange.bind(this)}

                                    id="productName" className="form-control" placeholder="Product Name" />

                        </div>

                    </div>

                    <div className="form-group">

                        <label className="control-label col-sm-2" htmlFor="productPrice">Price : </label>

                        <div className="col-sm-10">

                            <input  type="number" name='productPrice' 

                                    onChange={this.onProductPriceChange.bind(this)}

                                    id="productPrice" className="form-control" placeholder="Product Price" />

                        </div>

                    </div>

                    <div className="form-group">

                        <div className="col-sm-offset-2 col-sm-10">

                            <button type="submit" className="btn btn-default">Save</button>

                        </div>

                    </div>

                </form>


            </div>

        );

    }


}


export default ProductNewComponent;

ProductEditComponent.jsx

import React from 'react';

import axios from 'axios';


class ProductNewComponent extends React.Component{


    constructor(props) {

        super(props);

        this.state = {

            name : null,

            price : null

        }

    }


    submitForm(event){

        event.preventDefault();

        var data = $(event.target).serialize();

        toastr.clear();

        var isError = false;

        if(this.state.name===""){

            toastr.error("Product name must be filled!");

            isError=true;

        }

        if(this.state.price===0 || this.state.price===''){

            toastr.error("Product price must be filled!");

            isError=true;

        }

        if(!isError){

            toastr.info('Inserting new product data...');

            axios.post('/products',{

                name : this.state.name,

                price : this.state.price

            }).then(function(response){

                toastr.clear();

                location.href = "#/product/list";

            }).catch(function(error){

                toastr.clear();

                toastr.error(error);

            });

        }

    }


    onProductNameChange(e){

        this.setState({

            id : this.state.id,

            name : e.target.value.trim(),

            price : this.state.price

        });

    }


    onProductPriceChange(e){

        this.setState({

            id : this.state.id,

            name : this.state.name,

            price : e.target.value

        });

    }


    render(){

        return (

            <div>

                <form className="form-horizontal" onSubmit={this.submitForm.bind(this)}>

                    <div className="form-group">

                        <label className="control-label col-sm-2" htmlFor="productEmail">Name : </label>

                        <div className="col-sm-10">

                            <input  type="text" name='productName' 

                                    onChange={this.onProductNameChange.bind(this)}

                                    id="productName" className="form-control" placeholder="Product Name" />

                        </div>

                    </div>

                    <div className="form-group">

                        <label className="control-label col-sm-2" htmlFor="productPrice">Price : </label>

                        <div className="col-sm-10">

                            <input  type="number" name='productPrice' 

                                    onChange={this.onProductPriceChange.bind(this)}

                                    id="productPrice" className="form-control" placeholder="Product Price" />

                        </div>

                    </div>

                    <div className="form-group">

                        <div className="col-sm-offset-2 col-sm-10">

                            <button type="submit" className="btn btn-default">Save</button>

                        </div>

                    </div>

                </form>


            </div>

        );

    }


}


export default ProductNewComponent;


Creating 3D Dodge Ball Game Using three.js

posted Oct 30, 2016, 11:44 PM by Benedictus Jason Reinhart   [ updated Dec 5, 2016, 6:55 PM by Surya Wang ]


Getting Started

Three.js is a JavaScript library used to create and display animated 3D computer graphics in a web browser. It uses WebGL as the base technology. In this tutorial we are going to create a 3D dodge ball game using the Three.js library and play it a web browser. This tutorial will not cover the basic JavaScript, WebGL, or how to create a multiplayer game.

Before reading this tutorial, make sure you have:

  • ·         Strong basic knowledge of JavaScript
  • ·         Common sense in 3D world (Vectors, Rays, etc.)
  • ·         Text editor for your JavaScript and HTML code (Sublime, Notepad++, VS Code, etc.)
  • ·         Modern browser that supports WebGL (Chrome, Firefox, etc.) to see and test your creation

If you already have those mentioned above, then you should download the Three.js library from here. Before you can use it, you need a HTML to display it, as it’s based on a canvas element.

<!DOCTYPE html> 
<html>
<head> 
    <title>Dodge Ball</title> 
    <style> 
        body { margin: 0; } 
        canvas { width: 100%; height: 100% } 
    </style> 
</head> 
<body> 
    <script src="three.js"></script> 
    <script> 
        // Our JavaScript will go here. 
    </script> 
</body> 
</html>

Creating a Scene

A scene is simply a world where objects “live”. An object such as a cube or sphere needs to be placed in a scene in order to be rendered.

"use strict";
var renderer = null;
var scene = null;
var camera = null;

var balls = [];
var player = null;
var ballsDodged = 0;

var moveLeft = false;
var moveRight = false;

var delta = 0;
var lastUpdate = Date.now();
var spawnTimer = 500; // Delay spawning of the first ball

var init = function() {
    scene = new THREE.Scene(); // Creating a scene.
    camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000); // A scene needs a camera so the player can see things in the scene.

    renderer = new THREE.WebGLRenderer(); // The WebGLRenderer of the browser
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement); // It appends a canvas element to the HTML

    // We are going to create the ground using a box. Creating an object (a mesh, actually) in Three.js needs 2 parameter, shape (we call it geometry here) and material (texture, color, etc.)
    var landGeometry = new THREE.BoxGeometry(40, 1, 70);
    var landTexture = new THREE.TextureLoader().load('textures/land.jpg');
    landTexture.wrapS = THREE.RepeatWrapping;
    landTexture.wrapT = THREE.RepeatWrapping;
    landTexture.repeat.set(2, 2);
    var landMaterial = new THREE.MeshLambertMaterial({
        color: 0xaadd00,
        map: landTexture
    });
    var land = new THREE.Mesh(landGeometry, landMaterial);
    scene.add(land); // Add the land to the scene. Without this method, your land will not be rendered.

    var directionalLight = new THREE.DirectionalLight(0xffffff, 0.7);
    scene.add(directionalLight);

    camera.position.set(-0.3, 9, 40); // x, y, z accordingly
}

var render = function() {
    requestAnimationFrame(render);
    var now = Date.now();
    delta = now - lastUpdate;
    lastUpdate = now;
}

init();
render();

In the above code, we create a world (scene), a camera in it so player can see things, a renderer for the web browser, and a directional light so the terrain won’t be dark. Notice that we load a texture (textures/land.jpg). We can apply a texture for a mesh with the TextureLoader class, so make sure you have a texture in textures/ directory.

Summary:

  • ·         Every Three.js application needs a scene as its world (THREE.Scene)
  • ·         Every scene needs a renderer and a camera to be able to see what is in the world (THREE.WebGLRenderer and THREE.PerspectiveCamera, there are other types of camera but in this tutorial we use the PerspectiveCamera)
  • ·         Every object (mesh) in the world (scene) needs a geometry (THREE.BoxGeometry, there are various types of geometry) and material (THREE.MeshLambertMaterial, there are various types of material)
  • ·         Every object instantiated needs to be added to the scene (via scene.add(object))
  • ·         A scene needs lighting so the textures will have brightness on it and shadows (we’ll get into it in later chapter)
  • ·         We need to call requestAnimationFrame(callback) function. The callback parameter is a function to animate and update things every frame
  • ·         We need to compute delta time in order to maintain a stable game as different CPU might give different delta time

Note: If you have an error XmlHttpRequest not allowed to load file, you need a web server to host it. It is not mandatory to use a texture in this tutorial, so you can just skip or comment the LoadTexture code and the map attribute on material.

Adding Player Control

For the sake of simplicity, the player will control a cube that can only strafe left or right. Previously, we have declared:

var player = null;

Before we assign a value to the player, let’s create the object first. Add the following code in the init function:

var playerGeometry = new THREE.BoxGeometry(1.5, 1.5, 1.5);
var playerMaterial = new THREE.MeshLambertMaterial({color: 0x4444dd});
var player = new THREE.Mesh(playerGeometry, playerMaterial);
player.receiveShadow = true;
player.castShadow = true;
player.position.set(0, 1.5, 28);
player.isAlive = true;

scene.add(player);

To make things look realistic, we’ll set the player to receive and cast shadow. We also set the player position to a certain coordinate. Because I hardcoded the values, If you want to use different values for the ground and player, you’ll need to adjust things yourself. Don’t forget to add the player to the scene or the player will not be rendered. The isAlive property is a custom property we use to determine whether the player is alive or not. Later we’ll set it to false if the player collides with a ball, ending the game respectively.

For player to be able to move, we need to add keyboard listeners. Add the following code to the init function:

document.onkeydown = function(event) {
    event = event || window.event;

    switch (event.keyCode) {
    case 37:
    case 65:
        moveLeft = true;
        break;
    case 39:
    case 68:
        moveRight = true;
        break;
    }
}

document.onkeyup = function(event) {
    event = event || window.event;

    switch (event.keyCode) {
    case 37:
    case 65:
        moveLeft = false;
        break;
    case 39:
    case 68:
        moveRight = false;
        break;
    }
}

We have declared the moveLeft and moveRight variable previously, and we’ll set it to true or false according to user’s keyboard state. In this case, the keycode I used are A and left arrow to move left and D and right arrow to move right. Then, add the following code in the render() function so the movement will be checked in every frame:

if (moveLeft && player.position.x > -18) player.translateX(-0.01 * delta);
if (moveRight && player.position.x < 18) player.translateX(0.01 * delta);

The hardcoded width of the ground is 40, and the hardcoded player box width is 1, so we need to validate the box to not move beyond the ground’s width. As the x axis of the ground is 0, the ground will span from -20 to 20, so we validate that the box will not move beyond that point.

Spawning and Rolling Balls

In the previous section we have added a computation of delta time (var delta = ...) and a spawn timer. We will use both the spawn timer variable and the delta time to produce balls for every given time.

Before spawning the balls, let’s prepare a function that creates a ball every time it’s called. We will name it createBall(). Add the function outside from any scope so it can be called anywhere:

var createBall = (function() {
    var ballGeometry = new THREE.SphereGeometry(1, 128, 128);
    var ballTexture = new THREE.TextureLoader().load('textures/ball.jpg');
    ballTexture.wrapS = THREE.RepeatWrapping;
    ballTexture.wrapT = THREE.RepeatWrapping;
    var ballMaterial = new THREE.MeshLambertMaterial({map: ballTexture});

    return function() {
        var ball = new THREE.Mesh(ballGeometry, ballMaterial);
        ball.castShadow = true;
        ball.receiveShadow = true;
        ball.position.set((Math.random() - 0.5) * 38, 1.4, -35);
        return ball;
    }
})();

The main reason we create the function and the self-invoking function is because creating a new geometry, texture, and material are an expensive operation while these are actually reusable objects, so we will store those in the self-invoking function variables.

To spawn a ball for every given time, add the following code in the render() function:

spawnTimer -= delta;
if (spawnTimer <= 0) {
    var ball = createBall();
    scene.add(ball);
    balls.push(ball);
    spawnTimer = 100;
}

The balls variable is used to store the balls so we don’t have to use findObjectByName(). Now, rolling the ball and removing it after reaching certain point:

for (var ball of balls) { 
    var distance = 0.02 * delta; 
    ball.position.z += distance; 
    ball.rotation.x += distance; 

    if (ball.position.z >= 70) { 
        balls.splice(balls.indexOf(ball), 1); 
        scene.remove(ball); 
        ballsDodged++; 
    } 
}

Checking Collision

Collision is an important feature in this game, as the primary goal of the game is to avoid collision. To check whether 2 objects collide each other or not, we will use a simple collision detection using raycaster.

Raycasting can be described as the process of shooting a ray or line from a point to a certain direction. After raycasting, we detect whether the ray intersects with an object or not. In this game, we will cast a ray from player to 8 point, north, north east, east, south east, and so on. If one of these rays intersects with a ball, the player lose the game. To do so, we must check the collision of each ball in the game. Let’s modify our player code to this:

var playerGeometry = new THREE.BoxGeometry(1.5, 1.5, 1.5); 
var playerMaterial = new THREE.MeshLambertMaterial({color: 0x4444dd}); 
var directions = [
    new THREE.Vector3(0, 0, 1), 
    new THREE.Vector3(1, 0, 1), 
    new THREE.Vector3(1, 0, 0), 
    new THREE.Vector3(1, 0, -1), 
    new THREE.Vector3(0, 0, -1), 
    new THREE.Vector3(-1, 0, -1), 
    new THREE.Vector3(-1, 0, 0), 
    new THREE.Vector3(-1, 0, 1) 
]; 

var player = new THREE.Mesh(playerGeometry, playerMaterial); 
player.receiveShadow = true; 
player.castShadow = true; 
player.position.set(0, 1.5, 28); 
player.isAlive = true; 
player.checkCollision = function(ball) { 
    var playerPosition = this.position.clone(); 
    var raycaster = new THREE.Raycaster(); 
    var collisions = []; 
    for (var direction of directions) { 
        raycaster.set(playerPosition, direction); 
        var collision = raycaster.intersectObject(ball); 
        if (collision.length > 0 && collision[0].distance <= 0.5) { 
            this.isAlive = false;
            break;
        }
    }
}

So we add a directions array which contains a vector to define the 8 directions mentioned above. We also add a checkCollision() function which has a parameter of ball. Now, we will use the function inside the game loop. Modify the balls update logic:

for (var ball of balls) { 
    var distance = 0.02 * delta; 
    ball.position.z += distance; 
    ball.rotation.x += distance; 
    player.checkCollision(ball); 

    if (ball.position.z >= 70) { 
        balls.splice(balls.indexOf(ball), 1); 
        scene.remove(ball); 
        ballsDodged++;
    }
}

Now we add a validation so the game only runs when the player is alive.

if (player.isAlive) {
    requestAnimationFrame(render);
}

Lighting and Shadow

Most 3D games look realistic with the help of shadow. In Three.js, all objects don’t cast or receive shadows by default. To enable it, we can simply modify the castShadow and receiveShadow attribute to true. Let’s modify our objects now by adding the following code in the init() function:

land.receiveShadow = true;
land.castShadow = false;
player.receiveShadow = true;
player.castShadow = true;

In the createBall:

var ball = new THREE.Mesh(ballGeometry, ballMaterial); 
... 
... 
ball.castShadow = true; 
ball.receiveShadow = true;

Then we add a SpotLight as the “sun” in our scene. Add the SpotLight in init():

var light = new THREE.SpotLight(0xffffff);
light.castShadow = true;
light.angle = Math.PI / 4;
light.position.set(-10, 20, 40);
scene.add(light);

That's it, our game is complete and looks okay now. This tutorial does not cover the best practices of using three.js, so if you have questions, suggestions, and critics please leave a comment below.

[Java] Tic Tac Toe AI with Minimax Tree and Alpha Beta Pruning

posted Oct 28, 2016, 3:53 AM by Denny Angkasa   [ updated Dec 5, 2016, 6:54 PM by Surya Wang ]


Introduction

Tic Tac Toe is a game where players take turns marking spaces in a 3x3 grid with their own symbol, either X or O. It is however, a flawed game in the meaning that when both players do not make a mistake, the game will for sure lead to a draw. In that case, it is possible to create an AI to play the game where it will never lose, only knowing how to win or draw the game. We will create the game and the AI in Java, console based.

Node Class

Node class is used to represent a node in the Minimax Tree. The board variable represents the current state of the board in the node. The nextPlayer variable represents the next player taking the turn. The parent variable represents the parent of the current node in the tree. The heuristic value represents the estimated value of the move of the node. The atDepth variable ensures that we only take a possible next move from atDepth == 1 (next move for the node). The traversalDepth variable represents the depth of the node in the tree.

public class Node {

String[][] board;
String nextPlayer;
Node parent;
int heuristicValue = 0;
int atDepth = 0;
int traversalDepth = 0;
public Node(){
board = new String[3][3];
parent = null;
}
public Node(String[][] board, Node parent, int heuristicValue, int atDepth, String nextPlayer, int traversalDepth){
this.board = board;
this.parent = parent;
this.heuristicValue = heuristicValue;
this.atDepth = atDepth;
this.nextPlayer = nextPlayer;
this.traversalDepth = traversalDepth;
}
}

Starting the game

We create a root node. A root node is the state of the board when the game begins (clean board). We start the game by asking if the player wants to move first. After this we’ll look at how to perform a move for the player.

int getIntInput()
{
    int i = -1;
    try{
        i = scanner.nextInt();
        scanner.nextLine();
    }catch(Exception e){
        scanner.nextLine();
    }
    
    return i;
}

boolean isPlayerMovingFirst(Node node)
{
    printBoard(node);
    String input = "";
    
    do
    {
        System.out.println("Do you want to move first? [y/n] ['e' to exit]: ");
        input = scanner.nextLine();
        
        if(input.equalsIgnoreCase("e"))
            System.exit(0);
    }while(!input.equalsIgnoreCase("y") && !input.equalsIgnoreCase("n"));
    
    if(input.equalsIgnoreCase("y"))
        return true;
    
    return false;
}

void startGame()
{
    Node root = new Node();
    clear();
    
    boolean playerMovesFirst = isPlayerMovingFirst(root);
    if(playerMovesFirst)
    {
        root.nextPlayer = "O";
        moveForPlayer(root);
    }
    else
    {
        root.nextPlayer = "X";
        moveForBot(root);
    }
}

public Main(){
    while(true){
        startGame();
        scanner.nextLine();
    }
}

public static void main(String[] args) {
    new Main();
}

Player’s move

To do a move for the player, we ask the player where they want to move. Then we have to validate if that move is valid. A move is valid if it is inside the board, and the place where the move will be placed in the board is not occupied. If the move is indeed valid, we produce a new node which is the successor of the previous node with the move the player just made. This new node with updated game state is then passed into the moveForBot function so that the bot can move. The bot will then produce a new successor node too and pass it to moveForPlayer function. This cycle will continue until the game ends in either the bot’s win or the bot’s draw, because apparently this bot cannot lose.


ArrayList<Point> getAvailableMoves(Node node)
{
    ArrayList<Point> availableMoves = new ArrayList<Point>();
    for(int i = 0; i<3; i++)
    {
        for(int j = 0; j<3; j++)
        {
            if(node.board[i][j] == null)
            {
                availableMoves.add(new Point(j, i));
            }
        }
    }
    
    return availableMoves;
}

Node getSuccessor(Node node, Point p) {
    
    if(isLeafNode(node)) return null;
    
    return new Node(updateBoard(node, p), node, evaluateHeuristicValue(node), node.atDepth+1, node.nextPlayer.equals("X") ? "O" : "X", node.traversalDepth+1);
}

void printBoard(Node node){
    String board[][] = node.board;
    
    clear();
    System.out.println("==========================");
    System.out.println("| Impossible Tic-Tac Toe |");
    System.out.println("==========================");
    
    System.out.println("-----------");
    System.out.println("|y\\x| 0 | 1 | 2 |");
    
    for(int i = 0; i<3; i++)
    {
        System.out.println("-----------");
        System.out.print("| " + i + " ");
        for(int j = 0; j<3; j++)
        {
            System.out.print("| ");
            if(board[i][j] != null)
                System.out.print(board[i][j]);
            else
                System.out.print(" ");
            System.out.print(" ");
        }
        System.out.println("|");
    }
    System.out.println("-----------");
}

void moveForPlayer(Node node)
{
    Node newNode = new Node();
    ArrayList<Point> availableMoves = getAvailableMoves(node);
    Point input = getInputFromPlayer(node, availableMoves);
    newNode = getSuccessor(node, input);
    
    printBoard(newNode);
    System.out.println("Computer's turn, press enter to continue");
    
    if(checkWin(newNode))
    {
        System.out.println("You Won! Press enter to play again");
    }
    else if(isLeafNode(newNode))
    {
        System.out.println("Draw Game! Press enter to play again");
    }
    else
    {
        scanner.nextLine();
        moveForBot(newNode);
    }
}

Point getInputFromPlayer(Node node, ArrayList<Point> availableMoves)
{
    Point move = new Point();
    do
    {
        int inputX, inputY;
        
        do
        {
            System.out.print("Input X: [0-2]: ");
            inputX = getIntInput();
        }while(inputX < 0 || inputX > 2);
        
        do
        {
            System.out.print("Input Y: [0-2]: ");
            inputY = getIntInput();
        }while(inputY < 0 || inputY > 2);
        
        move.x = inputX;
        move.y = inputY;
        
        if(!isValidMove(move, availableMoves))
            System.out.println("Your move is invalid!");
        
    }while(!isValidMove(move, availableMoves));
    
    return move;
}

Checking if the game has been won by a player or drawn

A player wins the game if he has 3 consecutive symbols in the board either vertically, horizontally, or diagonally. If a node is a leaf node, that means the next player has no possible moves left in the board (board is full), meaning the game ends in a draw.

boolean isLeafNode(Node node){
    return checkWin(node) || getAvailableMoves(node).size() == 0;
}

boolean checkWin(Node node){
    return checkWinRow(node) || checkWinColumn(node) || checkWinDiagonal(node);
}

boolean checkWinRow(Node node){
    
    String[][] board = node.board;
    return (board[0][0] != null && board[0][0] == board[0][1] && board[0][1] == board[0][2]) ||
            (board[1][0] != null && board[1][0] == board[1][1] && board[1][1] == board[1][2]) ||
            (board[2][0] != null && board[2][0] == board[2][1] && board[2][1] == board[2][2]);
}

boolean checkWinColumn(Node node){
    
    String[][] board = node.board;
    return (board[0][0] != null && board[0][0] == board[1][0] && board[1][0] == board[2][0]) ||
            (board[0][1] != null && board[0][1] == board[1][1] && board[1][1] == board[2][1]) ||
            (board[0][2] != null && board[0][2] == board[1][2] && board[1][2] == board[2][2]);
}

boolean checkWinDiagonal(Node node){
    
    String[][] board = node.board;
    return (board[0][0] != null && board[0][0] == board[1][1] && board[1][1] == board[2][2]) ||
            (board[0][2] != null && board[0][2] == board[1][1] && board[1][1] == board[2][0]);
}

The Minimax Tree and Alpha Beta Pruning algorithm

Minimax tree is a tree in which it represents 2 players. It alternates the represented player in each depth. For examples depth 1 represents player, depth 2 represents the bot, depth 3 represents the player, depth 4 represents the bot, and so on. It assumes that each player wants to take the move that is best for them. It will predict a certain number of turns ahead, so that it can produce a move that is an evaluation of the moves the player will take. The algorithm will take the best possible move to ensure that the player does not win the game. It evaluates which move is the best by their heuristic values. For examples a bad move in which player wins has the heuristic value of -1, meaning the bot must not take this move while a good move in which the bot prevents the player from winning (reaching 3 consecutive symbols) has the heuristic value of 1.

Then comes the alpha beta pruning implementation. As I explained in the paragraph above, the bot predicts a certain number of turns ahead, until either the MAX_TRAVERSAL_DEPTH is reached, or it reaches a leaf node. However, when a node already has a bad move in which for example it allows the player to win, we actually do not need to further evaluate the successor of this node since the bot will never take this move. Another case is that the move that has been evaluated is better than the move we are going to evaluate next. Alpha beta pruning allows us to prune the moves that we will not need to evaluate, optimizing the minimax tree algorithm. Below will be given the full code of the game.

The full code

import java.awt.Point;
import java.util.ArrayList;
import java.util.Scanner;


public class Main {
public static final int INFINITY = 99999;
public static final int MAX_TRAVERSAL_DEPTH = 6;
Scanner scanner = new Scanner(System.in);
int getIntInput()
{
int i = -1;
try{
i = scanner.nextInt();
scanner.nextLine();
}catch(Exception e){
scanner.nextLine();
}
return i;
}
void clear()
{
for(int i = 0; i<25; i++)
System.out.println();
}
public Main(){
while(true){
startGame();
scanner.nextLine();
}
}
void startGame()
{
Node root = new Node();
clear();
boolean playerMovesFirst = isPlayerMovingFirst(root);
if(playerMovesFirst)
{
root.nextPlayer = "O";
moveForPlayer(root);
}
else
{
root.nextPlayer = "X";
moveForBot(root);
}
}
boolean isPlayerMovingFirst(Node node)
{
printBoard(node);
String input = "";
do
{
System.out.println("Do you want to move first? [y/n] ['e' to exit]: ");
input = scanner.nextLine();
if(input.equalsIgnoreCase("e"))
System.exit(0);
}while(!input.equalsIgnoreCase("y") && !input.equalsIgnoreCase("n"));
if(input.equalsIgnoreCase("y"))
return true;
return false;
}
void moveForPlayer(Node node)
{
Node newNode = new Node();
ArrayList<Point> availableMoves = getAvailableMoves(node);
Point input = getInputFromPlayer(node, availableMoves);
newNode = getSuccessor(node, input);
printBoard(newNode);
System.out.println("Computer's turn, press enter to continue");
if(checkWin(newNode))
{
System.out.println("You Won! Press enter to play again");
}
else if(isLeafNode(newNode))
{
System.out.println("Draw Game! Press enter to play again");
}
else
{
scanner.nextLine();
moveForBot(newNode);
}
}
Point getInputFromPlayer(Node node, ArrayList<Point> availableMoves)
{
Point move = new Point();
do
{
int inputX, inputY;
do
{
System.out.print("Input X: [0-2]: ");
inputX = getIntInput();
}while(inputX < 0 || inputX > 2);
do
{
System.out.print("Input Y: [0-2]: ");
inputY = getIntInput();
}while(inputY < 0 || inputY > 2);
move.x = inputX;
move.y = inputY;
if(!isValidMove(move, availableMoves))
System.out.println("Your move is invalid!");
}while(!isValidMove(move, availableMoves));
return move;
}
boolean isLeafNode(Node node){
return checkWin(node) || getAvailableMoves(node).size() == 0;
}
boolean checkWin(Node node){
return checkWinRow(node) || checkWinColumn(node) || checkWinDiagonal(node);
}
boolean checkWinRow(Node node){
String[][] board = node.board;
return (board[0][0] != null && board[0][0] == board[0][1] && board[0][1] == board[0][2]) ||
(board[1][0] != null && board[1][0] == board[1][1] && board[1][1] == board[1][2]) ||
(board[2][0] != null && board[2][0] == board[2][1] && board[2][1] == board[2][2]);
}
boolean checkWinColumn(Node node){
String[][] board = node.board;
return (board[0][0] != null && board[0][0] == board[1][0] && board[1][0] == board[2][0]) ||
(board[0][1] != null && board[0][1] == board[1][1] && board[1][1] == board[2][1]) ||
(board[0][2] != null && board[0][2] == board[1][2] && board[1][2] == board[2][2]);
}
boolean checkWinDiagonal(Node node){
String[][] board = node.board;
return (board[0][0] != null && board[0][0] == board[1][1] && board[1][1] == board[2][2]) ||
(board[0][2] != null && board[0][2] == board[1][1] && board[1][1] == board[2][0]);
}
boolean isValidMove(Point move, ArrayList<Point> availableMoves)
{
for(int i = 0; i<availableMoves.size(); i++)
{
Point curr = availableMoves.get(i);
if(move.x == curr.x && move.y == curr.y)
return true;
}
return false;
}
void moveForBot(Node node)
{
Node newNode = new Node();
newNode.board = node.board;
newNode.nextPlayer = "X";
newNode = nextMove(newNode);
printBoard(newNode);
System.out.println("Your turn, press enter to continue");
if(checkWin(newNode))
{
System.out.println("You lost! Press enter to play again");
}
else if(isLeafNode(newNode))
{
System.out.println("Draw Game! Press enter to play again");
}
else
{
scanner.nextLine();
moveForPlayer(newNode);
}
}
Node nextMove(Node node){
getMiniMaxAlphaBeta(node, getAlpha(node), getBeta(node));
Node newNode = getMaxNodeFromPossibleMoves();
possibleNextMoves.clear();
return newNode;
}
Node getMaxNodeFromPossibleMoves()
{
Node maxNode = possibleNextMoves.get(0);
for(int i = 0, l = possibleNextMoves.size(); i<l; i++)
{
if(maxNode.heuristicValue < possibleNextMoves.get(i).heuristicValue)
{
maxNode = possibleNextMoves.get(i);
}
}
return maxNode;
}
int getMiniMaxAlphaBeta(Node node, int alpha, int beta)
{
if(isLeafNode(node) || node.traversalDepth >= MAX_TRAVERSAL_DEPTH)
return miniMaxLeafNode(node);
else if(node.nextPlayer.equals("O"))
return minimaxAlphaBetaForMinimizer(node, alpha, beta);
else
return minimaxAlphaBetaForMaximizer(node, alpha, beta);
}
int minimaxAlphaBetaForMinimizer(Node node, int alpha, int beta)
{
ArrayList<Node> allSuccessors = getAllSuccessors(node);
for(int i = 0, l = allSuccessors.size(); i<l; i++)
{
Node s = allSuccessors.get(i);
int currMin = getMiniMaxAlphaBeta(s, alpha, beta);
beta = Math.min(beta, currMin);
node.heuristicValue = Math.min(node.heuristicValue, beta);
if(alpha >= beta)
break;
}
if(possibleNextMoves(node) != null)
possibleNextMoves.add(node);
return beta;
}
int minimaxAlphaBetaForMaximizer(Node node, int alpha, int beta)
{
ArrayList<Node> allSuccessors = getAllSuccessors(node);
for(int i = 0, l = allSuccessors.size(); i<l; i++)
{
Node s = allSuccessors.get(i);
int currMax = getMiniMaxAlphaBeta(s, alpha, beta);
alpha = Math.max(alpha, currMax);
node.heuristicValue = Math.max(node.heuristicValue, alpha);
if(alpha >= beta)
break;
}
if(possibleNextMoves(node) != null)
possibleNextMoves.add(node);
return alpha;
}
int getAlpha(Node node)
{
if(isLeafNode(node))
return evaluateHeuristicValue(node);
return -INFINITY;
}
int getBeta(Node node)
{
if(isLeafNode(node))
return evaluateHeuristicValue(node);
return INFINITY;
}
ArrayList<Node> possibleNextMoves = new ArrayList<Node>();
int miniMaxLeafNode(Node node)
{
if(possibleNextMoves(node) != null)
possibleNextMoves.add(node);
return evaluateHeuristicValue(node);
}
ArrayList<Node> getAllSuccessors(Node node)
{
ArrayList<Node> successors = new ArrayList<Node>();
ArrayList<Point> availableMoves = getAvailableMoves(node);
for(int i = 0, l = availableMoves.size(); i<l; i++)
{
successors.add(getSuccessor(node, availableMoves.get(i)));
}
return successors;
}
Node possibleNextMoves(Node node){
if(node.atDepth == 1)
return node;
else
return null;
}
ArrayList<Point> getAvailableMoves(Node node)
{
ArrayList<Point> availableMoves = new ArrayList<Point>();
for(int i = 0; i<3; i++)
{
for(int j = 0; j<3; j++)
{
if(node.board[i][j] == null)
{
availableMoves.add(new Point(j, i));
}
}
}
return availableMoves;
}
Node getSuccessor(Node node, Point p) {
if(isLeafNode(node)) return null;
return new Node(updateBoard(node, p), node, evaluateHeuristicValue(node), node.atDepth+1, node.nextPlayer.equals("X") ? "O" : "X", node.traversalDepth+1);
}
int evaluateHeuristicValue(Node node)
{
if(node.nextPlayer == "X" && this.checkWin(node)==true) return -1;
if(node.nextPlayer == "O" && this.checkWin(node)==true) return 1;
return 0;
}
String[][] updateBoard(Node node, Point p) {
String[][] newBoard = copyBoard(node.board);
newBoard[p.y][p.x] = node.nextPlayer;
return newBoard;
}
String[][] copyBoard(String[][] aBoard) {
int boardSize = aBoard.length;
String[][] newBoard = new String[boardSize][boardSize];
for(int row = 0; row < boardSize; row++) {
for(int column = 0; column < boardSize; column++) 
newBoard[row][column] = aBoard[row][column];
}
return newBoard;
}
void printBoard(Node node){
String board[][] = node.board;
clear();
System.out.println("==========================");
System.out.println("| Impossible Tic-Tac Toe |");
System.out.println("==========================");
System.out.println("-----------");
System.out.println("|y\\x| 0 | 1 | 2 |");
for(int i = 0; i<3; i++)
{
System.out.println("-----------");
System.out.print("| " + i + " ");
for(int j = 0; j<3; j++)
{
System.out.print("| ");
if(board[i][j] != null)
System.out.print(board[i][j]);
else
System.out.print(" ");
System.out.print(" ");
}
System.out.println("|");
}
System.out.println("-----------");
}
public static void main(String[] args) {
new Main();
}
}

Simple Android Chat Application Part 2

posted Nov 14, 2015, 2:12 AM by Kenrick Satrio Sahputra   [ updated Aug 15, 2016, 11:35 PM by Surya Wang ]


Okay, continue from the last tutorial, where we have already setup the GCM stuff, 
now it's time for us to send a downstream message.
  
Downstream message is a message that is sent from our server to GCM Server. 
After that, GCM will figure out where this message should be passed, using token id as it's identifier, then it will send the message to the target device 
But first, our chat application must have a service, that can listen to a new incoming GCM message. 
That's is the overview of how GCM downstream message will work.

But first of all, we need to build our application interface first. For the sake of simplicity, we will only have one View. 
That view will contain 2 input control, 1 button, and 1 list view. 
The first input control will be used as a sender's name, the other will be used as a message content.
The button will be used to send the message.
The list view will contain all chat conversation.

Pretty simple, so let's get started.

1. Change the view in R.layout.activity_main

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<EditText
android:id="@+id/username"
android:hint="Username"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<Button
android:id="@+id/send_button"
android:text="Send Message"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

<EditText
android:id="@+id/message_input"
android:layout_toLeftOf="@id/send_button"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<ListView
android:id="@+id/chat_list_container"
android:layout_below="@id/username"
android:layout_above="@id/send_button"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

</RelativeLayout>
2. Next modify our MainActivity class.
    -. Register a local broadcast receiver so we can handle a new incoming message.
    -. Register button click listener.
    -. Set the cookie storage, so our http request will have the same session id over time.
    -. Set the adapter for our list view, so it can display the chat conversation.
public class MainActivity extends AppCompatActivity {

private EditText mUsernameEt;

private EditText mMessageEt;

private View mSendButton;

private ListView mListView;

private ChatMessageAdapter mAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAdapter = new ChatMessageAdapter(this);

setContentView(R.layout.activity_main);

prepareView();

mSendButton.setOnClickListener(sendBtnClickListener);
mListView.setAdapter(mAdapter);

// Start a service to register GCM token id to server
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);

// register the local broadcast manager
// to receive message from GCM Listener
LocalBroadcastManager.getInstance(this).registerReceiver(
new ChatReceiver(),
new IntentFilter("message"));

// set the cookie storage, so our http request will have the same sessio id
CookieManager cookieManage = new CookieManager();
CookieHandler.setDefault(cookieManage);
}

private void prepareView() {
mUsernameEt = (EditText) findViewById(R.id.username);
mMessageEt = (EditText) findViewById(R.id.message_input);
mSendButton = findViewById(R.id.send_button);
mListView = (ListView) findViewById(R.id.chat_list_container);
}

private View.OnClickListener sendBtnClickListener = new View.OnClickListener() {

@Override
public void onClick(View v) {
String from = mUsernameEt.getText().toString();
String message = mMessageEt.getText().toString();

// Send a broadcast message
RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);
requestQueue.add(new StringRequest(
Request.Method.GET,
"http://192.168.1.120:8080/AndroidChatServer/broadcast?" +
"from=" + from + "&" +
"message=" + message, null, null));
requestQueue.start();

// Add our own chat to the list
Chat chat = new Chat("You", message, true);
mAdapter.addChatList(chat);

// Scroll the list view to the bottom
mListView.setSelection(mAdapter.getCount() - 1);

// reset input text field
mMessageEt.setText("");
}
};

public class ChatReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
Chat chat = new Chat(extras.getString("from"), extras.getString("message"), false);
mAdapter.addChatList(chat);

// Scroll the list view to the bottom
mListView.setSelection(mAdapter.getCount() - 1);
}
}

}

3. Create a Chat class, that will encapsulate our chat content
public class Chat {

private String from;

private String message;

// will determine if the message is our own message
private boolean isSelf;

public Chat(String from, String message, boolean isSelf) {
this.from = from;
this.message = message;
this.isSelf = isSelf;
}

public String getFrom() {
return from;
}

public String getMessage() {
return message;
}

public boolean isSelf() {
return isSelf;
}
}

4. Create a ChatMessageAdapter class, to display a list view item

public class ChatMessageAdapter extends BaseAdapter {

private List<Chat> chatList;

private Context context;

public ChatMessageAdapter(Context context) {
this.context = context;
this.chatList = new ArrayList<>();
}

@Override
public int getCount() {
return chatList.size();
}

@Override
public Chat getItem(int position) {
return chatList.get(position);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

if(null == convertView)
convertView = LayoutInflater.from(context).inflate(R.layout.list_chat_view, parent, false);

Chat chat = getItem(position);

TextView fromTv = (TextView) convertView.findViewById(R.id.chat_from_container);
TextView messageTv = (TextView) convertView.findViewById(R.id.chat_message_container);

// Change the alignment of our own message
if(chat.isSelf()) {
fromTv.setGravity(Gravity.END);
messageTv.setGravity(Gravity.END);
} else {
fromTv.setGravity(Gravity.START);
messageTv.setGravity(Gravity.START);
}

fromTv.setText(chat.getFrom());
messageTv.setText(chat.getMessage());

return convertView;
}

@Override
public long getItemId(int position) {
return 0;
}

public void addChatList(Chat chat) {
this.chatList.add(chat);
this.notifyDataSetChanged();
}

}
5. Register a GCM Listener, an object that will be notify, when a new gcm message arrived.

public class MyGCMListenerService extends GcmListenerService {

@Override
public void onMessageReceived(String from, Bundle data) {

Intent intent = new Intent("message");
intent.putExtra("from", data.getString("sender"));
intent.putExtra("message", data.getString("message"));
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
And also don't forget to register the listener service in AndroidManifest.xml
<service
android:name=".MyGCMListenerService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>

So that's it all the code we need for android. Next we will modify our web server so that it can handle Incoming message from Android, 
then it will broadcast to all connected device.

1. Modify register servlet, so that it will saved the tokenId for each session id. 
We will use this session, to guard the broadcast message process, so that it doesn't broadcast it self (sender device).

@WebServlet(urlPatterns = "/register")
public class RegisterTokenServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

String token = req.getParameter("token");

// Add token to application scope
Set<String> tokens = (Set<String>) req.getServletContext().getAttribute("tokens");
if(tokens == null) tokens = new HashSet<>();
tokens.add(token);
req.getServletContext().setAttribute("tokens", tokens);

// Add token to current session scope
req.getSession().setAttribute("token", token);

resp.getWriter().println("Success receive token: " + token);
}

}

2. Create a new BroadcastServlet to receive incoming message and broadcast to all connected device.

@WebServlet(urlPatterns = "/broadcast")
public class BroadcastChatServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

String currentToken = (String) req.getSession().getAttribute("token");

// Get all connected device's token id
Set<String> tokens = (Set<String>) req.getServletContext().getAttribute("tokens");

// Validate so that, if no one have register
// the application not yields an error
if(tokens == null) return;

tokens.forEach(token -> {

// No need to send GCM Message to our own self
if(token.equals(currentToken)) return;

ResteasyClient client = new ResteasyClientBuilder().build();
client.register((ClientRequestFilter) request -> {
request.getHeaders().add("Content-Type", "application/json");
request.getHeaders().add("Authorization", "key=AIzaSyBUwoBTcSHP7xvFrG3cx6mwJPhj9g84A3o");
});
ResteasyWebTarget target = client.target("https://gcm-http.googleapis.com/gcm/send");

Map<String, Object> body = new HashMap<>();
Map<String, String> data = new HashMap<>();

String from = req.getParameter("from");
if(from == null || "".equals(from))
from = "Anonymous";

data.put("sender", from);
data.put("message", req.getParameter("message"));

body.put("to", token);
body.put("data", data); target.request().post(Entity.json(body));

});
}
}

That's it, pretty simple. I hope you guys understand the bold point here, and you can development your own realtime application.


Swift, A Beginner’s Guide

posted Nov 1, 2015, 11:50 PM by Justinus Hermawan Sadeli   [ updated Aug 15, 2016, 11:38 PM by Surya Wang ]


Swift Logo

Swift is a new programming language for iOS, OS X, watchOS, and tvOS apps. Swift was introduced at Apple’s Worldwide Developer Conference (WWDC) 2014 as a replacement for Objective C, Apple’s long-time programming language. At WWDC 2015, Swift 2.0 was announced with a number of improvements and changes, including Apple’s commitment to make Swift an open source language.

In this tutorial, you will learn about the beginning of Swift programming, especially about how to make a Swift command-line app as the beginning to make a full iOS app with a beautiful user interface. This will provide you with the basic knowledge you’ll need to make the amazing apps you’ve dreamed of!

Getting Started

Note: The Swift version that I used in this tutorial is Swift 2.1 and the Xcode version is Xcode 7.

The very first step is to download Xcode (the software program that you write your apps in) for free on the Mac App Store.
SS 1

Be sure you have the latest version of Xcode. You need Xcode 6 or later to work with Swift. Once you have Xcode installed, open it and click the Get started with a playground option.

SS 2

Note: If you don’t see the Welcome to Xcode window, click Window -> Welcome to Xcode to display it.

A playground is a simple way to experiment and play around with Swift code. It allows you to edit the code listings and see the result immediately.

You can’t run a playground as an iPhone app, but it will be very important in helping you to understand the basic of Swift. Don’t worry, you’ll be creating your very own iPhone app soon enough!

Set the name to MyFirstPlayground, the platform to iOS, and click Next. Save the playground wherever you wish.

SS 3
Introduction to Playgrounds

You will see that the playground you created already has three lines of code:
 // Playground - noun: a place where people can play
 
 import UIKit
 
 var str = "Hello, playground"

Here’s the breakdown of the playground, one line at a time.

 // Playground - noun: a place where people can play

The first line, which starts with two forward slashes, is called a comment.

This line is only there for you, or any other programmers that look at your code, to see. It does not affect the way that your code functions. Think of it as “a way to write notes in your code”.

 import UIKit

The second line imports UIKit, which you can think of as “a bunch of code written by the smart folks at Apple.” All you need to know about this right now is that you need it for the rest of your code to work.

 var str = "Hello, playground"

The third line is the one you should focus on right now.

This line creates a variable named str that holds the value Hello, playground. On the right side of the window, you can see that Xcode is keeping track of what this variable holds.

SS 4

Try changing “Hello, playground” to “Hello, Swift!”, like this:

 var str = "Hello, Swift!"
SS 5

Did you see how the right side of the window changed what it said too? Congratulations, you just did some Swift programming!

Playground as a Calculator

Now let’s see what else you can do in playground. At the bottom of your file, try typing a basic math expression such as 9 % 5 (9 modulo by 5) and hit enter to go to the next line:

 9 % 5

The playground will give you the answer to your equation over in the shaded right side of the window:

SS 6

Cool, yeah? You can do any other extreme math operation too.

Challenge: Quick – try to use Playgrounds to show me the result of 1234 * 5678!

Using playground as a simple calculator is great and all, but now let’s move on and get into some more coding! Delete everything in the program except for import UIKit so you have a clean state to work with.

 import UIKit

It is extremely important that you leave that line there because the Playground will not work without it.

Variables

Next, it’s time for you to play with variables. You use variables to store values. When you create a variable, you always use the following syntax:

 var variableName: variableType = initialValue

Except you substitute the following:

·  variableName: Whatever you want to name the variable, like str or age for example.

·  variableType: The type of the variable, like String or Int. More on that in a moment.

·  initialValue: Whatever you want to set the initial value of the variable to, like “Hello, Swift!” or 22.

Try an example! Add these lines to the bottom of your playground:

 var str: String = "Hello, Swift!"
 var age: Int = 22

In the first line, you created a variable named str of type String, and set the initial value to “Hello, Swift!”

In the second line, you created a variable named age of type Int, and set the initial value to 22.

You’re starting to get a good idea how to make a variable, but you may be wondering what the difference between String and Int types is, and what other data types you can use.

Data Types

Here’s a list of some of the basic data types that Swift has to offer:

·  Int – whole numbers, or integers

·  Double – decimal numbers

·  Bool – a value that can be true, or false

·  String – a “string” of letters or words

Practice using these data types. Add the following lines to the bottom of your playground:

 var currentTime: Int = 12
 var costOfBurger: Double = 20.55
 var isHungry: Bool = true
 var name: String = "Kosur"

Notice how each of the values show up on the shaded right area of the window as the playground keeps track of them. Now, try changing the value of the String name.

Add the following line to the bottom of your playground:

 name = "Komala"

This line did not require the use of var or : String because the object was already created. All you did here was change the value that it was storing.

Challenge: Your turn to give it a try. At the bottom of the file, try creating a variable to represent your favorite movie.

1-10 of 67