first commit
This commit is contained in:
commit
b2502bd29e
19 files changed
+556
No files matched your search
+24
@@ -0,0 +1,24 @@
|
|||||||
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Folders
|
||||||
|
_obj
|
||||||
|
_test
|
||||||
|
|
||||||
|
# Architecture specific extensions/prefixes
|
||||||
|
*.[568vq]
|
||||||
|
[568vq].out
|
||||||
|
|
||||||
|
*.cgo1.go
|
||||||
|
*.cgo2.c
|
||||||
|
_cgo_defun.c
|
||||||
|
_cgo_gotypes.go
|
||||||
|
_cgo_export.*
|
||||||
|
|
||||||
|
_testmain.go
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
*.test
|
||||||
|
*.prof
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 didier amyot
|
||||||
|
|
||||||
|
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,94 @@
|
|||||||
|
package data
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/gorilla/securecookie"
|
||||||
|
"github.com/influxdb/influxdb/client"
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
)
|
||||||
|
|
||||||
|
var hashKey = []byte("0ea20ffa64fb127136be5bb9fb0814289267f6d162c81f06af237a09e375d182bada41b9ba14eb4d34f73c9c8b792fc0")
|
||||||
|
var s = securecookie.New(hashKey, nil)
|
||||||
|
|
||||||
|
type Data struct {
|
||||||
|
IncluxDB *client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Data) CreateUserId(w http.ResponseWriter) bson.ObjectId {
|
||||||
|
id := bson.NewObjectId()
|
||||||
|
|
||||||
|
if encoded, err := s.Encode("onepixel", map[string]string{"id": id.Hex()}); err == nil {
|
||||||
|
cookie := &http.Cookie{
|
||||||
|
Name: "onepixel",
|
||||||
|
Value: encoded,
|
||||||
|
Path: "/",
|
||||||
|
}
|
||||||
|
http.SetCookie(w, cookie)
|
||||||
|
} else {
|
||||||
|
log.Println("cannot encrypt uuid")
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Data) GetUserIdInCookie(r *http.Request) bson.ObjectId {
|
||||||
|
if cookie, err := r.Cookie("onepixel"); err == nil {
|
||||||
|
value := make(map[string]string)
|
||||||
|
if err = s.Decode("onepixel", cookie.Value, &value); err == nil {
|
||||||
|
if bson.IsObjectIdHex(value["id"]) {
|
||||||
|
return bson.ObjectIdHex(value["id"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Data) GetAndSetId(w http.ResponseWriter, request *http.Request) bson.ObjectId {
|
||||||
|
if id := d.GetUserIdInCookie(request); id.Valid() {
|
||||||
|
return id
|
||||||
|
} else {
|
||||||
|
return d.CreateUserId(w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Data) ServeHTTP(w http.ResponseWriter, request *http.Request) {
|
||||||
|
vars := mux.Vars(request)
|
||||||
|
|
||||||
|
ip, _, _ := net.SplitHostPort(request.RemoteAddr)
|
||||||
|
|
||||||
|
userAgent := request.UserAgent()
|
||||||
|
useId := d.GetAndSetId(w, request)
|
||||||
|
url := vars["url"]
|
||||||
|
serieName := vars["serie_name"]
|
||||||
|
|
||||||
|
d.AddDataPoint(serieName, url, userAgent, ip, useId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Data) CreateSeries(serieName, url, userAgent, ip string, userId bson.ObjectId) []*client.Series {
|
||||||
|
series := &client.Series{
|
||||||
|
Name: serieName,
|
||||||
|
Columns: []string{"url", "user_id", "user_agent", "ip"},
|
||||||
|
Points: [][]interface{}{
|
||||||
|
{url, userId, userAgent, ip},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return []*client.Series{series}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Data) AddDataPoint(serieName, url, userAgent, ip string, userId bson.ObjectId) {
|
||||||
|
fmt.Println("serieName :", serieName)
|
||||||
|
fmt.Println("url :", url)
|
||||||
|
fmt.Println("id :", userId.Hex())
|
||||||
|
fmt.Println("userAgent :", userAgent)
|
||||||
|
fmt.Println("")
|
||||||
|
|
||||||
|
series := d.CreateSeries(serieName, url, userAgent, ip, userId)
|
||||||
|
if err := d.IncluxDB.WriteSeries(series); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package data
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MockResponseWriter struct {
|
||||||
|
header http.Header
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMockResponseWriter() http.ResponseWriter {
|
||||||
|
var header http.Header = make(map[string][]string)
|
||||||
|
return &MockResponseWriter{header}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockResponseWriter) Header() http.Header {
|
||||||
|
return m.header
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockResponseWriter) Write(b []byte) (int, error) {
|
||||||
|
return 500, errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockResponseWriter) WriteHeader(c int) {}
|
||||||
|
|
||||||
|
func TestSecureCookie(t *testing.T) {
|
||||||
|
w := NewMockResponseWriter()
|
||||||
|
d := new(Data)
|
||||||
|
|
||||||
|
uuid := d.CreateUserId(w)
|
||||||
|
|
||||||
|
if !uuid.Valid() {
|
||||||
|
t.Error("invalid uuid")
|
||||||
|
}
|
||||||
|
|
||||||
|
if w.Header().Get("Set-Cookie") == "" {
|
||||||
|
t.Error("nothing in set in the cookie")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
package data
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/didiercrunch/onepixel/data"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
const STATIC_DIR_PATH = "static/"
|
||||||
|
|
||||||
|
func serveStatic(router *mux.Router) {
|
||||||
|
handler := func(w http.ResponseWriter, request *http.Request) {
|
||||||
|
vars := mux.Vars(request)
|
||||||
|
filepath := "/" + vars["path"]
|
||||||
|
w.Header().Set("Cache-Control", "public, max-age=43200")
|
||||||
|
http.ServeFile(w, request, path.Join(STATIC_DIR_PATH, filepath))
|
||||||
|
}
|
||||||
|
router.HandleFunc("/{path:.*}", handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func serveApi(router *mux.Router, apiHandler http.Handler) {
|
||||||
|
router.Handle("/api/{serie_name}/{url:.*}", apiHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createMuxRouter() http.Handler {
|
||||||
|
r := mux.NewRouter()
|
||||||
|
serveApi(r, &data.Data{params.InfluxDBClient})
|
||||||
|
serveStatic(r.PathPrefix("/").Subrouter())
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
r := createMuxRouter()
|
||||||
|
http.Handle("/", r)
|
||||||
|
address := params.Host + ":" + strconv.Itoa(params.Port)
|
||||||
|
if err := http.ListenAndServe(address, createMuxRouter()); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"github.com/influxdb/influxdb/client"
|
||||||
|
|
||||||
|
goyaml "gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const PARAM_FILE string = "params.yml"
|
||||||
|
|
||||||
|
type Params struct {
|
||||||
|
Port int `yaml:"port,omitempty"`
|
||||||
|
Host string `yaml:"host,omitempty"`
|
||||||
|
InfluxDBClientConfig *client.ClientConfig `yaml:"influxdb,omitempty"`
|
||||||
|
InfluxDBClient *client.Client `yaml:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Params) LoadFromYamlFile(fileName string) error {
|
||||||
|
data, err := ioutil.ReadFile(fileName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return this.LoadFromYamlData(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Params) LoadFromYamlData(data []byte) error {
|
||||||
|
var err error
|
||||||
|
p := new(Params)
|
||||||
|
if err = goyaml.Unmarshal(data, p); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Host != "" {
|
||||||
|
this.Host = p.Host
|
||||||
|
}
|
||||||
|
if p.Port > 0 {
|
||||||
|
this.Port = p.Port
|
||||||
|
}
|
||||||
|
if p.InfluxDBClientConfig == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if p.InfluxDBClientConfig.Host != "" {
|
||||||
|
this.InfluxDBClientConfig.Host = p.InfluxDBClientConfig.Host
|
||||||
|
}
|
||||||
|
if p.InfluxDBClientConfig.Database != "" {
|
||||||
|
this.InfluxDBClientConfig.Database = p.InfluxDBClientConfig.Database
|
||||||
|
}
|
||||||
|
if p.InfluxDBClientConfig.Password != "" {
|
||||||
|
this.InfluxDBClientConfig.Password = p.InfluxDBClientConfig.Password
|
||||||
|
}
|
||||||
|
if p.InfluxDBClientConfig.Username != "" {
|
||||||
|
this.InfluxDBClientConfig.Username = p.InfluxDBClientConfig.Username
|
||||||
|
}
|
||||||
|
this.InfluxDBClientConfig.IsSecure = p.InfluxDBClientConfig.IsSecure
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Params) initInfluxDB() error {
|
||||||
|
var err error
|
||||||
|
this.InfluxDBClient, err = client.NewClient(this.InfluxDBClientConfig)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDefaultParams() *Params {
|
||||||
|
influxdbClientConfig := &client.ClientConfig{}
|
||||||
|
return &Params{7777, "localhost", influxdbClientConfig, nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
var params = GetDefaultParams()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if err := params.LoadFromYamlFile(PARAM_FILE); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := params.initInfluxDB(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
# This is onepixel params' file. The file is in yaml format. The file
|
||||||
|
# should be auto-documented
|
||||||
|
|
||||||
|
|
||||||
|
# the port where the onepixel web site will run
|
||||||
|
port: 6900
|
||||||
|
|
||||||
|
# the host name. 0.0.0.0 to share the service with everyone on the network.
|
||||||
|
# localhost for running on localhost without the possibility to share the
|
||||||
|
# service
|
||||||
|
host: 0.0.0.0 #localhost
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# all the params relative to inflixdb
|
||||||
|
influxdb:
|
||||||
|
host: ~
|
||||||
|
username: root
|
||||||
|
password: root
|
||||||
|
database: onepixel
|
||||||
|
issecure: yes
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
const yaml_params = `
|
||||||
|
---
|
||||||
|
|
||||||
|
port: 9999
|
||||||
|
|
||||||
|
host: 0.0.0.0 #localhost
|
||||||
|
|
||||||
|
# all the params relative to mongodb
|
||||||
|
influxdb:
|
||||||
|
host: "bigtits.com"
|
||||||
|
username: "alice"
|
||||||
|
password: "qwerty"
|
||||||
|
database: "tits"
|
||||||
|
issecure: yes
|
||||||
|
`
|
||||||
|
|
||||||
|
func TestLoadFromYamlData(t *testing.T) {
|
||||||
|
p := GetDefaultParams()
|
||||||
|
if err := p.LoadFromYamlData([]byte(yaml_params)); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if p.Port != 9999 {
|
||||||
|
t.Error("port")
|
||||||
|
}
|
||||||
|
if p.Host != "0.0.0.0" {
|
||||||
|
t.Error("host")
|
||||||
|
}
|
||||||
|
if p.InfluxDBClientConfig.Host != "bigtits.com" {
|
||||||
|
t.Error("InfluxDBClientConfig.Host", p.InfluxDBClientConfig.Host, " fuck")
|
||||||
|
}
|
||||||
|
if p.InfluxDBClientConfig.Database != "tits" {
|
||||||
|
t.Error("InfluxDBClientConfig.Database")
|
||||||
|
}
|
||||||
|
if !p.InfluxDBClientConfig.IsSecure {
|
||||||
|
t.Error("InfluxDBClientConfig.IsSecure")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
define [
|
||||||
|
"angular"
|
||||||
|
"filters"
|
||||||
|
"services"
|
||||||
|
"directives"
|
||||||
|
"controllers"
|
||||||
|
"angularRoute"
|
||||||
|
], (angular, filters, services, directives, controllers) ->
|
||||||
|
|
||||||
|
# Declare app level module which depends on filters, and services
|
||||||
|
angular.module "myApp", [
|
||||||
|
"ngRoute"
|
||||||
|
"myApp.filters"
|
||||||
|
"myApp.services"
|
||||||
|
"myApp.directives"
|
||||||
|
"myApp.controllers"
|
||||||
|
]
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
define [], ->
|
||||||
|
[
|
||||||
|
"$scope"
|
||||||
|
"$http"
|
||||||
|
($scope, $http) ->
|
||||||
|
|
||||||
|
# You can access the scope of the controller from here
|
||||||
|
$scope.welcomeMessage = "hey this is myctrl2.js!"
|
||||||
|
|
||||||
|
# because this has happened asynchroneusly we've missed
|
||||||
|
# Angular's initial call to $apply after the controller has been loaded
|
||||||
|
# hence we need to explicityly call it at the end of our Controller constructor
|
||||||
|
$scope.$apply()
|
||||||
|
]
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
define [
|
||||||
|
"angular"
|
||||||
|
"services"
|
||||||
|
], (angular, services) ->
|
||||||
|
|
||||||
|
# Directives
|
||||||
|
angular.module("myApp.directives", ["myApp.services"]).directive "appVersion", [
|
||||||
|
"version"
|
||||||
|
(version) ->
|
||||||
|
return (scope, elm, attrs) ->
|
||||||
|
elm.text version
|
||||||
|
return
|
||||||
|
]
|
||||||
|
return
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
require.config
|
||||||
|
paths:
|
||||||
|
angular: "../bower_components/angular/angular"
|
||||||
|
angularRoute: "../bower_components/angular-route/angular-route"
|
||||||
|
angularMocks: "../bower_components/angular-mocks/angular-mocks"
|
||||||
|
text: "../bower_components/requirejs-text/text"
|
||||||
|
|
||||||
|
shim:
|
||||||
|
angular:
|
||||||
|
exports: "angular"
|
||||||
|
|
||||||
|
angularRoute: ["angular"]
|
||||||
|
angularMocks:
|
||||||
|
deps: ["angular"]
|
||||||
|
exports: "angular.mock"
|
||||||
|
|
||||||
|
priority: ["angular"]
|
||||||
|
|
||||||
|
|
||||||
|
#http://code.angularjs.org/1.2.1/docs/guide/bootstrap#overview_deferred-bootstrap
|
||||||
|
window.name = "NG_DEFER_BOOTSTRAP!"
|
||||||
|
require [
|
||||||
|
"angular"
|
||||||
|
"app"
|
||||||
|
"routes"
|
||||||
|
], (angular, app, routes) ->
|
||||||
|
$html = angular.element(document.getElementsByTagName("html")[0])
|
||||||
|
angular.element().ready ->
|
||||||
|
angular.resumeBootstrap [app["name"]]
|
||||||
|
return
|
||||||
|
|
||||||
|
return
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
define [
|
||||||
|
"angular"
|
||||||
|
"app"
|
||||||
|
], (angular, app) ->
|
||||||
|
app.config [
|
||||||
|
"$routeProvider"
|
||||||
|
($routeProvider) ->
|
||||||
|
$routeProvider.when "/view1",
|
||||||
|
templateUrl: "app/partials/partial1.html"
|
||||||
|
controller: "MyCtrl1"
|
||||||
|
|
||||||
|
$routeProvider.when "/view2",
|
||||||
|
templateUrl: "app/partials/partial2.html"
|
||||||
|
controller: "MyCtrl2"
|
||||||
|
|
||||||
|
$routeProvider.otherwise redirectTo: "/view1"
|
||||||
|
]
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
define ["angular"], (angular) ->
|
||||||
|
|
||||||
|
# Services
|
||||||
|
|
||||||
|
# Demonstrate how to register services
|
||||||
|
# In this case it is a simple value service.
|
||||||
|
angular.module("myApp.services", []).value "version", "0.1"
|
||||||
|
return
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
var bower = require('gulp-bower');
|
||||||
|
var gulp = require('gulp');
|
||||||
|
var coffee = require('gulp-coffee');
|
||||||
|
var help = require('gulp-task-listing');
|
||||||
|
var clean = require('gulp-clean');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
gulp.task('help', help);
|
||||||
|
|
||||||
|
gulp.task('bower', function() {
|
||||||
|
return bower()
|
||||||
|
.pipe(gulp.dest('bower_components/'))
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('coffee', function() {
|
||||||
|
gulp.src('app/coffee/**/*.coffee')
|
||||||
|
.pipe(coffee({bare: true}))
|
||||||
|
.pipe(gulp.dest('./app/js/'))
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('clean', function(){
|
||||||
|
return gulp.src(["js/", "bower_components/"], {read: false})
|
||||||
|
.pipe(clean())
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
gulp.task('default', ['bower', 'coffee']);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
gulp.task('dev', ['bower', 'coffee'], function(){
|
||||||
|
gulp.watch('coffee/**/*.coffee', ['coffee']);
|
||||||
|
});
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<!--[if lt IE 7]> <html lang="en" ng-app="myApp" class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
|
||||||
|
<!--[if IE 7]> <html lang="en" ng-app="myApp" class="no-js lt-ie9 lt-ie8"> <![endif]-->
|
||||||
|
<!--[if IE 8]> <html lang="en" ng-app="myApp" class="no-js lt-ie9"> <![endif]-->
|
||||||
|
<!--[if gt IE 8]><!--> <html lang="en" ng-app="myApp" class="no-js"> <!--<![endif]-->
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<title>Angular-RequireJS sample app</title>
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="stylesheet" href="app/bower_components/html5-boilerplate/css/normalize.css">
|
||||||
|
<link rel="stylesheet" href="app/bower_components/html5-boilerplate/css/main.css">
|
||||||
|
<link rel="stylesheet" href="app/css/app.css"/>
|
||||||
|
<script src="app/bower_components/html5-boilerplate/js/vendor/modernizr-2.6.2.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>AngularJS + RequireJS</h1>
|
||||||
|
<ul class="menu">
|
||||||
|
<li><a href="#/view1">view1</a></li>
|
||||||
|
<li><a href="#/view2">view2</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!--[if lt IE 7]>
|
||||||
|
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
||||||
|
<![endif]-->
|
||||||
|
|
||||||
|
<div ng-view></div>
|
||||||
|
|
||||||
|
<div>AngularJS + RequireJS seed app: v<span app-version></span></div>
|
||||||
|
<script data-main="app/js/main" src="app/bower_components/requirejs/require.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"gulp-task-listing": "~0.3.0",
|
||||||
|
"gulp-clean": "~0.3.1",
|
||||||
|
"gulp-coffee": "~2.2.0",
|
||||||
|
"gulp": "~3.8.9",
|
||||||
|
"gulp-bower": "0.0.7"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user