Added examples
Change-Id: Id952e4ade28cdab226d8daab6865c951d476e1b7
After Width: | Height: | Size: 126 B |
|
@ -0,0 +1,17 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ping(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("pong"))
|
||||||
|
}
|
||||||
|
func main() {
|
||||||
|
http.Handle("/", http.FileServer(http.Dir("../FE")))
|
||||||
|
http.HandleFunc("/ping", ping)
|
||||||
|
http.HandleFunc("/upload/", UploadFile)
|
||||||
|
if err := http.ListenAndServe(":9000", nil); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,174 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"image/png"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"math"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/disintegration/imaging"
|
||||||
|
"github.com/harrydb/go/img/grayscale"
|
||||||
|
// "github.com/nfnt/resize"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UploadFile uploads a file to the server
|
||||||
|
func UploadFile(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Printf("Inside upload \n")
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save a copy of this request for debugging.
|
||||||
|
//requestDump, err := httputil.DumpRequest(r, true)
|
||||||
|
//if err != nil {
|
||||||
|
// fmt.Println(err)
|
||||||
|
//}
|
||||||
|
|
||||||
|
//fmt.Println(string(requestDump))
|
||||||
|
|
||||||
|
file, handle, err := r.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("upload error\n")
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
fmt.Fprintf(w, "%v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
mimeType := handle.Header.Get("Content-Type")
|
||||||
|
switch mimeType {
|
||||||
|
// case "image/jpeg":
|
||||||
|
// saveFile(w, file, handle)
|
||||||
|
case "image/png":
|
||||||
|
saveFile(w, file, handle)
|
||||||
|
default:
|
||||||
|
jsonResponse(w, http.StatusBadRequest, "The format file is not valid.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func processImage(infile multipart.File) (err error) {
|
||||||
|
imgSrc, _, err := image.Decode(infile)
|
||||||
|
if err != nil {
|
||||||
|
panic(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new grayscale image
|
||||||
|
bounds := imgSrc.Bounds()
|
||||||
|
w, h := bounds.Max.X, bounds.Max.Y
|
||||||
|
grayScale := image.NewGray(image.Rectangle{image.Point{0, 0}, image.Point{w, h}})
|
||||||
|
for x := 0; x < w; x++ {
|
||||||
|
for y := 0; y < h; y++ {
|
||||||
|
imageColor := imgSrc.At(x, y)
|
||||||
|
rr, gg, bb, _ := imageColor.RGBA()
|
||||||
|
r := math.Pow(float64(rr), 2.2)
|
||||||
|
g := math.Pow(float64(gg), 2.2)
|
||||||
|
b := math.Pow(float64(bb), 2.2)
|
||||||
|
m := math.Pow(0.2125*r+0.7154*g+0.0721*b, 1/2.2)
|
||||||
|
Y := uint16(m + 0.5)
|
||||||
|
grayColor := color.Gray{uint8(Y >> 8)}
|
||||||
|
grayScale.Set(x, y, grayColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Resize image
|
||||||
|
newImg := imaging.Resize(imgSrc, 28, 28, imaging.Lanczos)
|
||||||
|
|
||||||
|
// Grayscale 2
|
||||||
|
grayImg := grayscale.Convert(newImg, grayscale.ToGrayLuminance)
|
||||||
|
threshold := grayscale.Otsu(grayImg)
|
||||||
|
grayscale.Threshold(grayImg, threshold, 0, 255)
|
||||||
|
|
||||||
|
// Encode the grayscale image to the new file
|
||||||
|
newFileName := "grayscale.png"
|
||||||
|
newfile, err := os.Create("./files/" + newFileName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("failed creating %s: %s", newfile, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//defer newfile.Close()
|
||||||
|
//png.Encode(newfile, grayScale)
|
||||||
|
png.Encode(newfile, grayImg)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveFile(w http.ResponseWriter, file multipart.File, handle *multipart.FileHeader) {
|
||||||
|
err := processImage(file)
|
||||||
|
//data, err := ioutil.ReadAll(file2)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(w, "%v", err)
|
||||||
|
fmt.Println("%v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//err = ioutil.WriteFile("./files/"+handle.Filename, data, 0666)
|
||||||
|
//if err != nil {
|
||||||
|
// fmt.Fprintf(w, "%v", err)
|
||||||
|
// return
|
||||||
|
//}
|
||||||
|
resp := predictNumber()
|
||||||
|
jsonResponse(w, http.StatusCreated, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func postFile(filename string, targetUrl string) (string, error) {
|
||||||
|
bodyBuf := &bytes.Buffer{}
|
||||||
|
bodyWriter := multipart.NewWriter(bodyBuf)
|
||||||
|
|
||||||
|
// this step is very important
|
||||||
|
fileWriter, err := bodyWriter.CreateFormFile("file", filename)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("error writing to buffer")
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// open file handle
|
||||||
|
fh, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("error opening file")
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer fh.Close()
|
||||||
|
|
||||||
|
//iocopy
|
||||||
|
_, err = io.Copy(fileWriter, fh)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
contentType := bodyWriter.FormDataContentType()
|
||||||
|
bodyWriter.Close()
|
||||||
|
|
||||||
|
resp, err := http.Post(targetUrl, contentType, bodyBuf)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
resp_body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
fmt.Println(resp.Status)
|
||||||
|
fmt.Println(string(resp_body))
|
||||||
|
return string(resp_body), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func predictNumber() string {
|
||||||
|
target_url := "http://localhost:5000/mnist/classify"
|
||||||
|
filename := "./files/grayscale.png"
|
||||||
|
resp, _ := postFile(filename, target_url)
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func jsonResponse(w http.ResponseWriter, code int, message string) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(code)
|
||||||
|
fmt.Fprint(w, message)
|
||||||
|
}
|
|
@ -0,0 +1,170 @@
|
||||||
|
var mousePressed = false;
|
||||||
|
var lastX, lastY;
|
||||||
|
var ctx, ctx2;
|
||||||
|
|
||||||
|
function InitThis() {
|
||||||
|
ctx = document.getElementById('myCanvas').getContext("2d");
|
||||||
|
ctx2 = document.getElementById('myCanvas2').getContext("2d");
|
||||||
|
|
||||||
|
$('#myCanvas').mousedown(function (e) {
|
||||||
|
mousePressed = true;
|
||||||
|
Draw(e.pageX - $(this).offset().left, e.pageY - $(this).offset().top, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#clear-area').mousedown(function (e) {
|
||||||
|
clearArea();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#upload-area').mousedown(function (e) {
|
||||||
|
//uploadArea2();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#myCanvas').mousemove(function (e) {
|
||||||
|
if (mousePressed) {
|
||||||
|
Draw(e.pageX - $(this).offset().left, e.pageY - $(this).offset().top, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#myCanvas').mouseup(function (e) {
|
||||||
|
mousePressed = false;
|
||||||
|
//alert("mouseup")
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#myCanvas').mouseleave(function (e) {
|
||||||
|
mousePressed = false;
|
||||||
|
//alert("mouseleave")
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('touchstart',function(e){ mapTouchEvents(e,'mousedown'); },true);
|
||||||
|
document.addEventListener('touchmove',function(e){ mapTouchEvents(e,'mousemove'); },true);
|
||||||
|
document.addEventListener('touchend',function(e){ mapTouchEvents(e,'mouseup'); },true);
|
||||||
|
document.addEventListener('touchcancel',function(e){ mapTouchEvents(e,'mouseup'); },true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function uploadArea() {
|
||||||
|
alert('Inside Upload....');
|
||||||
|
console.log("Inside Upload....");
|
||||||
|
var image = document.getElementById("myCanvas").toDataURL("image/png").replace("image/png", "image/octet-stream");
|
||||||
|
var data = new FormData();
|
||||||
|
data["file"] = image;
|
||||||
|
console.log(data);
|
||||||
|
$.ajax({
|
||||||
|
url: 'http://localhost:9000/upload/',
|
||||||
|
type: 'POST',
|
||||||
|
data: data,
|
||||||
|
cache: false,
|
||||||
|
dataType: 'json',
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
success: function( data , textStatus , jqXHR )
|
||||||
|
{
|
||||||
|
if( typeof data.error === 'undefined' ) {
|
||||||
|
submitForm( event, data );
|
||||||
|
} else {
|
||||||
|
alert( 'ERRORS: ' + data.error );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(jqXHR, textStatus, errorThrown) { alert( 'error on upload' ); }
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDstImage(data) {
|
||||||
|
console.log("Entering into getDstImage")
|
||||||
|
var fname = "./img/"
|
||||||
|
switch(data["classification"]) {
|
||||||
|
case 1:
|
||||||
|
return fname+"1.jpg"
|
||||||
|
case 2:
|
||||||
|
return fname+"2.png"
|
||||||
|
case 3:
|
||||||
|
return fname+"3.png"
|
||||||
|
case 4:
|
||||||
|
return fname+"4.jpg"
|
||||||
|
case 5:
|
||||||
|
return fname+"5.png"
|
||||||
|
case 6:
|
||||||
|
return fname+"6.jpg"
|
||||||
|
case 7:
|
||||||
|
return fname+"7.png"
|
||||||
|
case 8:
|
||||||
|
return fname+"8.png"
|
||||||
|
case 9:
|
||||||
|
return fname+"9.png"
|
||||||
|
default:
|
||||||
|
return "error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function uploadArea2() {
|
||||||
|
var canvas = document.getElementById("myCanvas")
|
||||||
|
canvas.toBlob(
|
||||||
|
function (blob) {
|
||||||
|
// Do something with the blob object,
|
||||||
|
// e.g. creating a multipart form for file uploads:
|
||||||
|
var formData = new FormData();
|
||||||
|
formData.append('file', blob, "predict.png");
|
||||||
|
$.ajax({
|
||||||
|
url: 'http://localhost:9000/upload/',
|
||||||
|
type: 'POST',
|
||||||
|
data: formData,
|
||||||
|
cache: false,
|
||||||
|
dataType: 'json',
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
success: function( data , textStatus , jqXHR )
|
||||||
|
{
|
||||||
|
if( typeof data.error === 'undefined' ) {
|
||||||
|
//submitForm( event, data );
|
||||||
|
} else {
|
||||||
|
alert( 'ERRORS: ' + data.error );
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Inside success of uploadArea2")
|
||||||
|
|
||||||
|
var canvas = document.getElementById("myCanvas2");
|
||||||
|
var ctx = canvas.getContext("2d");
|
||||||
|
var image = new Image();
|
||||||
|
image.src = getDstImage(data);
|
||||||
|
image.onload = function() {
|
||||||
|
ctx.drawImage(image, 0, 0);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
error: function(jqXHR, textStatus, errorThrown) { alert( 'error on upload2' ); alert(textStatus);}
|
||||||
|
|
||||||
|
});
|
||||||
|
/* ... */
|
||||||
|
},
|
||||||
|
'image/png'
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function Draw(x, y, isDown) {
|
||||||
|
if (isDown) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.strokeStyle = $('#selColor').val();
|
||||||
|
// ctx.lineWidth = $('#selWidth').val();
|
||||||
|
ctx.lineWidth = 9;
|
||||||
|
ctx.lineJoin = "round";
|
||||||
|
ctx.moveTo(lastX, lastY);
|
||||||
|
ctx.lineTo(x, y);
|
||||||
|
ctx.closePath();
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
lastX = x;
|
||||||
|
lastY = y;
|
||||||
|
|
||||||
|
//alert("Drawing done....");
|
||||||
|
//console.log("Drawing done.....");
|
||||||
|
//doUpload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearArea() {
|
||||||
|
// Use the identity matrix while clearing the canvas
|
||||||
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||||
|
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||||
|
ctx2.setTransform(1, 0, 0, 1, 0, 0);
|
||||||
|
ctx2.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
!function(t){"use strict";var e=t.HTMLCanvasElement&&t.HTMLCanvasElement.prototype,o=t.Blob&&function(){try{return Boolean(new Blob)}catch(t){return!1}}(),n=o&&t.Uint8Array&&function(){try{return 100===new Blob([new Uint8Array(100)]).size}catch(t){return!1}}(),r=t.BlobBuilder||t.WebKitBlobBuilder||t.MozBlobBuilder||t.MSBlobBuilder,a=/^data:((.*?)(;charset=.*?)?)(;base64)?,/,i=(o||r)&&t.atob&&t.ArrayBuffer&&t.Uint8Array&&function(t){var e,i,l,u,c,f,b,d,B;if(!(e=t.match(a)))throw new Error("invalid data URI");for(i=e[2]?e[1]:"text/plain"+(e[3]||";charset=US-ASCII"),l=!!e[4],u=t.slice(e[0].length),c=l?atob(u):decodeURIComponent(u),f=new ArrayBuffer(c.length),b=new Uint8Array(f),d=0;d<c.length;d+=1)b[d]=c.charCodeAt(d);return o?new Blob([n?b:f],{type:i}):((B=new r).append(f),B.getBlob(i))};t.HTMLCanvasElement&&!e.toBlob&&(e.mozGetAsFile?e.toBlob=function(t,o,n){var r=this;setTimeout(function(){t(n&&e.toDataURL&&i?i(r.toDataURL(o,n)):r.mozGetAsFile("blob",o))})}:e.toDataURL&&i&&(e.toBlob=function(t,e,o){var n=this;setTimeout(function(){t(i(n.toDataURL(e,o)))})})),"function"==typeof define&&define.amd?define(function(){return i}):"object"==typeof module&&module.exports?module.exports=i:t.dataURLtoBlob=i}(window);
|
||||||
|
//# sourceMappingURL=canvas-to-blob.min.js.map
|
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 38 KiB |
|
@ -0,0 +1,64 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
|
<!-- meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no" -->
|
||||||
|
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
|
||||||
|
<script type="text/javascript" src="map-touch-events.js"></script>
|
||||||
|
<script type="text/javascript" src="canvas-to-blob.min.js"></script>
|
||||||
|
<script type="text/javascript" src="JsCode.js"></script>
|
||||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
|
||||||
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
||||||
|
<style>
|
||||||
|
img{
|
||||||
|
max-width:100%
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body onload="InitThis();">
|
||||||
|
<div class="container">
|
||||||
|
<div class="jumbotron">
|
||||||
|
<center> <h1>Know Thy Numbers....</h1></center>
|
||||||
|
<p></p>
|
||||||
|
<center>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><img src="img/me_gopher.png"><br /><br /> <center><button id="clear-area" onclick="javascript:clearArea();return false;">Clear Area</button>
|
||||||
|
<br /> <button id="upload-area" onclick="javascript:uploadArea2()">Predict</button></center></td>
|
||||||
|
<td>
|
||||||
|
<table>
|
||||||
|
<tr><th><center>Draw Here</center></th><th><center>Did you drew this...?</center></th></tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div id="input">
|
||||||
|
<canvas id="myCanvas" width="150" height="350" style="border:2px solid black"></canvas>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div id="prediction">
|
||||||
|
<canvas id="myCanvas2" width="150" height="350" style="border:2px solid black"></canvas>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td></tr></table>
|
||||||
|
<br /><br />
|
||||||
|
<!-- button onclick="javascript:clearArea();return false;">Clear Area</button -->
|
||||||
|
<!-- button id="clear-area">Clear Area</button -->
|
||||||
|
<!-- button id="upload-area" onclick="javascript:doUpload();return false;">Predict</button -->
|
||||||
|
<!-- td -->
|
||||||
|
<br /><br />
|
||||||
|
Color : <select id="selColor" class="form-control">
|
||||||
|
<option value="black">black</option>
|
||||||
|
<option value="blue" selected="selected">blue</option>
|
||||||
|
<option value="red">red</option>
|
||||||
|
<option value="green">green</option>
|
||||||
|
<option value="yellow">yellow</option>
|
||||||
|
<option value="gray">gray</option>
|
||||||
|
</select>
|
||||||
|
</center>
|
||||||
|
</div></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,36 @@
|
||||||
|
function mapTouchEvents(event,simulatedType) {
|
||||||
|
|
||||||
|
//Ignore any mapping if more than 1 fingers touching
|
||||||
|
if(event.changedTouches.length>1){return;}
|
||||||
|
|
||||||
|
var touch = event.changedTouches[0];
|
||||||
|
|
||||||
|
//--https://developer.mozilla.org/en/DOM/document.createEvent--
|
||||||
|
eventToSimulate = document.createEvent('MouseEvent');
|
||||||
|
|
||||||
|
//--https://developer.mozilla.org/en-US/docs/Web/API/event.initMouseEvent--
|
||||||
|
eventToSimulate.initMouseEvent(
|
||||||
|
simulatedType, //type
|
||||||
|
true, //bubbles
|
||||||
|
true, //cancelable
|
||||||
|
window, //view
|
||||||
|
1, //detail
|
||||||
|
touch.screenX, //screenX
|
||||||
|
touch.screenY, //screenY
|
||||||
|
touch.clientX, //clientX
|
||||||
|
touch.clientY, //clientY
|
||||||
|
false, //ctrlKey
|
||||||
|
false, //altKey
|
||||||
|
false, //shiftKey
|
||||||
|
false, //metaKey
|
||||||
|
0, //button
|
||||||
|
null //relatedTarget
|
||||||
|
);
|
||||||
|
|
||||||
|
touch.target.dispatchEvent(eventToSimulate);
|
||||||
|
//This ignores the default scroll behavior
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 Viswanath Kumar Skand Priya
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,2 @@
|
||||||
|
# KnowThyNumber
|
||||||
|
A Test ( mobile ) WebApp to show the power of Openstack Gyan
|