├── relx
├── apps
├── web
│ ├── priv
│ │ ├── static
│ │ │ ├── appstore
│ │ │ │ ├── feed.less
│ │ │ │ ├── carousel.less
│ │ │ │ ├── appstore.less
│ │ │ │ ├── buttons.less
│ │ │ │ ├── navs.less
│ │ │ │ ├── variables.less
│ │ │ │ ├── account.less
│ │ │ │ ├── common.less
│ │ │ │ └── products.less
│ │ │ ├── channel.html
│ │ │ ├── img
│ │ │ │ ├── p1.jpg
│ │ │ │ ├── p2.jpg
│ │ │ │ ├── crashsite.jpg
│ │ │ │ ├── infinity.png
│ │ │ │ ├── crysis3-bg1.png
│ │ │ │ ├── crysis3-bg2.png
│ │ │ │ ├── squad_jumping.jpg
│ │ │ │ ├── theme
│ │ │ │ │ ├── lghtmesh.png
│ │ │ │ │ └── 45degreee_fabric.png
│ │ │ │ ├── glyphicons-halflings.png
│ │ │ │ ├── bootstrap-mdo-sfmoma-01.jpg
│ │ │ │ ├── bootstrap-mdo-sfmoma-02.jpg
│ │ │ │ ├── bootstrap-mdo-sfmoma-03.jpg
│ │ │ │ ├── glyphicons-halflings-white.png
│ │ │ │ ├── facebook.svg
│ │ │ │ ├── twitter.svg
│ │ │ │ └── google.svg
│ │ │ ├── js
│ │ │ │ ├── all.min.js
│ │ │ │ ├── holder.js
│ │ │ │ └── bootstrap.min.js
│ │ │ └── css
│ │ │ │ └── theme.css
│ │ └── templates
│ │ │ ├── prod.dtl
│ │ │ ├── hd.dtl
│ │ │ ├── tl.dtl
│ │ │ ├── dev.dtl
│ │ │ └── login.dtl
│ ├── src
│ │ ├── web_app.erl
│ │ ├── web.app.src
│ │ ├── login.erl
│ │ ├── dashboard.erl
│ │ ├── routes.erl
│ │ ├── web_sup.erl
│ │ ├── element_carousel.erl
│ │ ├── reviews.erl
│ │ ├── index.erl
│ │ ├── chat.erl
│ │ ├── account.erl
│ │ ├── products.erl
│ │ ├── feed.erl
│ │ └── product.erl
│ ├── rebar.config
│ └── include
│ │ ├── records.hrl
│ │ └── wf.hrl
└── rebar.config
├── rels
└── web
│ ├── files
│ ├── vm.args
│ ├── sys.config
│ ├── erl
│ ├── start_erl.cmd
│ ├── install_upgrade.escript
│ ├── node.cmd
│ ├── nodetool
│ └── node
│ └── reltool.config
├── less.sh
├── Makefile
├── .gitignore
├── orderapps.erl
├── README.md
├── rebar.config
├── javascript.sh
└── otp.mk
/relx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erpuno/skyline/HEAD/relx
--------------------------------------------------------------------------------
/apps/web/priv/static/appstore/feed.less:
--------------------------------------------------------------------------------
1 | .entry-type-tabs {
2 | }
--------------------------------------------------------------------------------
/apps/web/priv/static/channel.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/web/priv/static/img/p1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erpuno/skyline/HEAD/apps/web/priv/static/img/p1.jpg
--------------------------------------------------------------------------------
/apps/web/priv/static/img/p2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erpuno/skyline/HEAD/apps/web/priv/static/img/p2.jpg
--------------------------------------------------------------------------------
/apps/web/priv/static/appstore/carousel.less:
--------------------------------------------------------------------------------
1 | .carousel-inner .item img{
2 | margin:0 auto;
3 | width:100%;
4 | }
--------------------------------------------------------------------------------
/apps/rebar.config:
--------------------------------------------------------------------------------
1 | {sub_dirs, [
2 | "web"
3 | ]}.
4 | {lib_dirs, ["../apps"]}.
5 | {deps_dir, ["../deps"]}.
6 |
--------------------------------------------------------------------------------
/apps/web/priv/static/img/crashsite.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erpuno/skyline/HEAD/apps/web/priv/static/img/crashsite.jpg
--------------------------------------------------------------------------------
/apps/web/priv/static/img/infinity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erpuno/skyline/HEAD/apps/web/priv/static/img/infinity.png
--------------------------------------------------------------------------------
/apps/web/priv/static/img/crysis3-bg1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erpuno/skyline/HEAD/apps/web/priv/static/img/crysis3-bg1.png
--------------------------------------------------------------------------------
/apps/web/priv/static/img/crysis3-bg2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erpuno/skyline/HEAD/apps/web/priv/static/img/crysis3-bg2.png
--------------------------------------------------------------------------------
/apps/web/priv/static/img/squad_jumping.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erpuno/skyline/HEAD/apps/web/priv/static/img/squad_jumping.jpg
--------------------------------------------------------------------------------
/apps/web/priv/static/img/theme/lghtmesh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erpuno/skyline/HEAD/apps/web/priv/static/img/theme/lghtmesh.png
--------------------------------------------------------------------------------
/apps/web/priv/static/img/glyphicons-halflings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erpuno/skyline/HEAD/apps/web/priv/static/img/glyphicons-halflings.png
--------------------------------------------------------------------------------
/apps/web/priv/static/img/theme/45degreee_fabric.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erpuno/skyline/HEAD/apps/web/priv/static/img/theme/45degreee_fabric.png
--------------------------------------------------------------------------------
/rels/web/files/vm.args:
--------------------------------------------------------------------------------
1 | -sname skyline
2 | -setcookie node_runner
3 | +K true
4 | +A 5
5 | -env ERL_MAX_PORTS 4096
6 | -env ERL_FULLSWEEP_AFTER 10
7 |
--------------------------------------------------------------------------------
/apps/web/priv/static/img/bootstrap-mdo-sfmoma-01.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erpuno/skyline/HEAD/apps/web/priv/static/img/bootstrap-mdo-sfmoma-01.jpg
--------------------------------------------------------------------------------
/apps/web/priv/static/img/bootstrap-mdo-sfmoma-02.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erpuno/skyline/HEAD/apps/web/priv/static/img/bootstrap-mdo-sfmoma-02.jpg
--------------------------------------------------------------------------------
/apps/web/priv/static/img/bootstrap-mdo-sfmoma-03.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erpuno/skyline/HEAD/apps/web/priv/static/img/bootstrap-mdo-sfmoma-03.jpg
--------------------------------------------------------------------------------
/apps/web/priv/static/img/glyphicons-halflings-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/erpuno/skyline/HEAD/apps/web/priv/static/img/glyphicons-halflings-white.png
--------------------------------------------------------------------------------
/apps/web/src/web_app.erl:
--------------------------------------------------------------------------------
1 | -module(web_app).
2 | -behaviour(application).
3 | -export([start/2, stop/1]).
4 |
5 | start(_StartType, _StartArgs) -> web_sup:start_link().
6 | stop(_State) ->ok.
7 |
--------------------------------------------------------------------------------
/less.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | APPSTORE=apps/web/priv/static/appstore
4 | CSS=apps/web/priv/static/css
5 |
6 | NODE_APP=node
7 |
8 | $NODE_APP apps/web/priv/static/less/bin/lessc -x $APPSTORE/appstore.less > $CSS/appstore.css
9 |
10 | echo $?
11 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | RELEASE := web
2 | COOKIE := node_runner
3 | VER := 1.0.0
4 | FILES := apps/web/priv/static/n2o
5 |
6 | default: compile static-link
7 | static-link:
8 | rm -rf $(FILES)
9 | ln -sf ../../../../deps/n2o/priv $(FILES)
10 |
11 | include otp.mk
12 |
--------------------------------------------------------------------------------
/apps/web/src/web.app.src:
--------------------------------------------------------------------------------
1 | {application, web,
2 | [
3 | {description, "SKY VXZ Skyline N2O Demo"},
4 | {vsn, "1"},
5 | {registered, []},
6 | {applications, [kernel, stdlib, xmerl, erlydtl, cowboy, n2o, kvs]},
7 | {mod, { web_app, []}},
8 | {env, []}
9 | ]}.
10 |
--------------------------------------------------------------------------------
/apps/web/priv/static/appstore/appstore.less:
--------------------------------------------------------------------------------
1 | @import "variables.less";
2 | @import "../bootstrap/less/bootstrap.less";
3 | @import "../bootstrap/less/responsive.less";
4 | @import "common.less";
5 | @import "buttons.less";
6 | @import "navs.less";
7 | @import "carousel.less";
8 | @import "products.less";
9 | @import "feed.less";
10 | @import "account.less";
--------------------------------------------------------------------------------
/apps/web/priv/static/appstore/buttons.less:
--------------------------------------------------------------------------------
1 | .btn-google-plus {
2 | .buttonBackground(@btnGooglePlusBackground, @btnGooglePlusBackgroundHighlight);
3 | & .icon-google-plus{margin-right:12px;}
4 |
5 | }
6 |
7 | .btn{& .icon-facebook{margin-right:12px;} & .icon-twitter{margin-right:12px;}}
8 |
9 | .btn-google-plus.active {
10 | color: rgba(255,255,255,.75);
11 | }
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node
2 | ebin
3 | .applist
4 | .rebarinfo
5 | .dialyzer.plt
6 | *.dets
7 | *.gz
8 | *.dump
9 | apps/web/priv/static/n2o
10 | apps/web/priv/static/bootstrap
11 | apps/web/priv/static/font-awesome
12 | apps/web/priv/static/less
13 | apps/web/priv/static/tinymce
14 | deps
15 | bootstrap.min.js
16 | _rel
17 | kai
18 | log
19 | rels
20 | .idea/
21 | apps/web/.rebar/
22 | rebar
23 | skyline.iml
--------------------------------------------------------------------------------
/apps/web/rebar.config:
--------------------------------------------------------------------------------
1 | {erl_opts, [debug_info]}.
2 | {deps_dir, ["../../deps"]}.
3 | {deps, [n2o,cowboy,{erlydtl,".*",{git,"git://github.com/evanmiller/erlydtl.git",{tag,"0.8.0"}}}]}.
4 | {erlydtl_opts, [
5 | {doc_root, "priv/templates"},
6 | {out_dir, "ebin"},
7 | {compiler_options, [report, return, debug_info]},
8 | {source_ext, ".dtl"},
9 | {module_ext, "_view"}
10 | ]}.
11 |
--------------------------------------------------------------------------------
/apps/web/include/records.hrl:
--------------------------------------------------------------------------------
1 | -include_lib("nitro/include/nitro.hrl").
2 |
3 | -record(feed_entry, {?ELEMENT_BASE(product), entry}).
4 | -record(feed_comment, {?ELEMENT_BASE(product), comment}).
5 | -record(feed_media, {?ELEMENT_BASE(product), media, target, fid=0, cid=0, only_thumb}).
6 | -record(product_figure, {?ELEMENT_BASE(product), product}).
7 |
8 | -record(media, {
9 | id,
10 | title :: iolist(),
11 | width,
12 | height,
13 | html :: iolist(),
14 | url :: iolist(),
15 | version,
16 | thumbnail_url :: iolist(),
17 | type :: {atom(), atom() | string()},
18 | thumbnail_height}).
19 |
--------------------------------------------------------------------------------
/rels/web/files/sys.config:
--------------------------------------------------------------------------------
1 | [{n2o, [{port,8001},{transition_port,8001},{route,routes},{login,"/account"},{log_modules,index}]},
2 | {web,
3 | [{http_address, "http://skyline.synrc.com"},
4 | {fb_id, "385389014900491"},
5 | {fb_secret, []},
6 | {tw_consumer_key, "qfrLWd9KPpK8cz0pWmBg"},
7 | {tw_consumer_secret, "FTaon5hzrucCrMGsULMc6Zd6sYEkuiZy36LLURTFaoU"},
8 | {gplus_client_id, "146782506820.apps.googleusercontent.com"},
9 | {gplus_cookiepolicy, "http://synrc.com"}]},
10 | {kvs,
11 | [{pass_init_db,true},
12 | {nodes,[]},
13 | {log_modules,index},
14 | {dba, store_mnesia},
15 | {schema, [kvs_user, kvs_acl, kvs_feed, kvs_subscription ]}]}
16 | ].
17 |
--------------------------------------------------------------------------------
/apps/web/src/login.erl:
--------------------------------------------------------------------------------
1 | -module(login).
2 | -compile(export_all).
3 | -include_lib("avz/include/avz.hrl").
4 | -include_lib("n2o/include/wf.hrl").
5 | -include_lib("kvs/include/user.hrl").
6 | -include_lib("nitro/include/nitro.hrl").
7 |
8 | main() ->
9 | avz:callbacks(?METHODS),
10 | [ #dtl{file = "login", ext="dtl",bindings=[{title,<<"Login">>},
11 | {header,index:header()},
12 | {footer,index:footer()},
13 | {sdk,avz:sdk(?METHODS)},
14 | {buttons,avz:buttons(?METHODS)}]} ].
15 |
16 | event({counter,C}) -> wf:update(onlinenumber,wf:to_list(C));
17 | event(X) ->
18 | avz:event(X).
19 | api_event(X,Y,Z) -> avz:api_event(X,Y,Z).
20 |
--------------------------------------------------------------------------------
/apps/web/priv/static/img/facebook.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/orderapps.erl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env escript
2 |
3 | % This script boots up the Reltool Server for apps ordering
4 | % It also could generate reltool.config
5 |
6 | -module(orderapps).
7 | -compile([export_all]).
8 |
9 | relconfig(Apps) ->
10 | LibDirs = [Dir || Dir <- ["apps", "deps"], case file:read_file_info(Dir) of {ok, _} -> true; _ -> false end],
11 | {sys, [{lib_dirs,LibDirs}, {rel,"node","1",Apps}, {profile, embedded},
12 | {boot_rel,"node"}, {app,observer,[{incl_cond,exclude}]} ]}.
13 |
14 | main([]) -> io:format("usage: ./orderapps.erl apps~n", []);
15 | main(MainApps) ->
16 | Relconfig = relconfig([list_to_atom(A) || A <- MainApps]),
17 | {ok, Server} = reltool:start_server([{config, Relconfig}]),
18 | {ok, {release, _Node, _Erts, Apps}} = reltool_server:get_rel(Server, "node"),
19 | Ordered = [element(1, A) || A <- Apps],
20 | io:format("~w~n", [Ordered]).
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Skyline: N2O Sample Website
2 | ===========================
3 |
4 | Skyline was made with Nitrogen DSL and based on [N2O](https://github.com/5HT/n2o).
5 | It is a demo how to use N2O in real-life applications.
6 | Feel free to use it in your projects. It is provided as is in public domain.
7 |
8 | 
9 |
10 | Prerequisites
11 | =============
12 |
13 | * Erlang R16: sudo apt-get install erlang
14 | * Rebar: https://github.com/rebar/rebar
15 | * iNotify Tools (Linux only): sudo apt-get install inotify-tools
16 |
17 | Startup
18 | -------------
19 |
20 | make
21 | make console
22 |
23 | Init Database
24 | -------------
25 |
26 | In Erlang Shell perform
27 |
28 | > kvs:join().
29 |
30 | And open in browser [http://localhost:8001](http://localhost:8001)
31 |
32 | Credits
33 | -------
34 |
35 | * Maxim Sokhatsky
36 | * Andrew Zadorozhny
37 |
38 | OM A HUM
39 |
--------------------------------------------------------------------------------
/apps/web/src/dashboard.erl:
--------------------------------------------------------------------------------
1 | -module(dashboard).
2 | -compile(export_all).
3 | -include_lib("n2o/include/wf.hrl").
4 | -include_lib("nitro/include/nitro.hrl").
5 |
6 |
7 | sidebar_menu(Page)->
8 | Lis = [#li{class=if Page==I->active;true->[]end, body=#link{url="/"++atom_to_list(I), body=T}}
9 | || {I, T} <- [{products, <<"products">>}, {reviews, <<"reviews">>}, {account, <<"account">>}]],
10 | #panel{class=["docs-sidebar-menu", "dash-sidebar-menu"], body=#list{class=[nav, "nav-list", "docs-sidebar-nav", "dash-sidebar-nav", "affix-top"],
11 | data_fields=[{<<"data-spy">>, <<"affix">>}],
12 | body=Lis}}.
13 |
14 | section(Body, Icon) ->
15 | #section{class=["row-fluid", "dashboard-section"], body=[
16 | #panel{class=[span1], body=#i{class=[Icon, "icon-2x"]}},
17 | #panel{class=[span11, "dashboard-unit"], body=Body}
18 | ]}.
19 |
20 | broadcast_hello() ->
21 | spawn(fun()-> wf:wire(#alert{text="Hello, There!"}), wf:flush(room) end).
22 |
--------------------------------------------------------------------------------
/apps/web/src/routes.erl:
--------------------------------------------------------------------------------
1 | -module (routes).
2 | -author('Maxim Sokhatsky').
3 | -behaviour (route_handler).
4 | -include_lib("n2o/include/wf.hrl").
5 | -export([init/2, finish/2]).
6 |
7 | finish(State, Ctx) -> {ok, State, Ctx}.
8 | init(State, Ctx) ->
9 | Path = wf:path(Ctx#cx.req),
10 | Module = route_prefix(Path),
11 | {ok, State, Ctx#cx{path=Path,module=Module}}.
12 |
13 | route_prefix(<<"/ws/",P/binary>>) -> route(P);
14 | route_prefix(<<"/",P/binary>>) -> route(P);
15 | route_prefix(P) -> route(P).
16 |
17 | route(<<>>) -> index;
18 | route(<<"index">>) -> index;
19 | route(<<"login">>) -> login;
20 | route(<<"feed">>) -> feed;
21 | route(<<"account">>) -> account;
22 | route(<<"products">>) -> products;
23 | route(<<"product">>) -> product;
24 | route(<<"reviews">>) -> reviews;
25 | route(<<"chat">>) -> chat;
26 | route(<<"favicon.ico">>) -> static_file;
27 | route(_) -> index.
28 |
--------------------------------------------------------------------------------
/rebar.config:
--------------------------------------------------------------------------------
1 | {sub_dirs,["deps","apps"]}.
2 | {lib_dirs,["apps","deps"]}.
3 | {deps_dir,["deps"]}.
4 | {deps, [
5 | {"../apps/web/priv/static/bootstrap", ".*", {git, "git://github.com/twbs/bootstrap", {tag,"v2.3.2"}}, [raw]},
6 | {"../apps/web/priv/static/less", ".*", {git, "git://github.com/less/less.js.git", {tag,"v1.5.0"}}, [raw]},
7 | {"../apps/web/priv/static/font-awesome", ".*", {git, "git://github.com/FortAwesome/Font-Awesome", {tag,"v3.2.1"}}, [raw]},
8 | {n2o, ".*", {git, "git://github.com/5HT/n2o.git", {tag,"3.4"}}},
9 | {kvs, ".*", {git, "git://github.com/synrc/kvs.git", {tag,"3.4"}}},
10 | {avz, ".*", {git, "git://github.com/synrc/avz.git", {tag,"3.4"}}},
11 | {active, ".*", {git, "git://github.com/synrc/active", "master"}},
12 | {recon, ".*", {git, "git@github.com:ferd/recon.git", "master"}}
13 | ]}.
14 |
--------------------------------------------------------------------------------
/javascript.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | uglifyjs=`which uglifyjs`
4 | uglifyjs_args='-nc'
5 |
6 | check_uglifyjs() {
7 | if [ "$uglifyjs" == "" ] ; then
8 | echo "ERROR: uglifyjs not found. Please set uglifyjs in javascript.sh"
9 | exit 1;
10 | fi
11 | }
12 |
13 | create_script() {
14 | output="`pwd`/$2"
15 | echo "Generating `basename $output` in `dirname $output`"
16 | cp /dev/null $output
17 |
18 | cd $1
19 |
20 | # sort hack to keep order:
21 | for js in `ls -p -S *.js | egrep -v $3`; do
22 | echo "-> $js"
23 | $uglifyjs $uglifyjs_args $js >> $output
24 | done
25 |
26 | echo "done."
27 | cd -
28 | }
29 |
30 | check_uglifyjs
31 |
32 | create_script apps/web/priv/static/bootstrap/js apps/web/priv/static/js/bootstrap.min.js "/"
33 | create_script deps/n2o/priv apps/web/priv/static/js/all.min.js "/|all.js|zepto.js|minified.js"
34 |
35 | echo $?
36 |
--------------------------------------------------------------------------------
/apps/web/priv/templates/prod.dtl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{title}}
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | {{body}}
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/rels/web/files/erl:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | ## This script replaces the default "erl" in erts-VSN/bin. This is necessary
4 | ## as escript depends on erl and in turn, erl depends on having access to a
5 | ## bootscript (start.boot). Note that this script is ONLY invoked as a side-effect
6 | ## of running escript -- the embedded node bypasses erl and uses erlexec directly
7 | ## (as it should).
8 | ##
9 | ## Note that this script makes the assumption that there is a start_clean.boot
10 | ## file available in $ROOTDIR/release/VSN.
11 |
12 | # Determine the abspath of where this script is executing from.
13 | ERTS_BIN_DIR=$(cd ${0%/*} && pwd)
14 |
15 | # Now determine the root directory -- this script runs from erts-VSN/bin,
16 | # so we simply need to strip off two dirs from the end of the ERTS_BIN_DIR
17 | # path.
18 | ROOTDIR=${ERTS_BIN_DIR%/*/*}
19 |
20 | # Parse out release and erts info
21 | START_ERL=`cat $ROOTDIR/releases/start_erl.data`
22 | ERTS_VSN=${START_ERL% *}
23 | APP_VSN=${START_ERL#* }
24 |
25 | BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin
26 | EMU=beam
27 | PROGNAME=`echo $0 | sed 's/.*\\///'`
28 | CMD="$BINDIR/erlexec"
29 | export EMU
30 | export ROOTDIR
31 | export BINDIR
32 | export PROGNAME
33 |
34 | exec $CMD -boot $ROOTDIR/releases/$APP_VSN/start_clean ${1+"$@"}
35 |
--------------------------------------------------------------------------------
/apps/web/priv/static/img/twitter.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
--------------------------------------------------------------------------------
/apps/web/priv/templates/hd.dtl:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
--------------------------------------------------------------------------------
/rels/web/files/start_erl.cmd:
--------------------------------------------------------------------------------
1 | @setlocal
2 |
3 | @rem Parse arguments. erlsrv.exe prepends erl arguments prior to first ++.
4 | @rem Other args are position dependent.
5 | @set args="%*"
6 | @for /F "delims=++ tokens=1,2,3" %%I in (%args%) do @(
7 | @set erl_args=%%I
8 | @call :set_trim node_name %%J
9 | @rem Trim spaces from the left of %%K (node_root), which may have spaces inside
10 | @for /f "tokens=* delims= " %%a in ("%%K") do @set node_root=%%a
11 | )
12 |
13 | @set releases_dir=%node_root%\releases
14 |
15 | @rem parse ERTS version and release version from start_erl.dat
16 | @for /F "usebackq tokens=1,2" %%I in ("%releases_dir%\start_erl.data") do @(
17 | @call :set_trim erts_version %%I
18 | @call :set_trim release_version %%J
19 | )
20 |
21 | @set erl_exe="%node_root%\erts-%erts_version%\bin\erl.exe"
22 | @set boot_file="%releases_dir%\%release_version%\%node_name%"
23 |
24 | @if exist "%releases_dir%\%release_version%\sys.config" (
25 | @set app_config="%releases_dir%\%release_version%\sys.config"
26 | ) else (
27 | @set app_config="%node_root%\etc\app.config"
28 | )
29 |
30 | @if exist "%releases_dir%\%release_version%\vm.args" (
31 | @set vm_args="%releases_dir%\%release_version%\vm.args"
32 | ) else (
33 | @set vm_args="%node_root%\etc\vm.args"
34 | )
35 |
36 | @%erl_exe% %erl_args% -boot %boot_file% -config %app_config% -args_file %vm_args%
37 |
38 | :set_trim
39 | @set %1=%2
40 | @goto :EOF
41 |
--------------------------------------------------------------------------------
/apps/web/src/web_sup.erl:
--------------------------------------------------------------------------------
1 | -module(web_sup).
2 | -behaviour(supervisor).
3 | -export([start_link/0, init/1]).
4 | -compile(export_all).
5 | -include_lib("n2o/include/wf.hrl").
6 | -define(APP, web).
7 |
8 | start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []).
9 |
10 | init([]) ->
11 | {ok, _} = cowboy:start_http(http, 100, [{port, 8001}],
12 | [{env, [{dispatch, dispatch_rules()}]}]),
13 |
14 | Pid = spawn(fun () -> wf:reg(lobby), chat_room([],0) end),
15 | wf:cache(mode,wf:config(n2o,mode,"prod")),
16 | {ok, {{one_for_one, 5, 10}, []}}.
17 |
18 | dispatch_rules() ->
19 | cowboy_router:compile(
20 | [{'_', [
21 | {"/static/[...]", cowboy_static,
22 | {priv_dir, ?APP, <<"static">>,[{mimetypes,cow_mimetypes,all}]}},
23 | {"/ws/[...]", bullet_handler, [{handler, n2o_bullet}]},
24 | {'_', n2o_cowboy, []}
25 | ]}]).
26 |
27 | chat_room(List,Counter) ->
28 | receive
29 | {counter,Caller} -> Caller ! {counter,Counter}, chat_room(List,Counter);
30 | {inc} -> chat_room(List,Counter+1);
31 | {dec} -> chat_room(List,Counter-1);
32 | {add, Message} -> chat_room([Message|List],Counter);
33 | print -> io:format("~p",[List]), chat_room(List,Counter);
34 | {top, Number, Caller} -> Caller ! lists:sublist(List,Number), chat_room(List,Counter);
35 | {win, Page, Caller} -> Caller ! lists:sublist(List,Page*10,10), chat_room(List,Counter);
36 | _ -> chat_room(List,Counter) end.
37 |
38 |
--------------------------------------------------------------------------------
/apps/web/priv/static/appstore/navs.less:
--------------------------------------------------------------------------------
1 | .sky-nav{
2 | font-size: 24px;
3 | font-weight:bold;
4 |
5 | & li {
6 | &.active, &.active:hover, &.active:focus{
7 | & a, a:focus {
8 | color: @linkColorHover;
9 |
10 | &:hover{
11 | color:@linkColorHover;
12 | }
13 | background-color: transparent;
14 | border:3px solid white;
15 | border-top: 3px solid @linkColorHover;
16 | }
17 | }
18 |
19 | & a {
20 | color: #555555;
21 | text-transform: uppercase;
22 | border: 3px solid transparent;
23 | background-color: transparent;
24 | text-shadow: none;
25 |
26 | &:hover, &:focus{
27 | color: @linkColorHover;
28 | background-color: transparent;
29 | border: 3px solid transparent;
30 | border-top: 3px solid @linkColorHover;
31 | }
32 | }
33 | }
34 | }
35 |
36 | /* support colors?
37 | .muted { color: @grayLight; }
38 | a.muted:hover,
39 | a.muted:focus { color: darken(@grayLight, 10%); }
40 |
41 | .text-warning { color: @warningText; }
42 | a.text-warning:hover,
43 | a.text-warning:focus { color: darken(@warningText, 10%); }
44 |
45 | .text-error { color: @errorText; }
46 | a.text-error:hover,
47 | a.text-error:focus { color: darken(@errorText, 10%); }
48 |
49 | .text-info { color: @infoText; }
50 | a.text-info:hover,
51 | a.text-info:focus { color: darken(@infoText, 10%); }
52 |
53 | .text-success { color: @successText; }
54 | a.text-success:hover,
55 | a.text-success:focus { color: darken(@successText, 10%); }
56 | */
--------------------------------------------------------------------------------
/apps/web/priv/templates/tl.dtl:
--------------------------------------------------------------------------------
1 |
2 |
33 |
--------------------------------------------------------------------------------
/apps/web/src/element_carousel.erl:
--------------------------------------------------------------------------------
1 | -module(element_carousel).
2 | -compile(export_all).
3 | -include_lib("web/include/wf.hrl").
4 |
5 | render_element(R = #carousel{})->
6 | Id = if R#carousel.id == undefined -> wf:temp_id(); true -> R#carousel.id end,
7 | Interval = case R#carousel.interval of false -> <<"false">>; I -> list_to_binary(integer_to_list(I)) end,
8 | case length(R#carousel.items) of
9 | 0 -> [];
10 | ItemsCount -> {List, Items} = lists:unzip([
11 | begin
12 | Index = list_to_binary(integer_to_list(I)),
13 | { #li{data_fields=[{<<"data-target">>, list_to_binary("#"++Id)}, {<<"data-slide-to">>, Index}]},
14 | #panel{ class=if I==0 -> [item,active]; true -> [item] end,
15 | data_fields=[{<<"data-slide-number">>, Index}], body=E} }
16 | end || {I, E} <- lists:zip(lists:seq(0,ItemsCount-1), R#carousel.items)]),
17 |
18 | C = #panel{id = Id, show_if=ItemsCount > 0, class=[carousel, slide | R#carousel.class], style=[R#carousel.style],
19 | data_fields=[{<<"data-interval">>, Interval}, {<<"data-pause">>, R#carousel.pause}], body=[
20 | #list{show_if=R#carousel.indicators == true, numbered=true, class=["carousel-indicators"], body=List},
21 | #panel{class=["carousel-inner"], body=[Items]},
22 | #link{class=["carousel-control", left], url="#"++Id, data_fields=[{<<"data-slide">>, <<"prev">>}], body="‹"},
23 | #link{class=["carousel-control", right], url="#"++Id, data_fields=[{<<"data-slide">>, <<"next">>}], body="›"},
24 | #panel{class=["carousel-caption"], body=R#carousel.caption} ]},
25 | element_panel:render_element(C)
26 | end.
27 |
--------------------------------------------------------------------------------
/apps/web/priv/templates/dev.dtl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{title}}
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | {{body}}
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/rels/web/files/install_upgrade.escript:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env escript
2 | %%! -noshell -noinput
3 | %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
4 | %% ex: ft=erlang ts=4 sw=4 et
5 |
6 | -define(TIMEOUT, 60000).
7 | -define(INFO(Fmt,Args), io:format(Fmt,Args)).
8 |
9 | main([NodeName, Cookie, ReleasePackage]) ->
10 | TargetNode = start_distribution(NodeName, Cookie),
11 | {ok, Vsn} = rpc:call(TargetNode, release_handler, unpack_release,
12 | [ReleasePackage], ?TIMEOUT),
13 | ?INFO("Unpacked Release ~p~n", [Vsn]),
14 | {ok, OtherVsn, Desc} = rpc:call(TargetNode, release_handler,
15 | check_install_release, [Vsn], ?TIMEOUT),
16 | {ok, OtherVsn, Desc} = rpc:call(TargetNode, release_handler,
17 | install_release, [Vsn], ?TIMEOUT),
18 | ?INFO("Installed Release ~p~n", [Vsn]),
19 | ok = rpc:call(TargetNode, release_handler, make_permanent, [Vsn], ?TIMEOUT),
20 | ?INFO("Made Release ~p Permanent~n", [Vsn]);
21 | main(_) ->
22 | init:stop(1).
23 |
24 | start_distribution(NodeName, Cookie) ->
25 | MyNode = make_script_node(NodeName),
26 | {ok, _Pid} = net_kernel:start([MyNode, shortnames]),
27 | erlang:set_cookie(node(), list_to_atom(Cookie)),
28 | TargetNode = make_target_node(NodeName),
29 | case {net_kernel:hidden_connect_node(TargetNode),
30 | net_adm:ping(TargetNode)} of
31 | {true, pong} ->
32 | ok;
33 | {_, pang} ->
34 | io:format("Node ~p not responding to pings.\n", [TargetNode]),
35 | init:stop(1)
36 | end,
37 | TargetNode.
38 |
39 | make_target_node(Node) ->
40 | [_, Host] = string:tokens(atom_to_list(node()), "@"),
41 | list_to_atom(lists:concat([Node, "@", Host])).
42 |
43 | make_script_node(Node) ->
44 | list_to_atom(lists:concat([Node, "_upgrader_", os:getpid()])).
45 |
--------------------------------------------------------------------------------
/apps/web/src/reviews.erl:
--------------------------------------------------------------------------------
1 | -module(reviews).
2 | -compile(export_all).
3 | -include_lib("web/include/wf.hrl").
4 | -include_lib("kvs/include/user.hrl").
5 | -include_lib("kvs/include/feed.hrl").
6 | -include_lib("nitro/include/nitro.hrl").
7 |
8 | main() -> [#dtl{file = wf:cache(mode), ext="dtl", bindings=[{title,<<"Reviews">>},{body,body()}]}].
9 |
10 | body() -> index:header() ++ [
11 | #section{id=content, body=
12 | #panel{class=[container], body=
13 | #panel{class=[row, dashboard], body=[
14 | #panel{class=[span3], body=dashboard:sidebar_menu(reviews)},
15 | #panel{class=[span9], body=dashboard:section(feed(wf:user()), "icon-list")}]}}}
16 | ] ++ index:footer().
17 |
18 | feed(User) -> [
19 | #h3{body= <<"your reviews">>},
20 | #panel{class=["btn-toolbar"], body=[#link{class=[btn, "btn-large", "btn-success"], body= <<"Create New Box">>}]},
21 |
22 | #table{class=[table, "table-hover", containers],
23 | header=[ #tr{cells=[
24 | #th{body= <<"ID">>},
25 | #th{body= <<"Host">>},
26 | #th{body= <<"Pass">>},
27 | #th{body= <<"Region">>},
28 | #th{body= <<"SSH">>},
29 | #th{body= <<"action">>}]} ],
30 | body=[[
31 | #tr{class=[success], cells=[
32 | #td{body= <<"1d3e102378f9">>},
33 | #td{body= <<"sncn1">>},
34 | #td{body= <<"pass">>},
35 | #td{body= <<"do1.synrc.com">>},
36 | #td{body= <<"49153">>},
37 | #td{body=#link{class=[btn],body= <<"Stop">>}} ]},
38 | #tr{class=[error], cells=[
39 | #td{body= <<"0515e2b20bac">>},
40 | #td{body= <<"sncn2">>},
41 | #td{body= <<"pass">>},
42 | #td{body= <<"do1.synrc.com">>},
43 | #td{body= <<"49154">>},
44 | #td{body=#link{class=[btn], body= <<"Start">>}} ]} ]]}
45 | ].
46 |
47 | event(init) -> [];
48 | event({counter,C}) -> wf:update(onlinenumber,wf:to_list(C)).
49 | api_event(Name,Tag,Term) -> error_logger:info_msg("Name ~p, Tag ~p, Term ~p",[Name,Tag,Term]), ok.
50 |
--------------------------------------------------------------------------------
/rels/web/reltool.config:
--------------------------------------------------------------------------------
1 | {sys, [
2 | {lib_dirs, ["../../apps","../../deps"]},
3 | {erts, [{mod_cond, derived}, {app_file, strip}]},
4 | {app_file, strip},
5 | {rel, "node", "1",
6 | [
7 | kernel,
8 | stdlib,
9 | sasl,
10 | avz,
11 | erts,
12 | mnesia,
13 | compiler,
14 | % bitcask,
15 | % eleveldb,
16 | % riak_api,
17 | % riak_control,
18 | mimetypes,
19 | n2o,
20 | % folsom,
21 | gproc,
22 | ssl,
23 | kai,
24 | kvs,
25 | ranch,
26 | % active,
27 | % erlfsmon,
28 | % rebar,
29 | sync,
30 | erlydtl,
31 | cowboy,
32 | crypto,
33 | lager,
34 | oauth,
35 | xmerl,
36 | web
37 | ]},
38 | {rel, "start_clean", "",
39 | [
40 | kernel,
41 | stdlib
42 | ]},
43 | {boot_rel, "node"},
44 | {profile, embedded},
45 | {incl_cond, derived},
46 | {mod_cond, derived},
47 | {excl_archive_filters, [".*"]}, %% Do not archive built libs
48 | {excl_sys_filters, ["^bin/.*", "^erts.*/bin/(dialyzer|typer)",
49 | "^erts.*/(doc|info|include|lib|man|src)"]},
50 | {excl_app_filters, ["\.gitignore"]},
51 | {app, appmon, [{mod_cond, app}, {incl_cond, exclude}]},
52 | {app, web, [{mod_cond, app}, {incl_cond, include}]}
53 | ]}.
54 |
55 | {target_dir, "node"}.
56 |
57 | {overlay, [
58 | {mkdir, "log/sasl"},
59 | {copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"},
60 | {copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"},
61 | {copy, "files/node", "bin/node"},
62 | {copy, "files/node.cmd", "bin/node.cmd"},
63 | {copy, "files/start_erl.cmd", "bin/start_erl.cmd"},
64 | {copy, "files/install_upgrade.escript", "bin/install_upgrade.escript"},
65 | {copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"},
66 | {copy, "files/vm.args", "releases/\{\{rel_vsn\}\}/vm.args"}
67 | ]}.
68 |
--------------------------------------------------------------------------------
/apps/web/include/wf.hrl:
--------------------------------------------------------------------------------
1 | -ifndef(N2O_BOOTSTRAP_HRL).
2 | -define(N2O_BOOTSTRAP_HRL, true).
3 |
4 | %%-include("../../../deps/n2o/include/wf.hrl").
5 | -include("../../../deps/nitro/include/nitro.hrl").
6 |
7 | % emulate msg ! socket through wire
8 | -define(WS_SEND(Id,Ev,Detail), wf:wire(wf:f("document.getElementById('~s').dispatchEvent("
9 | "new CustomEvent('~s', {'detail': ~s}));", [Id,wf:to_list(Ev),wf:json([Detail])]))).
10 |
11 | % REST macros
12 | -define(rest(), is_rest() -> true).
13 | -define(unmap(Record), unmap(P,R) -> wf_utils:hunmap(P,R,record_info(fields, Record),size(R)-1)).
14 | -define(map(Record), map(O) ->
15 | Y = [ try N=lists:nth(1,B), if is_number(N) -> wf:to_binary(B); true -> B end catch _:_ -> B end
16 | || B <- tl(tuple_to_list(O)) ],
17 | lists:zip(record_info(fields, Record), Y)).
18 |
19 |
20 | % Twitter Bootstrap Elements
21 | -record(carousel, {?ELEMENT_BASE(element_carousel), interval=5000, pause= <<"hover">>, start=0, indicators=true, items=[], caption=[]}).
22 | -record(accordion, {?ELEMENT_BASE(element_accordion), items=[], nav_stacked=false}).
23 | -record(slider, {?ELEMENT_BASE(element_slider), min, max, step, orientation, value, selection, tooltip, handle, formater}).
24 |
25 | % Synrc Elements
26 | %%-record(rtable, {?ELEMENT_BASE(element_rtable), rows=[], postback}).
27 | -record(rtable, {?ELEMENT_BASE(element_rtable), rows=[]}).
28 | -record(upload_state, {cid, root=code:priv_dir(n2o), dir="", name,
29 | type, room=upload, data= <<>>, preview=false, size=[{200,200}], index=0, block_size=1048576}).
30 | %%-record(upload, {?CTRL_BASE(element_upload), name, value, state=#upload_state{}, root, dir, delegate_query, delegate_api, post_write, img_tool, post_target, size, preview}).
31 | %%-record(textboxlist, {?ELEMENT_BASE(element_textboxlist), placeholder="", postback, unique=true, values=[], autocomplete=true, queryRemote=true, onlyFromValues=true, minLenght=1}).
32 | -record(textboxlist, {?ELEMENT_BASE(element_textboxlist), placeholder="", unique=true, values=[], autocomplete=true, queryRemote=true, onlyFromValues=true, minLenght=1}).
33 | %%-record(htmlbox, {?CTRL_BASE(element_htmlbox), html, state=#upload_state{}, root, dir, delegate_query, delegate_api, post_write, img_tool, post_target, size}).
34 | -record(htmlbox, {?CTRL_BASE(element_htmlbox), html, state=#upload_state{}, root, delegate_query, delegate_api, post_write, img_tool, post_target, size}).
35 | -endif.
36 |
--------------------------------------------------------------------------------
/apps/web/priv/static/appstore/variables.less:
--------------------------------------------------------------------------------
1 | // Bootstrap Core variables
2 | @import "../bootstrap/less/variables.less";
3 |
4 |
5 | @azure: #6bc7e1;
6 | @darkAzure: #41b7d8;
7 |
8 | // Links
9 | // -------------------------
10 | @linkColor: @azure;
11 | @linkColorHover: @darkAzure;
12 |
13 | // Typography
14 | // -------------------------
15 | @import url(http://fonts.googleapis.com/css?family=Open+Sans:400italic,400,800);
16 |
17 | @font-face {
18 | font-family: 'Nokia Pure Text';
19 | src: url("http://synrc.com/fonts/nokiapuretextlight-webfont.eot?v=3");
20 | src: url("http://synrc.com/fonts/nokiapuretextlight-webfont.eot?v=3") format("eot"),
21 | url("http://synrc.com/fonts/nokiapuretextlight-webfont.woff?v=3") format("truetype"),
22 | url("http://synrc.com/fonts/nokiapuretextlight-webfont.ttf?v=3") format("truetype");
23 | font-weight: 200;
24 | font-style: normal;
25 | }
26 |
27 | @nokiaFontFamily: "Nokia Pure Text", Arial, serif;
28 | @openSansFontFamily: "Open Sans", Arial, serif;
29 |
30 | @baseFontSize: 20px;
31 | @baseFontFamily: @nokiaFontFamily;
32 | @baseLineHeight: 24px;
33 | @altFontFamily: @openSansFontFamily;
34 |
35 | @headingsFontFamily: @openSansFontFamily; // empty to use BS default, @baseFontFamily
36 | @headingsFontWeight: 800; // instead of browser default, bold
37 | @headingsColor: inherit; // empty to use BS default, @textColor
38 |
39 | // Component sizing
40 | // -------------------------
41 | @fontSizeLarge: @baseFontSize * 1.25;
42 | @fontSizeSmall: @baseFontSize * 0.85;
43 | @fontSizeMini: @baseFontSize * 0.75;
44 |
45 | @baseBorderRadius: 0;
46 | @borderRadiusLarge: 0;
47 | @borderRadiusSmall: 0;
48 |
49 | // Navbar
50 | // -------------------------
51 | @navbarCollapseWidth: 979px;//?
52 | @navbarCollapseDesktopWidth: @navbarCollapseWidth + 1;
53 |
54 | @navbarHeight: 40px;// ?
55 | @navbarLinkColorHover: @darkAzure;
56 |
57 | // Products
58 | // -------------------------
59 | @productHeight: 160px;
60 | @prodListBackground: @grayLighter;
61 | @prodBackground: @white;
62 | @reviewBackground: @white;
63 |
64 | // Buttons
65 | // -------------------------
66 | @btnGooglePlusBackground: #cc3732;
67 | @btnGooglePlusBackgroundHighlight: #e74b37;
68 |
--------------------------------------------------------------------------------
/otp.mk:
--------------------------------------------------------------------------------
1 | VM := rels/web/files/vm.args
2 | SYS := rels/web/files/sys.config
3 | PLT_NAME := ~/.n2o_dialyzer.plt
4 | ERL_ARGS := -args_file $(VM) -config $(SYS)
5 | RUN_DIR ?= rels/web/devbox
6 | LOG_DIR ?= rels/web/devbox/logs
7 | empty :=
8 | ROOTS := apps deps
9 | space := $(empty) $(empty)
10 | comma := $(empty),$(empty)
11 | VSN := $(shell git rev-parse HEAD | head -c 6)
12 | DATE := $(shell date "+%Y%m%d-%H%M%S")
13 | ERL_LIBS := $(subst $(space),:,$(ROOTS))
14 | relx := "{release,{$(RELEASE),\"$(VER)\"},[$(RELEASE)]}.\\n{include_erts,true}.\
15 | \\n{extended_start_script,true}.\\n{generate_start_script,true}.\\n{sys_config,\"$(SYS)\"}.\
16 | \\n{vm_args,\"$(VM)\"}.\\n{overlay,[{mkdir,\"log/sasl\"}]}."
17 |
18 | test: eunit ct
19 | compile: get-deps static-link
20 | clean:
21 | rm -f .applist
22 | rebar $@
23 | delete-deps get-deps compile update-deps:
24 | rebar $@
25 | .applist:
26 | $(eval APPS := $(subst deps/,,$(subst apps/,,$(shell find apps deps -maxdepth 1 -mindepth 1 -type d))))
27 | ./orderapps.erl $(APPS) > $@
28 | $(RUN_DIR) $(LOG_DIR):
29 | mkdir -p $(RUN_DIR) & mkdir -p $(LOG_DIR)
30 | console: .applist
31 | ERL_LIBS=$(ERL_LIBS) erl $(ERL_ARGS) -eval '[application:start(A) || A <- $(shell cat .applist)]'
32 | start: $(RUN_DIR) $(LOG_DIR) .applist
33 | RUN_ERL_LOG_GENERATIONS=1000 RUN_ERL_LOG_MAXSIZE=20000000 \
34 | ERL_LIBS=$(ERL_LIBS) run_erl -daemon $(RUN_DIR)/ $(LOG_DIR)/ "exec $(MAKE) console"
35 | attach:
36 | to_erl $(RUN_DIR)/
37 | release:
38 | echo $(relx) > relx.config && relx
39 | stop:
40 | @kill -9 $(shell ps ax -o pid= -o command=|grep $(RELEASE)|grep $(COOKIE)|awk '{print $$1}')
41 | $(PLT_NAME):
42 | $(eval APPS := $(subst deps/,,$(subst apps/,,$(shell find apps deps -maxdepth 1 -mindepth 1 -type d))))
43 | ERL_LIBS=$(ERL_LIBS) dialyzer --build_plt --output_plt $(PLT_NAME) --apps $(APPS) || true
44 | dialyze: $(PLT_NAME) compile
45 | $(eval APPS := $(shell find apps deps -maxdepth 1 -mindepth 1 -type d))
46 | @$(foreach var,$(APPS),(echo "Process $(var)"; dialyzer -q $(var)/ebin --plt $(PLT_NAME) --no_native -Werror_handling -Wunderspecs -Wrace_conditions -Wno_undefined_callbacks);)
47 | tar: release
48 | tar zcvf $(RELEASE)-$(VSN)-$(DATE).tar.gz _rel/lib/*/ebin _rel/lib/*/priv _rel/bin _rel/releases
49 | eunit:
50 | rebar eunit skip_deps=true
51 | ct:
52 | rebar ct skip_deps=true verbose=1
53 |
54 | .PHONY: delete-deps get-deps compile clean console start attach release update-deps dialyze ct eunit tar
55 |
--------------------------------------------------------------------------------
/apps/web/priv/static/img/google.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
26 |
27 |
--------------------------------------------------------------------------------
/apps/web/src/index.erl:
--------------------------------------------------------------------------------
1 | -module(index).
2 | -compile(export_all).
3 | -include_lib("n2o/include/wf.hrl").
4 | -include_lib("kvs/include/user.hrl").
5 | -include_lib("nitro/include/nitro.hrl").
6 |
7 |
8 | log_modules() -> [index,login,chat].
9 |
10 | main() -> [ #dtl{file = wf:cache(mode), ext="dtl", bindings=[{title,<<"Index">>},{body,body()}]} ].
11 |
12 | body() ->
13 | index:header()
14 | ++ [#panel{style="font-size:38pt;height:200px;text-align: center;margin-top:200px;",
15 | body="Hello, N2O!"}]
16 | ++ index:footer().
17 |
18 | account() ->
19 | #li{body=[
20 | case wf:user() of
21 | undefined -> #link{id=login1, body= <<"Login">>, postback=to_login, delegate=login};
22 | User -> #link{class=["dropdown-toggle", "avatar"], url="/account", body=[
23 | case User#user.images of
24 | undefined -> "";
25 | Img -> #image{class=["img-circle", "img-polaroid"],
26 | image=iolist_to_binary([Img,"?sz=50&width=50&height=50&s=50"]),
27 | width= <<"50px">>, height= <<"50px">>} end,
28 | case User#user.display_name of undefined -> []; N -> N end]} end,
29 | #button{id="style-switcher", class=[btn, "btn-inverse", "dropdown-toggle", "account-link"],
30 | data_fields=[{<<"data-toggle">>, <<"dropdown">>}], body=#i{class=["icon-cog"]}},
31 | #list{class=["dropdown-menu"], body=[
32 | #li{body=#link{body=[#i{class=["icon-cog"]}, <<" Preferences">>]}},
33 | #li{body=#link{postback=chat,body=[#i{class=["icon-cog"]}, <<" Notifications">>]}},
34 | case wf:user() of
35 | undefined -> #li{body=#link{id=loginbtn, postback=to_login, delegate=login,
36 | body=[#i{class=["icon-off"]}, <<" Login">> ]}};
37 | _A -> #li{body=#link{id=logoutbtn, postback=logout, delegate=login,
38 | body=[#i{class=["icon-off"]}, <<" Logout">> ] }} end ]} ]}.
39 |
40 |
41 | header() -> Online = ets:lookup(globals,onlineusers),
42 | C = case Online of
43 | [{_,I}] -> I;
44 | _ -> 0
45 | end,
46 | [ #dtl{file = "hd", ext="dtl", bindings=[{account,account()},{online,wf:to_list(C)}]} ].
47 | footer() -> [ #dtl{file = "tl", ext="dtl", bindings=[]} ].
48 |
49 | api_event(Name,Tag,Term) -> error_logger:info_msg("Index Name ~p, Tag ~p, Term ~p",[Name,Tag,Term]), event(change_me).
50 | event({counter,C}) -> wf:update(onlinenumber,wf:to_list(C));
51 | event(Event) ->
52 | wf:info(?MODULE,"Context: ~p",[wf_context:context()]),
53 | error_logger:info_msg("Event: ~p", [Event]).
54 |
--------------------------------------------------------------------------------
/rels/web/files/node.cmd:
--------------------------------------------------------------------------------
1 | @setlocal
2 |
3 | @set node_name=node
4 |
5 | @rem Get the absolute path to the parent directory,
6 | @rem which is assumed to be the node root.
7 | @for /F "delims=" %%I in ("%~dp0..") do @set node_root=%%~fI
8 |
9 | @set releases_dir=%node_root%\releases
10 |
11 | @rem Parse ERTS version and release version from start_erl.data
12 | @for /F "usebackq tokens=1,2" %%I in ("%releases_dir%\start_erl.data") do @(
13 | @call :set_trim erts_version %%I
14 | @call :set_trim release_version %%J
15 | )
16 |
17 | @set vm_args=%releases_dir%\%release_version%\vm.args
18 | @set sys_config=%releases_dir%\%release_version%\sys.config
19 | @set node_boot_script=%releases_dir%\%release_version%\%node_name%
20 | @set clean_boot_script=%releases_dir%\%release_version%\start_clean
21 |
22 | @rem extract erlang cookie from vm.args
23 | @for /f "usebackq tokens=1-2" %%I in (`findstr /b \-setcookie "%vm_args%"`) do @set erlang_cookie=%%J
24 |
25 | @set erts_bin=%node_root%\erts-%erts_version%\bin
26 |
27 | @set service_name=%node_name%_%release_version%
28 |
29 | @set erlsrv="%erts_bin%\erlsrv.exe"
30 | @set epmd="%erts_bin%\epmd.exe"
31 | @set escript="%erts_bin%\escript.exe"
32 | @set werl="%erts_bin%\werl.exe"
33 |
34 | @if "%1"=="usage" @goto usage
35 | @if "%1"=="install" @goto install
36 | @if "%1"=="uninstall" @goto uninstall
37 | @if "%1"=="start" @goto start
38 | @if "%1"=="stop" @goto stop
39 | @if "%1"=="restart" @call :stop && @goto start
40 | @if "%1"=="console" @goto console
41 | @if "%1"=="query" @goto query
42 | @if "%1"=="attach" @goto attach
43 | @if "%1"=="upgrade" @goto upgrade
44 | @echo Unknown command: "%1"
45 |
46 | :usage
47 | @echo Usage: %~n0 [install^|uninstall^|start^|stop^|restart^|console^|query^|attach^|upgrade]
48 | @goto :EOF
49 |
50 | :install
51 | @set description=Erlang node %node_name% in %node_root%
52 | @set start_erl=%node_root%\bin\start_erl.cmd
53 | @set args= ++ %node_name% ++ %node_root%
54 | @%erlsrv% add %service_name% -c "%description%" -sname %node_name% -w "%node_root%" -m "%start_erl%" -args "%args%" -stopaction "init:stop()."
55 | @goto :EOF
56 |
57 | :uninstall
58 | @%erlsrv% remove %service_name%
59 | @%epmd% -kill
60 | @goto :EOF
61 |
62 | :start
63 | @%erlsrv% start %service_name%
64 | @goto :EOF
65 |
66 | :stop
67 | @%erlsrv% stop %service_name%
68 | @goto :EOF
69 |
70 | :console
71 | @start "%node_name% console" %werl% -boot "%node_boot_script%" -config "%sys_config%" -args_file "%vm_args%" -sname %node_name%
72 | @goto :EOF
73 |
74 | :query
75 | @%erlsrv% list %service_name%
76 | @exit %ERRORLEVEL%
77 | @goto :EOF
78 |
79 | :attach
80 | @for /f "usebackq" %%I in (`hostname`) do @set hostname=%%I
81 | start "%node_name% attach" %werl% -boot "%clean_boot_script%" -remsh %node_name%@%hostname% -sname console -setcookie %erlang_cookie%
82 | @goto :EOF
83 |
84 | :upgrade
85 | @if "%2"=="" (
86 | @echo Missing upgrade package argument
87 | @echo Usage: %~n0 upgrade {package base name}
88 | @echo NOTE {package base name} MUST NOT include the .tar.gz suffix
89 | @goto :EOF
90 | )
91 | @%escript% %node_root%\bin\install_upgrade.escript %node_name% %erlang_cookie% %2
92 | @goto :EOF
93 |
94 | :set_trim
95 | @set %1=%2
96 | @goto :EOF
97 |
--------------------------------------------------------------------------------
/apps/web/priv/static/appstore/account.less:
--------------------------------------------------------------------------------
1 | .dash-sidebar-nav{
2 | font-size: 26px;
3 | list-style-type: none;
4 | margin: 24px 20px 0 0;
5 | padding: 0;
6 | width: 210px;
7 |
8 | @media (min-width: 1200px){width: 250px;}
9 | & li {
10 | & a{
11 | color: #555555;
12 | margin: 0 0 10px;
13 | text-align: right;
14 | text-transform: uppercase;
15 | padding-right: 20px;
16 | background-color: transparent;
17 | border-right: 3px solid #555555;
18 | text-shadow: none;
19 | }
20 | }
21 | }
22 |
23 | .dashboard{
24 | margin-top:40px;
25 | @media (max-width: 767px){margin-top:0;}
26 |
27 | & .dashboard-section{
28 | margin:60px 0 0 0;
29 | &:first-child{
30 | margin-top:0;
31 | border-bottom: 1px solid #e9e9e9;
32 | }
33 | }
34 |
35 | & .dashboard-unit{
36 | padding: 0;
37 | z-index: 1;
38 | overflow: hidden;
39 | padding-bottom:30px;
40 |
41 | & select{width:100%;}
42 | & h3{margin-bottom:60px;}
43 |
44 | &:hover{& .dashboard-img{
45 | border-color: rgba(153, 153, 153, 0.3);
46 | & img {.opacity(80);}
47 | }}
48 |
49 | & .dashboard-img-wrapper{
50 | text-align:center;
51 | @media (max-width: 979px) and (min-width: 768px){width:100%;}
52 | @media (min-width: 1200px) {text-align:left;}
53 | }
54 | & .dashboard-img {
55 | display:inline-block;
56 | margin:0 0 30px;
57 | max-width: 180px;
58 | max-height: 180px;
59 | .box-shadow(0 0 10px rgba(51, 51, 51, 0.9) inset);
60 | border: 10px solid #e9e9e9;
61 | .transition(all 0.2s);
62 | .border-radius(500px);
63 |
64 | z-index: -1;
65 | & img{
66 | .transition(all 0.2s);
67 | .border-radius(inherit);
68 | .opacity(40);
69 | }
70 | &.img-polaroid{padding:0;}
71 | }
72 |
73 | & .profile-info-wrapper{
74 | min-width:370px;
75 | text-align:center;
76 | @media (max-width:410px){width:100%;min-width:100%;}
77 | @media (max-width: 979px) and (min-width: 768px){width:100%;}
78 | @media (min-width: 1200px) {text-align:left; margin-left:0;}
79 | }
80 | & .profile-info{
81 | min-width:370px;
82 | @media (max-width:410px){width:100%; min-width:100%;}
83 |
84 | font-size: 30px;
85 | line-height: 1.5em;
86 | font-weight: 300;
87 | display:inline-block;
88 | text-align:left;
89 |
90 | & label {
91 | font-size: 30px;
92 | line-height: 1.5em;
93 | font-weight: 300;
94 | margin-right:10px;
95 | margin-bottom:0;
96 |
97 | @media (max-width:410px){width:100%;}
98 | }
99 | }
100 |
101 | & .payments{
102 | font-size:20px;
103 | margin-bottom:60px;
104 | max-width: 500px;
105 | @media (max-width:768px){margin: 0 auto;}
106 | }
107 |
108 | & .containers{
109 | margin-bottom:60px;
110 | max-width: 600px;
111 | font-size:18pt;
112 | }
113 |
114 | & .btn-charge{margin-top:10px;}
115 |
116 | & .ballance-label{
117 | margin-bottom:20px;
118 | font-size: 20px;
119 |
120 | & b{
121 | font-size:56px;
122 | line-height:70px;
123 | margin:0 auto;
124 | display:block;
125 | &.positive{color:green;}
126 | &.negative{color:red;}
127 | }
128 | & span { }
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/apps/web/src/chat.erl:
--------------------------------------------------------------------------------
1 | -module(chat).
2 | -compile(export_all).
3 | -include_lib("n2o/include/wf.hrl").
4 | -include_lib("kvs/include/user.hrl").
5 | -include_lib("nitro/include/nitro.hrl").
6 |
7 |
8 | main() ->
9 | [ #dtl{file = wf:cache(mode), ext="dtl", bindings=[{title,<<"Login">>},{body,body()}]} ].
10 |
11 | message(undefined,What) -> message("Anonymous",What);
12 | message(Who,What) ->
13 | error_logger:info_msg("~p",[What]),
14 | #panel{class=["media"],body=[
15 | #link{class=["pull-left"], body=[
16 | #image{class=["media-object"],image="static/img/infinity.png",width= <<"63">>} ]},
17 | #panel{class=["media-body"],body=[
18 | #h4{body= unicode:characters_to_binary(Who)},
19 | #span{body=wf:js_escape(What)} ]} ]}.
20 |
21 | body() ->
22 | {ok,Pid} = wf:async("looper",fun() -> chat_loop() end),
23 | index:header() ++ [
24 | #panel{class=["container-fluid", chat], body=[
25 | #panel{class=["row-fluid"], body=[
26 | #h1{body= <<"N2O based WebSocket Chat">>,class=[offset3, span8]}
27 | ]},
28 | #panel{class=["row-fluid"], body=[
29 | #panel{class=[span3], body=[
30 | #h4{body= "Online Users:" },
31 | #list{class=[unstyled, "chat-rooms"], body=[
32 | #li{body=#link{body= io_lib:format("~p",[Z])}} || {X,Y,Z} <- qlc:e(gproc:table()), X=={p,l,broadcast}
33 | ]} ]},
34 | #panel{class=[span8], body=[
35 | #panel{id=history, class=[history], body=[
36 | case wf:user() of undefined -> message("System","You are not logged in. Anonymous mode!");
37 | User -> message("System", "Hello, "++
38 | case User#user.display_name of <> -> binary_to_list(N);
39 | undefined -> "Anonymous";
40 | L -> L end
41 | ++ "! Here you can chat, please go on!") end ]},
42 | #textarea{id=message,style="display: inline-block; width: 200px; margin-top: 20px; margin-right: 20px;"},
43 | #button{id=send,body="Send",class=["btn","btn-primary","btn-large","btn-inverse"],postback={chat,Pid},source=[message]}
44 | ]}
45 | ]}
46 | ]}
47 |
48 | ] ++ index:footer().
49 |
50 |
51 | event({inc,Pid}) ->
52 | {Headers,Req} = wf:headers(?REQ),
53 | Host = lists:keyfind(<<"host">>,1,Headers),
54 | wf:info(?MODULE,"Headers: ~p",[Headers]),
55 | wf:info(?MODULE,"Host: ~p",[Host]),
56 | wf:info("Inc"),
57 | Pid ! inc;
58 |
59 | event(init) ->
60 | Self = self(),
61 | wf:reg(room),
62 | wf:send(lobby,{top,5,Self}),
63 | Terms = wf:render(receive Top -> [ message(U,M) || {U,M} <- Top] end),
64 | wf:insert_top(<<"history">>, #panel{body=[Terms]}),
65 | wf:wire("$('#history').scrollTop = $('#history').scrollHeight;");
66 |
67 | event({chat,Pid}) ->
68 | Username = case wf:user() of undefined -> "anonymous"; A -> A#user.id end,
69 | Message = wf:q(message),
70 | Terms = [ message("Systen","Message added"), #button{postback=hello} ],
71 | wf:wire("$('#message').focus(); $('#message').select(); "),
72 | Pid ! {message, Username, Message}.
73 |
74 | chat_loop() ->
75 | receive
76 | {message, Username, Message} ->
77 | error_logger:info_msg("Comet received : ~p",[{Username,Message}]),
78 | Terms = message(Username,Message),
79 | wf:insert_top(<<"history">>, Terms),
80 | wf:send(lobby,{add,{Username,Message}}),
81 | wf:flush(room);
82 | Unknown -> error_logger:info_msg("Unknown Looper Message ~p in Pid: ~p",[Unknown,self()])
83 | end, chat_loop().
84 |
85 |
--------------------------------------------------------------------------------
/apps/web/src/account.erl:
--------------------------------------------------------------------------------
1 | -module(account).
2 | -compile(export_all).
3 | -include_lib("n2o/include/wf.hrl").
4 | -include_lib("kvs/include/user.hrl").
5 | -include_lib("nitro/include/nitro.hrl").
6 |
7 |
8 | main() ->
9 | case wf:user() of undefined -> wf:redirect("/login"); _ -> [#dtl{file = wf:cache(mode), ext="dtl",bindings=[{title,<<"Account">>},{body,body()}]}] end.
10 |
11 | body() -> index:header() ++ [
12 | #section{id=content, body=
13 | #panel{class=[container], body=
14 | #panel{class=[row, dashboard], body=[
15 | #panel{class=[span3], body=dashboard:sidebar_menu(account)},
16 | #panel{class=[span9], body=[
17 | dashboard:section(profile_info(wf:user()), "icon-user"),
18 | dashboard:section(ballance(wf:user()), "icon-ok-sign"),
19 | dashboard:section(payments(wf:user()), "icon-list") ]} ]} } }
20 | ] ++ index:footer().
21 |
22 | profile_info(U) ->
23 | {{Y, M, D}, _} = calendar:now_to_datetime(U#user.register_date),
24 | RegDate = io_lib:format("~p ~s ~p", [D, element(M, {"Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"}), Y]),
25 | Mailto = if U#user.email==undefined -> []; true-> iolist_to_binary(["mailto:", U#user.email]) end,
26 | [
27 | #h3{class=["text-left"], body= <<"Profile">>},
28 | #panel{class=["row-fluid"], body=[
29 | #panel{class=[span4, "dashboard-img-wrapper"], body=
30 | #panel{class=["dashboard-img"], body=
31 | #image{class=[], alt="",
32 | image = case U#user.images of undefined -> undefined;
33 | Avatar -> re:replace(Avatar, <<"_normal">>, <<"">>, [{return, list}]) ++
34 | "?sz=180&width=180&height=180&s=180" end,
35 | width= <<"180px">>, height= <<"180px">> }} },
36 | #panel{class=[span8, "profile-info-wrapper"], body=
37 | #panel{class=["form-inline", "profile-info"], body=[
38 | #panel{body=[#label{body= <<"Name:">>}, #b{body= U#user.display_name}]},
39 | #panel{show_if=U#user.email=/=undefined, body=[#label{body= <<"Mail:">>}, #link{url= Mailto, body=#strong{body= U#user.email}}]},
40 | #panel{body=[#label{body= <<"Member since ">>}, #strong{body= RegDate}]},
41 | #b{class=["text-success"], body= <<"Active">>} ]}}]}].
42 |
43 | ballance(User) -> [
44 | #h3{body= <<"Balance">>},
45 | #panel{class=["row-fluid"], body=[
46 | #panel{class=[span4, "text-center", "ballance-label"], body=[
47 | #b{class=[positive], body= <<"+30.0">>},
48 | #span{body= <<"Credit">>}]},
49 | #panel{class=[span3, "text-center", "ballance-label"], body=[
50 | #b{class=[negative], body= <<"-0.82">>},
51 | #span{body= <<"Debit">>}]},
52 | #panel{class=[span4, "text-center"], body=[#link{class=[btn, "btn-large", "btn-success", "btn-charge"], body= <<"Charge">>}]},
53 | #panel{class=[span1]}]}].
54 |
55 | payments(User) -> [
56 | #h3{body= <<"Payments">>},
57 | #table{class=[table, "table-hover", payments], body=[[
58 | #tr{cells= [
59 | #td{body= <<"27 Jun 2013">>},
60 | #td{body= <<"Charge">>},
61 | #td{body= <<"-$0.82">>},
62 | #td{body=#link{body= <<"sncn1">>}} ]},
63 | #tr{cells= [
64 | #td{body= <<"26 Jun 2013">>},
65 | #td{body= <<"Payment">>},
66 | #td{body= <<"$30">>},
67 | #td{body= <<"">>} ]} ]]} ].
68 |
69 | api_event(Name,Tag,Term) -> error_logger:info_msg("dashboard Name ~p, Tag ~p, Term ~p",[Name,Tag,Term]).
70 | event(init) -> [];
71 | event({counter,C}) -> wf:update(onlinenumber,wf:to_list(C));
72 | event(U) -> wf:info("Unknown Event: ~p",[U]).
73 |
--------------------------------------------------------------------------------
/apps/web/priv/static/appstore/common.less:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top:0px;
3 | @media(min-width: 980px){padding-top:80px;}
4 | }
5 | @media(min-width: 980px){ .sky-navbar{ &.navbar .nav > li > a {padding:29px 10px 31px; &.avatar{padding: 10px 10px 10px;} } } }
6 | @media(max-width: 979px){ .sky-navbar { &.navbar .nav > li > a { &.avatar{padding-top:5px;} } } }
7 | .sky-navbar{
8 | & .brand {
9 | font-weight: 800;
10 | font-size: 30px;
11 | line-height: 30px;
12 | padding: 23px 20px 27px;
13 | margin-top: 0;
14 | margin-bottom: 0;
15 | color: #555555;
16 | text-shadow: 0 1px 0 white;
17 |
18 | & a{color: #555555;}
19 | }
20 |
21 | &.navbar-inverse{
22 | & .brand{& a { color: inherit;}}
23 | & .nav > li > a {padding: 23px 20px 27px;}
24 | }
25 |
26 | & .navbar-inner {
27 | background: @white;
28 | background: rgba(255, 255, 255, 0.95);
29 | //.box-shadow(none);
30 | border-bottom: 1px solid #e9e9e9;
31 | }
32 |
33 | & .btn-navbar {margin-top:15px;}
34 |
35 | & .account-link {
36 | position: absolute;
37 | top: 50%;
38 | right: -35px;
39 | margin: -17px 0 0;
40 | z-index: 10000;
41 | font-size: 13px;
42 | .border-radius(50%);
43 | width: 2.5em;
44 | height: 2.5em;
45 | padding: 0;
46 | }
47 |
48 | & .avatar{
49 | max-height:79px;
50 | & img { margin:0 5px;}
51 | }
52 | }
53 |
54 | .n2o-modal-body {
55 | position: relative;
56 | padding: 15px;
57 | overflow-y: auto;
58 | }
59 |
60 | .tag(@size, @color){
61 | @fontSize: @baseFontSize * @size;
62 | font-size: @fontSize;
63 | line-height: @fontSize + 4;
64 | color: @color;
65 |
66 | a {
67 | color:@color;
68 |
69 | &:hover{
70 | color: @linkColorHover;
71 | }
72 | }
73 | }
74 |
75 | .tag-mini {.tag(1, @grayLight);}
76 | .tag-small{.tag(1.2, @grayLight);}
77 | .tag-large{.tag(2.3, @grayLight);}
78 | .tag-huge {.tag(3.7, @grayLight);}
79 |
80 | .label,
81 | .badge {
82 | &-transparent, &-transperent[href]{
83 | background-color: transparent;
84 | color: currentColor;
85 | top:0 !important;
86 | text-shadow:none;
87 | }
88 | }
89 |
90 | #mainfooter{
91 | background: #333333;
92 | color: #e9e9e9;
93 | text-shadow: 1px 1px 1px #222222;
94 | .box-shadow(0 3px 3px rgba(0,0,0,.25));
95 | text-shadow:1px 1px 1px #222222;
96 | padding: 0px;
97 | }
98 |
99 | .footer-banner{
100 | background-color: @darkAzure;
101 | color: @white;
102 | text-shadow:0 0 0;
103 | & a{color:@white;&:hover{color:@white;}}
104 | }
105 |
106 | .sky-footer{
107 | padding: 0;
108 | margin: 0;
109 | position: relative;
110 |
111 | & .row-fluid [class*="span"] {
112 | padding:30px;
113 | }
114 |
115 | & small {
116 | color: #e9e9e9;
117 | font-style: italic;
118 | text-indent:0;
119 | display:block;
120 | }
121 | & .icons {
122 | text-indent: -1em;
123 | margin-left: 2em;
124 | list-style-type: none;
125 | }
126 |
127 | & h3 {text-transform: uppercase}
128 | }
129 |
130 | .chat {
131 | min-height:600px;
132 | }
133 |
134 | .chat-rooms {
135 | background-color: #f5f5f5;
136 | & li {
137 | border-top: 1px dashed #454;
138 | padding:10px 20px 10px 20px;
139 | font-weight: bold;
140 | & a { color: #34495e;}
141 | }
142 | }
143 |
144 | .history{
145 | background-color: #f5f5f5;
146 |
147 | & .media {
148 | border-top: 1px dashed #454;
149 | margin-top: 0px;
150 | padding:10px;
151 |
152 | & .media-object {background-color: darkblue;}
153 | }
154 |
155 | }
156 |
157 | #n2ostatus{
158 | word-break: break-word;
159 | }
--------------------------------------------------------------------------------
/apps/web/src/products.erl:
--------------------------------------------------------------------------------
1 | -module(products).
2 | -compile(export_all).
3 | -include_lib("web/include/wf.hrl").
4 | -include_lib("kvs/include/user.hrl").
5 | -include_lib("kvs/include/product.hrl").
6 | -include("records.hrl").
7 |
8 | -define(PAGE_SIZE, case wf:session(page_size) of list -> 6; _ -> 8 end).
9 |
10 | main()->
11 | wf:session(products, [product:product(I, 2) || I <- lists:seq(1,20)] ),
12 | wf:session(page_size, list),
13 | #dtl{file=wf:cache(mode), ext="dtl",bindings=[{title,<<"products">>},{body, body()}]}.
14 |
15 | body()->
16 | % wf:wire("$('#listsw').on('click', function(){ $('#products').removeClass('items-grid').addClass('items-list').children('li').addClass('span3').removeClass('span4'); });"),
17 | % wf:wire("$('#gridsw').on('click', function(){ $('#products').removeClass('items-list').addClass('items-grid').children('li').addClass('span4').removeClass('span3'); });"),
18 | index:header() ++ [
19 | #panel{id=content, body=[
20 | #section{class=[section, alt], body=#panel{class=[container], body=
21 | #carousel{class=["product-carousel"], items=[#product_figure{product=product:product(I,1)} || I <- lists:seq(1,2)] }}},
22 | #section{class=[section], body=[
23 | #panel{class=[container], body=[
24 | #panel{class=["page-header", "thumbnail-filters"], body=[#h1{body=[
25 | <<"Categories">>,
26 | #small{body=[[<<" / ">>, #link{data_fields=[{<<"data-filter">>, C}], body=C}] || {C, _D} <- categories() ]}
27 | ]} ]},
28 | #list{id=products, class=[thumbnails, bordered, "thumbnail-list", products, "items-list"], body=list_products(1)},
29 | #panel{class=["pagination pagination-centered"],body=[ #list{id=pagination, body=pagination(1)} ]}
30 | ]}
31 | ]},
32 | #section{class=[section, alt], body=#panel{class=[container], body=[
33 | #panel{class=["hero-unit", "text-center"], body=[
34 | #h1{body= <<"Got a question?">>},
35 | #p{body= <<"want to work with us to move your bussines to the next level? Well, dont be afraid">>},
36 | #link{class=[btn, "btn-large", "btn-info"], body= <<"contact us">>}
37 | ]}
38 | ]}}
39 | ]}] ++ index:footer().
40 |
41 | categories() ->
42 | [{<<"Action">>, <<"abababab">>}, {<<"Shooting">>, <<"shooting">>}, {<<"Sports">>, <<"bla-bla">>}, {<<"Role-Playing">>, <<"abababab">>}, {<<"Strategy">>, <<"bla-bla">>}].
43 |
44 | list_products(Page) -> [#li{class=[span4], body=#product_figure{product=P}} || P <- lists:sublist(wf:session(products), (Page-1) * ?PAGE_SIZE + 1, ?PAGE_SIZE)].
45 |
46 | pagination(Page)->
47 | PageCount = (length(wf:session(products)) -1 ) div ?PAGE_SIZE + 1,
48 | [#li{class=[if Page==1-> "disabled"; true->[] end, "previous"],body=#link{class=["fui-arrow-left"], body= <<"‹">>, postback={page, 1}, url="javascript:void(0);" }},
49 | [#li{class=if I==Page -> active;true->[] end,body=#link{id="pglink"++integer_to_list(I),body=integer_to_list(I), postback={page, I}, url="javascript:void(0);" }}
50 | || I <- lists:seq(1, PageCount)],
51 | #li{class=[if PageCount==Page -> "disabled";true->[] end,"next"], body=#link{class=["fui-arrow-right"], body= <<"›">>, postback={page, PageCount},url="javascript:void(0);" }} ].
52 |
53 | event(init) -> [];
54 | event({counter,C}) -> wf:update(onlinenumber,wf:to_list(C));
55 | event({page, Page})->
56 | wf:update(pagination, pagination(Page)),
57 | wf:update(products, list_products(Page));
58 | event({product, Id})-> wf:redirect("/product?id=" ++ Id);
59 | event(to_list)->
60 | wf:session(page_size, list),
61 | wf:update(products, list_products(1)),
62 | wf:update(pagination, pagination(1));
63 | event(to_grid)->
64 | wf:session(page_size, grid),
65 | wf:update(products, list_products(1)),
66 | wf:update(pagination, pagination(1));
67 |
68 | event(Event) -> error_logger:info_msg("Page event: ~p", [Event]), [].
69 |
70 | api_event(Name,Tag,Term) -> error_logger:info_msg("Name ~p, Tag ~p, Term ~p",[Name,Tag,Term]).
71 |
--------------------------------------------------------------------------------
/apps/web/priv/templates/login.dtl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{title}}
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
63 |
64 |
65 |
66 |
67 | {{sdk}}
68 |
69 |
70 |
71 |
72 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/rels/web/files/nodetool:
--------------------------------------------------------------------------------
1 | %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
2 | %% ex: ft=erlang ts=4 sw=4 et
3 | %% -------------------------------------------------------------------
4 | %%
5 | %% nodetool: Helper Script for interacting with live nodes
6 | %%
7 | %% -------------------------------------------------------------------
8 |
9 | main(Args) ->
10 | ok = start_epmd(),
11 | %% Extract the args
12 | {RestArgs, TargetNode} = process_args(Args, [], undefined),
13 |
14 | %% See if the node is currently running -- if it's not, we'll bail
15 | case {net_kernel:hidden_connect_node(TargetNode), net_adm:ping(TargetNode)} of
16 | {true, pong} ->
17 | ok;
18 | {_, pang} ->
19 | io:format("Node ~p not responding to pings.\n", [TargetNode]),
20 | halt(1)
21 | end,
22 |
23 | case RestArgs of
24 | ["ping"] ->
25 | %% If we got this far, the node already responsed to a ping, so just dump
26 | %% a "pong"
27 | io:format("pong\n");
28 | ["stop"] ->
29 | io:format("~p\n", [rpc:call(TargetNode, init, stop, [], 60000)]);
30 | ["restart"] ->
31 | io:format("~p\n", [rpc:call(TargetNode, init, restart, [], 60000)]);
32 | ["reboot"] ->
33 | io:format("~p\n", [rpc:call(TargetNode, init, reboot, [], 60000)]);
34 | ["rpc", Module, Function | RpcArgs] ->
35 | case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function),
36 | [RpcArgs], 60000) of
37 | ok ->
38 | ok;
39 | {badrpc, Reason} ->
40 | io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]),
41 | halt(1);
42 | _ ->
43 | halt(1)
44 | end;
45 | ["rpcterms", Module, Function, ArgsAsString] ->
46 | case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function),
47 | consult(ArgsAsString), 60000) of
48 | {badrpc, Reason} ->
49 | io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]),
50 | halt(1);
51 | Other ->
52 | io:format("~p\n", [Other])
53 | end;
54 | Other ->
55 | io:format("Other: ~p\n", [Other]),
56 | io:format("Usage: nodetool {ping|stop|restart|reboot}\n")
57 | end,
58 | net_kernel:stop().
59 |
60 | process_args([], Acc, TargetNode) ->
61 | {lists:reverse(Acc), TargetNode};
62 | process_args(["-setcookie", Cookie | Rest], Acc, TargetNode) ->
63 | erlang:set_cookie(node(), list_to_atom(Cookie)),
64 | process_args(Rest, Acc, TargetNode);
65 | process_args(["-name", TargetName | Rest], Acc, _) ->
66 | ThisNode = append_node_suffix(TargetName, "_maint_"),
67 | {ok, _} = net_kernel:start([ThisNode, longnames]),
68 | process_args(Rest, Acc, nodename(TargetName));
69 | process_args(["-sname", TargetName | Rest], Acc, _) ->
70 | ThisNode = append_node_suffix(TargetName, "_maint_"),
71 | {ok, _} = net_kernel:start([ThisNode, shortnames]),
72 | process_args(Rest, Acc, nodename(TargetName));
73 | process_args([Arg | Rest], Acc, Opts) ->
74 | process_args(Rest, [Arg | Acc], Opts).
75 |
76 |
77 | start_epmd() ->
78 | [] = os:cmd(epmd_path() ++ " -daemon"),
79 | ok.
80 |
81 | epmd_path() ->
82 | ErtsBinDir = filename:dirname(escript:script_name()),
83 | Name = "epmd",
84 | case os:find_executable(Name, ErtsBinDir) of
85 | false ->
86 | case os:find_executable(Name) of
87 | false ->
88 | io:format("Could not find epmd.~n"),
89 | halt(1);
90 | GlobalEpmd ->
91 | GlobalEpmd
92 | end;
93 | Epmd ->
94 | Epmd
95 | end.
96 |
97 |
98 | nodename(Name) ->
99 | case string:tokens(Name, "@") of
100 | [_Node, _Host] ->
101 | list_to_atom(Name);
102 | [Node] ->
103 | [_, Host] = string:tokens(atom_to_list(node()), "@"),
104 | list_to_atom(lists:concat([Node, "@", Host]))
105 | end.
106 |
107 | append_node_suffix(Name, Suffix) ->
108 | case string:tokens(Name, "@") of
109 | [Node, Host] ->
110 | list_to_atom(lists:concat([Node, Suffix, os:getpid(), "@", Host]));
111 | [Node] ->
112 | list_to_atom(lists:concat([Node, Suffix, os:getpid()]))
113 | end.
114 |
115 |
116 | %%
117 | %% Given a string or binary, parse it into a list of terms, ala file:consult/0
118 | %%
119 | consult(Str) when is_list(Str) ->
120 | consult([], Str, []);
121 | consult(Bin) when is_binary(Bin)->
122 | consult([], binary_to_list(Bin), []).
123 |
124 | consult(Cont, Str, Acc) ->
125 | case erl_scan:tokens(Cont, Str, 0) of
126 | {done, Result, Remaining} ->
127 | case Result of
128 | {ok, Tokens, _} ->
129 | {ok, Term} = erl_parse:parse_term(Tokens),
130 | consult([], Remaining, [Term | Acc]);
131 | {eof, _Other} ->
132 | lists:reverse(Acc);
133 | {error, Info, _} ->
134 | {error, Info}
135 | end;
136 | {more, Cont1} ->
137 | consult(Cont1, eof, Acc)
138 | end.
139 |
--------------------------------------------------------------------------------
/apps/web/src/feed.erl:
--------------------------------------------------------------------------------
1 | -module(feed).
2 | -compile(export_all).
3 | -include_lib("n2o/include/wf.hrl").
4 | -include_lib("kvs/include/product.hrl").
5 | -include_lib("kvs/include/comment.hrl").
6 | -include_lib("kvs/include/feed.hrl").
7 | -include_lib("nitro/include/nitro.hrl").
8 |
9 | -include("records.hrl").
10 |
11 | -define(PAGE_SIZE, 4).
12 |
13 | main() -> #dtl{file=wf:cache(mode), ext="dtl",bindings=[{title,<<"feed">>},{body, body()}]}.
14 |
15 | body() ->
16 | % Qid = wf:qs(<<"id">>),
17 | index:header()++[
18 | #section{class=[section, alt], body=#panel{class=[container], body=[
19 | #panel{class=["hero-unit"], body=[
20 | #h1{body= <<"Product feed">>},
21 | #p{body= <<"Thats a single review page">>}
22 | ]}
23 | ]}},
24 |
25 | #section{class=[section], body=#panel{class=[container], body=#panel{class=["row-fluid"], body=[
26 | #panel{class=[span9], body=[
27 | product:blog_post_expanded(),
28 | #panel{class=[comments], body=[
29 | #h3{body= <<"comments">>},
30 | product:comment([product:comment(), product:comment([product:comment()])]),
31 | product:comment()
32 | ]},
33 | #panel{class=["comments-form"], body=[
34 | #h3{class=["comments-form"], body= <<"Add your comment">>},
35 | #panel{class=["form-horizontal"], body=[
36 | #fieldset{body=[
37 | #panel{class=["control-group"], body=[
38 | #label{class=["control-label"], for="name", body= <<"Name">>},
39 | #panel{class=["controls"], body=[
40 | #textbox{id=name, class=["input-xxlarge"]}
41 | ]}
42 | ]},
43 | #panel{class=["control-group"], body=[
44 | #label{class=["control-label"], for="email", body= <<"Email">>},
45 | #panel{class=["controls"], body=[
46 | #textbox{id=email, class=["input-xxlarge"]}
47 | ]}
48 | ]},
49 | #panel{class=["control-group"], body=[
50 | #label{class=["control-label"], for="message", body= <<"Your message">>},
51 | #panel{class=["controls"], body=[
52 | #textarea{id=message, class=["input-xxlarge"]}
53 | ]}
54 | ]},
55 | #panel{class=["control-group"], body=[
56 | #panel{class=["controls"], body=[
57 | #button{class=[btn, "btn-info", "btn-large"], body= <<"send">>}
58 | ]}
59 | ]}
60 | ]}
61 | ]}
62 | ]}
63 | ]},
64 | #aside{class=[span3, sidebar], body=[
65 | #panel{class=["sidebar-widget"], body=[
66 | #h2{class=["sidebar-header"], body= <<"Search">>},
67 | #panel{class=["input-append"], body=[
68 | #textbox{id="search-button"},
69 | #button{class=[btn], body= <<"Go!">>}
70 | ]}
71 | ]},
72 | #panel{class=["sidebar-widget"], body=[
73 | #h2{class=["sidebar-header"], body= <<"About SmartBiz">>},
74 | #p{body= <<"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.">>}
75 | ]},
76 | #panel{class=["sidebar-widget"], body=[
77 | #h2{class=["sidebar-header"], body= <<"Recent posts">>},
78 | #list{class=[unstyled], body=[
79 | #li{body=[#h4{body=#link{body = <<"Lorem ipsum dolor sit">>}},
80 | #p{body=#small{body= <<"November 12, 2012">>}}]},
81 | #li{body=[#h4{body=#link{body = <<"Ed do eiusmod tempor">>}},
82 | #p{body=#small{body= <<"August 12, 2012">>}}]},
83 | #li{body=[#h4{body=#link{body = <<"Incididunt ut labore">>}},
84 | #p{body=#small{body= <<"June 12, 2012">>}}]},
85 | #li{body=[#h4{body=#link{body = <<"Quis nostrud exercitation">>}},
86 | #p{body=#small{body= <<"June 12, 2012">>}}]},
87 | #li{body=[#h4{body=#link{body = <<"Quis nostrud exercitation">>}},
88 | #p{body=#small{body= <<"June 12, 2012">>}}]}
89 | ]}
90 | ]},
91 | #panel{class=["sidebar-widget"], body=[
92 | #h2{class=["sidebar-header"], body= <<"Popular posts">>},
93 | #list{class=[unstyled], body=[
94 | #li{body=[#h4{body=#link{body = <<"Lorem ipsum dolor sit">>}},
95 | #p{body=#small{body= <<"November 12, 2012">>}}]},
96 | #li{body=[#h4{body=#link{body = <<"Ed do eiusmod tempor">>}},
97 | #p{body=#small{body= <<"August 12, 2012">>}}]},
98 | #li{body=[#h4{body=#link{body = <<"Quis nostrud exercitation">>}},
99 | #p{body=#small{body= <<"June 12, 2012">>}}]}
100 | ]}
101 | ]}
102 | ]}
103 | ]}}}
104 |
105 | ]++index:footer().
106 |
107 | title()-> <<"Review title">>.
108 |
109 | description(Id, Description) -> [
110 | #panel{id="description"++Id, body=[
111 | #panel{class=[collapse, in], body= <<"Description head">>},
112 | #panel{id=Id, class=collapse, body= Description}
113 | ]},
114 | #button{class=[btn, "btn-link"], data_fields=[
115 | {<<"data-toggle">>, <<"collapse">>},
116 | {<<"data-target">>, list_to_binary("#"++Id) },
117 | {<<"data-parent">>, list_to_binary("#description"++Id)}], body= <<"Read...">>}].
118 |
119 | list_medias(C)->
120 | {Cid, Fid} = C#comment.id,
121 | [#feed_media{media=M, target=wf:temp_id(), fid = Fid, cid = Cid} || M <- C#comment.media].
122 |
123 | image_media(_Media)-> element_image:render_element(#image{image= "/static/img/item-bg.png"}).
124 |
125 | event(init) -> [];
126 | event({counter,C}) -> wf:update(onlinenumber,wf:to_list(C));
127 | event(Event) -> error_logger:info_msg("Page event: ~p", [Event]), [].
128 |
129 | api_event(Name,Tag,Term) -> error_logger:info_msg("Name ~p, Tag ~p, Term ~p",[Name,Tag,Term]), event(change_me).
130 |
131 | control_event(Id, Tag) ->
132 | error_logger:info_msg("Tinymce editor control event ~p: ~p", [Id, Tag]),
133 | Ed = wf:q(mcecontent),
134 | error_logger:info_msg("Data: ~p", [Ed]),
135 | ok.
--------------------------------------------------------------------------------
/apps/web/priv/static/appstore/products.less:
--------------------------------------------------------------------------------
1 | .products {}
2 |
3 | .product-carousel{
4 | & .carousel-inner{ max-height:500px;}
5 | & .carousel-caption{background:none;}
6 | }
7 |
8 |
9 | .product {
10 | text-decoration:none;
11 | margin: 0 0 24px;
12 | position: relative;
13 | background: #333333;
14 |
15 |
16 | & .product-price{
17 | background: @white;
18 | color: @black;
19 |
20 | &-price{
21 | font-size: 30px;
22 | margin: -10px -20px 0 -20px;
23 | padding: 8px 0 10px;
24 | background-color: #eeeeee;
25 | .box-shadow(0px 0px 10px rgba(153, 153, 153, 0.2) inset);
26 | color: #41b7d8;
27 | text-shadow: 1px 1px 0 white;
28 |
29 | & span {font-weight: normal;}
30 | }
31 |
32 | &-list{
33 | list-style-type: none;
34 | margin: 0 0 20px;
35 | border-bottom: 1px solid white;
36 | .box-shadow(0px 1px 0px #e9e9e9);
37 |
38 | & li {
39 | border-top: 1px solid white;
40 | .box-shadow(0px -1px 0px #e9e9e9 );
41 | padding: 8px;
42 |
43 | &:first-child{
44 | border-color: transparent;
45 | .box-shadow(none);
46 | }
47 | }
48 | }
49 |
50 | &-featured {
51 | background: #41b7d8;
52 | border-color: #238caa;
53 | color: white;
54 | text-shadow: 0px 1px 0px #279ebf;
55 |
56 | & .product-price-price{ text-shadow: 1px 1px 0 white; color: #41b7d8;}
57 | & h3 {
58 | border-bottom: 0 none;
59 | & span{&:after{
60 | display: inline-block;
61 | font-family: "FontAwesome";
62 | content: "\f069";
63 | padding-left: 10px;
64 | }}
65 | }
66 | & .product-price-list{
67 | border-color: #279ebf;
68 | .box-shadow( 0px 1px 0px #6bc7e1);
69 | }
70 | & li {
71 | border-color: #6bc7e1;
72 | .box-shadow( 0px -1px 0px #279ebf);
73 | &:first-child{
74 | border-color: transparent;
75 | .box-shadow(none);
76 | }
77 | }
78 |
79 | &.featured-orange{
80 | background: #f89406;
81 | border-color: #c67605;
82 | color: white;
83 | text-shadow: 0px 1px 0px #c67605;
84 |
85 | & .product-price-price {
86 | text-shadow: 1px 1px 0 white;
87 | color: #f89406;
88 | }
89 |
90 | & h3 {border-bottom: 0 none;}
91 |
92 | & .product-price-list {
93 | border-color: #c67605;
94 | .box-shadow(0px 1px 0px #faa937);
95 | }
96 |
97 | & li {
98 | border-color: #faa937;
99 | .box-shadow(0px -1px 0px #c67605);
100 | &:first-child{
101 | border-color: transparent;
102 | .box-shadow(none);
103 | }
104 | }
105 | }
106 | }
107 | }
108 |
109 | //product inside the featured carousel
110 | .product-carousel .carousel-inner & {
111 |
112 | & img {max-height:500px; .transition(all .2s); &:hover{opacity:.4;}}
113 |
114 | & .product-caption {
115 | position: absolute;
116 | top: 50%;
117 | margin-top:-50px;
118 | left: 0;
119 | margin-left:0;
120 | .transition(all .2s);
121 |
122 | & .product-title {
123 | position: absolute;
124 | top: 0;
125 | margin-top:0px;
126 | .transition(all .2s);
127 | max-width: 600px;
128 | max-height: 200px;
129 |
130 | & p {
131 | max-height: 150px;
132 | overflow:hidden;
133 | }
134 | & span {
135 | display: inline-block;
136 | background: @white;
137 | background: rgba(255, 255, 255, 0.8);
138 | color: @black;
139 | padding: 5px 10px;
140 | text-shadow: 1px 1px 1px white;
141 | margin-top: 1px;
142 | }
143 | }
144 |
145 | & .product-price {
146 | @media (min-width: 768px){
147 | position: absolute;
148 | top:0;
149 | margin-top: -115px;
150 | left:70%;
151 | }
152 | @media (max-width: 767px) { display:none;}
153 | @media (min-width: 768px) and (max-width: 979px) {
154 | & h3 span:after{ padding-left:0;}
155 | }
156 | }
157 | }
158 | }
159 |
160 | // product inside grid view
161 | .items-grid & {
162 | & img {}
163 | & .product-price {display:none;}
164 | & .product-caption{
165 | position:absolute;
166 | top:0; left:0;
167 | margin-top:0;
168 | }
169 | & .product-title {
170 | position: absolute;
171 | top: 50%;
172 | margin-top:40px;
173 | .transition(all .2s);
174 |
175 | & .badges {display:none;}
176 | }
177 | }
178 |
179 | // product inside list view
180 | .items-list & {
181 | // width:100%;
182 | // overflow: hidden;
183 |
184 | &:before{
185 | // display: inline-block;vertical-align: middle;
186 | // content: "";
187 | // padding-top: 75%
188 | }
189 |
190 | & img {
191 | // width:100%;
192 | // display: inline-block;vertical-align: middle;
193 | // padding-left: 100%;
194 | // margin: -999em -100%;
195 | }
196 |
197 | & .product-caption{ position:absolute; top:0; left:0;}
198 | & .product-title{
199 | position:absolute;
200 | top:50%;
201 | margin-top:80px;
202 | overflow:hidden;
203 | max-height:100px;
204 | line-height:41px;
205 | & .badges{display:none;}
206 | }
207 | & .product-price{display:none;}
208 | }
209 |
210 | }
211 |
212 | .product {
213 | .product-view & {
214 | & .product-controls, & .product-name, & .product-price, & .product-description {
215 | width:100%;
216 | margin-left:0;
217 | }
218 |
219 | & .product-image {
220 | width:300px;
221 | img {max-width:290px;max-height:290px;}
222 | }
223 | }
224 | }
225 |
226 | .product-review1 {
227 | background: @reviewBackground;
228 | border: 1px solid #ddd;
229 | .border-radius(@baseBorderRadius);
230 | .box-shadow(0 1px 3px rgba(0,0,0,.055));
231 | padding: 5px;
232 | margin-left:0 !important;
233 |
234 | & .review-date {display: block;}
235 |
236 | & .review-author {
237 | text-align:center;
238 |
239 | & .avatar {
240 | max-width:100px;
241 | max-height:100px;
242 | }
243 | }
244 |
245 | }
246 |
247 | .brief{
248 | padding: 15px 0;
249 | }
250 |
251 |
--------------------------------------------------------------------------------
/rels/web/files/node:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # -*- tab-width:4;indent-tabs-mode:nil -*-
3 | # ex: ts=4 sw=4 et
4 |
5 | RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd)
6 |
7 | CALLER_DIR=$PWD
8 |
9 | RUNNER_BASE_DIR=${RUNNER_SCRIPT_DIR%/*}
10 | RUNNER_ETC_DIR=$RUNNER_BASE_DIR/etc
11 | # Note the trailing slash on $PIPE_DIR/
12 | PIPE_DIR=/tmp/$RUNNER_BASE_DIR/
13 | RUNNER_USER=
14 |
15 | # Make sure this script is running as the appropriate user
16 | if [ ! -z "$RUNNER_USER" ] && [ `whoami` != "$RUNNER_USER" ]; then
17 | exec sudo -u $RUNNER_USER -i $0 $@
18 | fi
19 |
20 | # Identify the script name
21 | SCRIPT=`basename $0`
22 |
23 | # Parse out release and erts info
24 | START_ERL=`cat $RUNNER_BASE_DIR/releases/start_erl.data`
25 | ERTS_VSN=${START_ERL% *}
26 | APP_VSN=${START_ERL#* }
27 |
28 | # Use $CWD/vm.args if exists, otherwise releases/APP_VSN/vm.args, or else etc/vm.args
29 | if [ -e "$CALLER_DIR/vm.args" ]; then
30 | VMARGS_PATH=$CALLER_DIR/vm.args
31 | USE_DIR=$CALLER_DIR
32 | else
33 | USE_DIR=$RUNNER_BASE_DIR
34 | if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" ]; then
35 | VMARGS_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args"
36 | else
37 | VMARGS_PATH="$RUNNER_ETC_DIR/vm.args"
38 | fi
39 | fi
40 |
41 | RUNNER_LOG_DIR=$USE_DIR/log
42 | # Make sure log directory exists
43 | mkdir -p $RUNNER_LOG_DIR
44 |
45 | # Use releases/VSN/sys.config if it exists otherwise use etc/app.config
46 | if [ -e "$USE_DIR/sys.config" ]; then
47 | CONFIG_PATH="$USE_DIR/sys.config"
48 | else
49 | if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" ]; then
50 | CONFIG_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config"
51 | else
52 | CONFIG_PATH="$RUNNER_ETC_DIR/app.config"
53 | fi
54 | fi
55 |
56 | # Extract the target node name from node.args
57 | NAME_ARG=`egrep '^-s?name' $VMARGS_PATH`
58 | if [ -z "$NAME_ARG" ]; then
59 | echo "vm.args needs to have either -name or -sname parameter."
60 | exit 1
61 | fi
62 |
63 | # Extract the name type and name from the NAME_ARG for REMSH
64 | REMSH_TYPE=`echo $NAME_ARG | awk '{print $1}'`
65 | REMSH_NAME=`echo $NAME_ARG | awk '{print $2}'`
66 |
67 | # Note the `date +%s`, used to allow multiple remsh to the same node transparently
68 | REMSH_NAME_ARG="$REMSH_TYPE remsh`date +%s`@`echo $REMSH_NAME | awk -F@ '{print $2}'`"
69 | REMSH_REMSH_ARG="-remsh $REMSH_NAME"
70 |
71 | # Extract the target cookie
72 | COOKIE_ARG=`grep '^-setcookie' $VMARGS_PATH`
73 | if [ -z "$COOKIE_ARG" ]; then
74 | echo "vm.args needs to have a -setcookie parameter."
75 | exit 1
76 | fi
77 |
78 | # Make sure CWD is set to the right dir
79 | cd $USE_DIR
80 |
81 | # Make sure log directory exists
82 | mkdir -p $USE_DIR/log
83 |
84 |
85 | # Add ERTS bin dir to our path
86 | ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin
87 |
88 | # Setup command to control the node
89 | NODETOOL="$ERTS_PATH/escript $ERTS_PATH/nodetool $NAME_ARG $COOKIE_ARG"
90 |
91 | # Setup remote shell command to control node
92 | REMSH="$ERTS_PATH/erl $REMSH_NAME_ARG $REMSH_REMSH_ARG $COOKIE_ARG"
93 |
94 | # Check the first argument for instructions
95 | case "$1" in
96 | start|start_boot)
97 | # Make sure there is not already a node running
98 | RES=`$NODETOOL ping`
99 | if [ "$RES" = "pong" ]; then
100 | echo "Node is already running!"
101 | exit 1
102 | fi
103 | case "$1" in
104 | start)
105 | shift
106 | START_OPTION="console"
107 | HEART_OPTION="start"
108 | ;;
109 | start_boot)
110 | shift
111 | START_OPTION="console_boot"
112 | HEART_OPTION="start_boot"
113 | ;;
114 | esac
115 | RUN_PARAM=$(printf "\'%s\' " "$@")
116 | HEART_COMMAND="$RUNNER_BASE_DIR/bin/$SCRIPT $HEART_OPTION $RUN_PARAM"
117 | export HEART_COMMAND
118 | mkdir -p $PIPE_DIR
119 | $ERTS_PATH/run_erl -daemon $PIPE_DIR $RUNNER_LOG_DIR "exec $RUNNER_BASE_DIR/bin/$SCRIPT $START_OPTION $RUN_PARAM" 2>&1
120 | ;;
121 |
122 | stop)
123 | # Wait for the node to completely stop...
124 | case `uname -s` in
125 | Linux|Darwin|FreeBSD|DragonFly|NetBSD|OpenBSD)
126 | # PID COMMAND
127 | PID=`ps ax -o pid= -o command=|\
128 | grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $1}'`
129 | ;;
130 | SunOS)
131 | # PID COMMAND
132 | PID=`ps -ef -o pid= -o args=|\
133 | grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $1}'`
134 | ;;
135 | CYGWIN*)
136 | # UID PID PPID TTY STIME COMMAND
137 | PID=`ps -efW|grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $2}'`
138 | ;;
139 | esac
140 | $NODETOOL stop
141 | ES=$?
142 | if [ "$ES" -ne 0 ]; then
143 | exit $ES
144 | fi
145 | while `kill -0 $PID 2>/dev/null`;
146 | do
147 | sleep 1
148 | done
149 | ;;
150 |
151 | restart)
152 | ## Restart the VM without exiting the process
153 | $NODETOOL restart
154 | ES=$?
155 | if [ "$ES" -ne 0 ]; then
156 | exit $ES
157 | fi
158 | ;;
159 |
160 | reboot)
161 | ## Restart the VM completely (uses heart to restart it)
162 | $NODETOOL reboot
163 | ES=$?
164 | if [ "$ES" -ne 0 ]; then
165 | exit $ES
166 | fi
167 | ;;
168 |
169 | ping)
170 | ## See if the VM is alive
171 | $NODETOOL ping
172 | ES=$?
173 | if [ "$ES" -ne 0 ]; then
174 | exit $ES
175 | fi
176 | ;;
177 |
178 | attach)
179 | # Make sure a node IS running
180 | RES=`$NODETOOL ping`
181 | ES=$?
182 | if [ "$ES" -ne 0 ]; then
183 | echo "Node is not running!"
184 | exit $ES
185 | fi
186 |
187 | shift
188 | exec $ERTS_PATH/to_erl $PIPE_DIR
189 | ;;
190 |
191 | remote_console)
192 | # Make sure a node IS running
193 | RES=`$NODETOOL ping`
194 | ES=$?
195 | if [ "$ES" -ne 0 ]; then
196 | echo "Node is not running!"
197 | exit $ES
198 | fi
199 |
200 | shift
201 | exec $REMSH
202 | ;;
203 |
204 | upgrade)
205 | if [ -z "$2" ]; then
206 | echo "Missing upgrade package argument"
207 | echo "Usage: $SCRIPT upgrade {package base name}"
208 | echo "NOTE {package base name} MUST NOT include the .tar.gz suffix"
209 | exit 1
210 | fi
211 |
212 | # Make sure a node IS running
213 | RES=`$NODETOOL ping`
214 | ES=$?
215 | if [ "$ES" -ne 0 ]; then
216 | echo "Node is not running!"
217 | exit $ES
218 | fi
219 |
220 | node_name=`echo $NAME_ARG | awk '{print $2}'`
221 | erlang_cookie=`echo $COOKIE_ARG | awk '{print $2}'`
222 |
223 | $ERTS_PATH/escript $RUNNER_BASE_DIR/bin/install_upgrade.escript $node_name $erlang_cookie $2
224 | ;;
225 |
226 | console|console_clean|console_boot)
227 | # .boot file typically just $SCRIPT (ie, the app name)
228 | # however, for debugging, sometimes start_clean.boot is useful.
229 | # For e.g. 'setup', one may even want to name another boot script.
230 | case "$1" in
231 | console) BOOTFILE=$SCRIPT ;;
232 | console_clean) BOOTFILE=start_clean ;;
233 | console_boot)
234 | shift
235 | BOOTFILE="$1"
236 | shift
237 | ;;
238 | esac
239 | # Setup beam-required vars
240 | ROOTDIR=$RUNNER_BASE_DIR
241 | BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin
242 | EMU=beam
243 | PROGNAME=`echo $0 | sed 's/.*\\///'`
244 | CMD="$BINDIR/erlexec -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE -mode embedded -config $CONFIG_PATH -args_file $VMARGS_PATH"
245 | export EMU
246 | export ROOTDIR
247 | export BINDIR
248 | export PROGNAME
249 |
250 | # Dump environment info for logging purposes
251 | echo "Exec: $CMD" -- ${1+"$@"}
252 | echo "Root: $ROOTDIR"
253 |
254 | # Log the startup
255 | logger -t "$SCRIPT[$$]" "Starting up"
256 |
257 | # Start the VM
258 | exec $CMD -- ${1+"$@"}
259 | ;;
260 |
261 | foreground)
262 | # start up the release in the foreground for use by runit
263 | # or other supervision services
264 |
265 | BOOTFILE=$SCRIPT
266 | FOREGROUNDOPTIONS="-noinput +Bd"
267 |
268 | # Setup beam-required vars
269 | ROOTDIR=$RUNNER_BASE_DIR
270 | BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin
271 | EMU=beam
272 | PROGNAME=`echo $0 | sed 's/.*\///'`
273 | CMD="$BINDIR/erlexec $FOREGROUNDOPTIONS -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE -config $CONFIG_PATH -args_file $VMARGS_PATH"
274 | export EMU
275 | export ROOTDIR
276 | export BINDIR
277 | export PROGNAME
278 |
279 | # Dump environment info for logging purposes
280 | echo "Exec: $CMD" -- ${1+"$@"}
281 | echo "Root: $ROOTDIR"
282 |
283 | # Start the VM
284 | exec $CMD -- ${1+"$@"}
285 | ;;
286 | *)
287 | echo "Usage: $SCRIPT {start|start_boot |foreground|stop|restart|reboot|ping|console|console_clean|console_boot |attach|remote_console|upgrade}"
288 | exit 1
289 | ;;
290 | esac
291 |
292 | exit 0
293 |
--------------------------------------------------------------------------------
/apps/web/priv/static/js/all.min.js:
--------------------------------------------------------------------------------
1 | function atom(o){return{type:"Atom",value:o,toString:function(){return this.value}}}function bin(o){return{type:"Binary",value:o,toString:function(){return"<<'"+this.value+"'>>"}}}function tuple(){return{type:"Tuple",value:arguments,toString:function(){var s="";for(var i=0;i0){throw"BERT: Range: "+OriginalInt}return s}function ltoi(S,Length){var isNegative,i,n,Num=0;isNegative=S.charCodeAt(0)>128;for(i=0;i=0;i--){n=S.charCodeAt(i);if(Num===0){Num=n}else{Num=Num*256+n}}if(isNegative){return Num*-1}return Num}function encode(o){return BERT+en_inner(o)}function en_inner(Obj){if(Obj===undefined)return NIL;var func="en_"+typeof Obj;return eval(func)(Obj)}function en_string(Obj){return STR+itol(Obj.length,2)+Obj}function en_boolean(Obj){if(Obj)return en_inner(atom("true"));else return en_inner(atom("false"))}function en_number(Obj){var s,isi=Obj%1===0;if(!isi){return en_float(Obj)}if(isi&&Obj>=0&&Obj<256){return SINT+itol(Obj,1)}return INT+itol(Obj,4)}function en_float(Obj){var s=Obj.toExponential();while(s.length<31){s+=ZERO}return FLOAT+s}function en_object(Obj){if(Obj.type==="Atom")return en_atom(Obj);if(Obj.type==="Binary")return en_bin(Obj);if(Obj.type==="Tuple")return en_tuple(Obj);if(Obj.constructor.toString().indexOf("Array")!==-1)return en_array(Obj);return en_associative_array(Obj)}function en_atom(Obj){return ATOM+itol(Obj.value.length,2)+Obj.value}function en_bin(Obj){return BINARY+itol(Obj.value.length,4)+Obj.value}function en_tuple(Obj){var i,s="";if(Obj.value.length<256){s+=TUPLE+itol(Obj.value.length,1)}else{s+=LTUPLE+itol(Obj.value.length,4)}for(i=0;idelayMax){delay=delayMax}isClosed=true;setTimeout(function(){init()},delay)}};transport.onerror=transport.onclose;transport.onmessage=function(e){stream.onmessage(e)}}init();this.onopen=function(){};this.oninit=function(){};this.onmessage=function(){};this.ondisconnect=function(){};this.onclose=function(){};this.onheartbeat=function(){return this.send("PING")};this.setURL=function(newURL){url=newURL};this.send=function(data){if(transport)return transport.send(data);else return false};this.close=function(){readyState=CLOSING;if(transport)transport.close()}};return stream}var msg=0;var ws;var utf8={};function addStatus(text){var date=new Date;if(document.getElementById("n2ostatus")){document.getElementById("n2ostatus").innerHTML=document.getElementById("n2ostatus").innerHTML+"E> "+text+" "}}utf8.toByteArray=function(str){var byteArray=[];if(str!==undefined&&str!==null)for(var i=0;i0){var dataView=new DataView(reader.result);var s=dataView.getInt8(0).toString();for(var i=1;i 1) {
68 | text_height = template.size / (ctx.measureText(text).width / width);
69 | }
70 | //Resetting font size if necessary
71 | ctx.font = "bold " + (text_height * ratio) + "px "+font;
72 | ctx.fillText(text, (width / 2), (height / 2), width);
73 | return canvas.toDataURL("image/png");
74 | }
75 |
76 | function render(mode, el, holder, src) {
77 | var dimensions = holder.dimensions,
78 | theme = holder.theme,
79 | text = holder.text ? decodeURIComponent(holder.text) : holder.text;
80 | var dimensions_caption = dimensions.width + "x" + dimensions.height;
81 | theme = (text ? extend(theme, { text: text }) : theme);
82 | theme = (holder.font ? extend(theme, {font: holder.font}) : theme);
83 |
84 | var ratio = 1;
85 | if(window.devicePixelRatio && window.devicePixelRatio > 1){
86 | ratio = window.devicePixelRatio;
87 | }
88 |
89 | if (mode == "image") {
90 | el.setAttribute("data-src", src);
91 | el.setAttribute("alt", text ? text : theme.text ? theme.text + " [" + dimensions_caption + "]" : dimensions_caption);
92 |
93 | if(fallback || !holder.auto){
94 | el.style.width = dimensions.width + "px";
95 | el.style.height = dimensions.height + "px";
96 | }
97 |
98 | if (fallback) {
99 | el.style.backgroundColor = theme.background;
100 |
101 | }
102 | else{
103 | el.setAttribute("src", draw(ctx, dimensions, theme, ratio));
104 | }
105 | } else {
106 | if (!fallback) {
107 | el.style.backgroundImage = "url(" + draw(ctx, dimensions, theme, ratio) + ")";
108 | el.style.backgroundSize = dimensions.width+"px "+dimensions.height+"px";
109 | }
110 | }
111 | };
112 |
113 | function fluid(el, holder, src) {
114 | var dimensions = holder.dimensions,
115 | theme = holder.theme,
116 | text = holder.text;
117 | var dimensions_caption = dimensions.width + "x" + dimensions.height;
118 | theme = (text ? extend(theme, {
119 | text: text
120 | }) : theme);
121 |
122 | var fluid = document.createElement("div");
123 |
124 | fluid.style.backgroundColor = theme.background;
125 | fluid.style.color = theme.foreground;
126 | fluid.className = el.className + " holderjs-fluid";
127 | fluid.style.width = holder.dimensions.width + (holder.dimensions.width.indexOf("%")>0?"":"px");
128 | fluid.style.height = holder.dimensions.height + (holder.dimensions.height.indexOf("%")>0?"":"px");
129 | fluid.id = el.id;
130 |
131 | el.style.width=0;
132 | el.style.height=0;
133 |
134 | if (theme.text) {
135 | fluid.appendChild(document.createTextNode(theme.text))
136 | } else {
137 | fluid.appendChild(document.createTextNode(dimensions_caption))
138 | fluid_images.push(fluid);
139 | setTimeout(fluid_update, 0);
140 | }
141 |
142 | el.parentNode.insertBefore(fluid, el.nextSibling)
143 |
144 | if(window.jQuery){
145 | jQuery(function($){
146 | $(el).on("load", function(){
147 | el.style.width = fluid.style.width;
148 | el.style.height = fluid.style.height;
149 | $(el).show();
150 | $(fluid).remove();
151 | });
152 | })
153 | }
154 | }
155 |
156 | function fluid_update() {
157 | for (i in fluid_images) {
158 | if(!fluid_images.hasOwnProperty(i)) continue;
159 | var el = fluid_images[i],
160 | label = el.firstChild;
161 |
162 | el.style.lineHeight = el.offsetHeight+"px";
163 | label.data = el.offsetWidth + "x" + el.offsetHeight;
164 | }
165 | }
166 |
167 | function parse_flags(flags, options) {
168 |
169 | var ret = {
170 | theme: settings.themes.gray
171 | }, render = false;
172 |
173 | for (sl = flags.length, j = 0; j < sl; j++) {
174 | var flag = flags[j];
175 | if (app.flags.dimensions.match(flag)) {
176 | render = true;
177 | ret.dimensions = app.flags.dimensions.output(flag);
178 | } else if (app.flags.fluid.match(flag)) {
179 | render = true;
180 | ret.dimensions = app.flags.fluid.output(flag);
181 | ret.fluid = true;
182 | } else if (app.flags.colors.match(flag)) {
183 | ret.theme = app.flags.colors.output(flag);
184 | } else if (options.themes[flag]) {
185 | //If a theme is specified, it will override custom colors
186 | ret.theme = options.themes[flag];
187 | } else if (app.flags.text.match(flag)) {
188 | ret.text = app.flags.text.output(flag);
189 | } else if(app.flags.font.match(flag)){
190 | ret.font = app.flags.font.output(flag);
191 | }
192 | else if(app.flags.auto.match(flag)){
193 | ret.auto = true;
194 | }
195 | }
196 |
197 | return render ? ret : false;
198 |
199 | };
200 |
201 | if (!canvas.getContext) {
202 | fallback = true;
203 | } else {
204 | if (canvas.toDataURL("image/png")
205 | .indexOf("data:image/png") < 0) {
206 | //Android doesn't support data URI
207 | fallback = true;
208 | } else {
209 | var ctx = canvas.getContext("2d");
210 | }
211 | }
212 |
213 | var fluid_images = [];
214 |
215 | var settings = {
216 | domain: "holder.js",
217 | images: "img",
218 | bgnodes: ".holderjs",
219 | themes: {
220 | "gray": {
221 | background: "#eee",
222 | foreground: "#aaa",
223 | size: 12
224 | },
225 | "social": {
226 | background: "#3a5a97",
227 | foreground: "#fff",
228 | size: 12
229 | },
230 | "industrial": {
231 | background: "#434A52",
232 | foreground: "#C2F200",
233 | size: 12
234 | }
235 | },
236 | stylesheet: ".holderjs-fluid {font-size:16px;font-weight:bold;text-align:center;font-family:sans-serif;margin:0}"
237 | };
238 |
239 |
240 | app.flags = {
241 | dimensions: {
242 | regex: /^(\d+)x(\d+)$/,
243 | output: function (val) {
244 | var exec = this.regex.exec(val);
245 | return {
246 | width: +exec[1],
247 | height: +exec[2]
248 | }
249 | }
250 | },
251 | fluid: {
252 | regex: /^([0-9%]+)x([0-9%]+)$/,
253 | output: function (val) {
254 | var exec = this.regex.exec(val);
255 | return {
256 | width: exec[1],
257 | height: exec[2]
258 | }
259 | }
260 | },
261 | colors: {
262 | regex: /#([0-9a-f]{3,})\:#([0-9a-f]{3,})/i,
263 | output: function (val) {
264 | var exec = this.regex.exec(val);
265 | return {
266 | size: settings.themes.gray.size,
267 | foreground: "#" + exec[2],
268 | background: "#" + exec[1]
269 | }
270 | }
271 | },
272 | text: {
273 | regex: /text\:(.*)/,
274 | output: function (val) {
275 | return this.regex.exec(val)[1];
276 | }
277 | },
278 | font: {
279 | regex: /font\:(.*)/,
280 | output: function(val){
281 | return this.regex.exec(val)[1];
282 | }
283 | },
284 | auto: {
285 | regex: /^auto$/
286 | }
287 | }
288 |
289 | for (var flag in app.flags) {
290 | if(!app.flags.hasOwnProperty(flag)) continue;
291 | app.flags[flag].match = function (val) {
292 | return val.match(this.regex)
293 | }
294 | }
295 |
296 | app.add_theme = function (name, theme) {
297 | name != null && theme != null && (settings.themes[name] = theme);
298 | return app;
299 | };
300 |
301 | app.add_image = function (src, el) {
302 | var node = selector(el);
303 | if (node.length) {
304 | for (var i = 0, l = node.length; i < l; i++) {
305 | var img = document.createElement("img")
306 | img.setAttribute("data-src", src);
307 | node[i].appendChild(img);
308 | }
309 | }
310 | return app;
311 | };
312 |
313 | app.run = function (o) {
314 | var options = extend(settings, o), images = [];
315 |
316 | if(options.images instanceof window.NodeList){
317 | imageNodes = options.images;
318 | }
319 | else if(options.images instanceof window.Node){
320 | imageNodes = [options.images];
321 | }
322 | else{
323 | imageNodes = selector(options.images);
324 | }
325 |
326 | if(options.elements instanceof window.NodeList){
327 | bgnodes = options.bgnodes;
328 | }
329 | else if(options.bgnodes instanceof window.Node){
330 | bgnodes = [options.bgnodes];
331 | }
332 | else{
333 | bgnodes = selector(options.bgnodes);
334 | }
335 |
336 | preempted = true;
337 |
338 | for (i = 0, l = imageNodes.length; i < l; i++) images.push(imageNodes[i]);
339 |
340 | var holdercss = document.getElementById("holderjs-style");
341 |
342 | if(!holdercss){
343 | holdercss = document.createElement("style");
344 | holdercss.setAttribute("id", "holderjs-style");
345 | holdercss.type = "text/css";
346 | document.getElementsByTagName("head")[0].appendChild(holdercss);
347 | }
348 |
349 | if(holdercss.styleSheet){
350 | holdercss.styleSheet += options.stylesheet;
351 | }
352 | else{
353 | holdercss.textContent+= options.stylesheet;
354 | }
355 |
356 | var cssregex = new RegExp(options.domain + "\/(.*?)\"?\\)");
357 |
358 | for (var l = bgnodes.length, i = 0; i < l; i++) {
359 | var src = window.getComputedStyle(bgnodes[i], null)
360 | .getPropertyValue("background-image");
361 | var flags = src.match(cssregex);
362 | if (flags) {
363 | var holder = parse_flags(flags[1].split("/"), options);
364 | if (holder) {
365 | render("background", bgnodes[i], holder, src);
366 | }
367 | }
368 | }
369 |
370 | for (var l = images.length, i = 0; i < l; i++) {
371 | var src = images[i].getAttribute("src") || images[i].getAttribute("data-src");
372 | if (src != null && src.indexOf(options.domain) >= 0) {
373 | var holder = parse_flags(src.substr(src.lastIndexOf(options.domain) + options.domain.length + 1)
374 | .split("/"), options);
375 | if (holder) {
376 | if (holder.fluid) {
377 | fluid(images[i], holder, src);
378 | } else {
379 | render("image", images[i], holder, src);
380 | }
381 | }
382 | }
383 | }
384 | return app;
385 | };
386 |
387 | contentLoaded(win, function () {
388 | if (window.addEventListener) {
389 | window.addEventListener("resize", fluid_update, false);
390 | window.addEventListener("orientationchange", fluid_update, false);
391 | } else {
392 | window.attachEvent("onresize", fluid_update)
393 | }
394 | preempted || app.run();
395 | });
396 |
397 | if ( typeof define === "function" && define.amd ) {
398 | define( "Holder", [], function () { return app; } );
399 | }
400 |
401 | })(Holder, window);
402 |
--------------------------------------------------------------------------------
/apps/web/src/product.erl:
--------------------------------------------------------------------------------
1 | -module(product).
2 | -compile(export_all).
3 | -include_lib("n2o/include/wf.hrl").
4 | -include_lib("kvs/include/user.hrl").
5 | -include_lib("kvs/include/product.hrl").
6 | -include_lib("kvs/include/comment.hrl").
7 | -include_lib("kvs/include/entry.hrl").
8 | -include_lib("kvs/include/feed.hrl").
9 | -include_lib("nitro/include/nitro.hrl").
10 |
11 | -include("records.hrl").
12 |
13 | -define(PAGE_SIZE, 4).
14 |
15 | main() ->
16 | #dtl{file=wf:cache(mode), ext="dtl",bindings=[{title,<<"product">>},{body, body()}]}.
17 |
18 | body() ->
19 | % Qid = wf:qs(<<"id">>),
20 | % Product = case [P || #product{id=Id} = P <- wf:session(products), Id == list_to_integer(binary_to_list(Qid))] of [] -> []; L -> lists:nth(1,L) end,
21 | P = product(1,2),
22 |
23 | index:header()++[
24 | #section{class=[section, alt], body=#panel{class=[container], body=#panel{class=["row-fluid"], body=[
25 | #panel{class=[span6], body=[
26 | #panel{class=["hero-unit"], body=[
27 | #h1{body=P#product.title},
28 | #p{body=P#product.brief},
29 | #button{class=[btn, "btn-large", "btn-info"], body= <<"buy it">>, postback={product, integer_to_list(P#product.id)}}
30 | ]}
31 | ]},
32 | #panel{class=[span6], body=#image{image=P#product.cover}}
33 | ]}}},
34 |
35 | #section{class=[section], body=#panel{class=[container], body=#panel{class=["row-fluid"], body=[
36 | #panel{class=[span9], body=[
37 | [blog_post() || _I <- lists:seq(1,3)],
38 | #list{class=[pager], body=[
39 | #li{class=[previous], body=#link{body=[#i{class=["icon-chevron-left"]}, <<" Older">> ]}},
40 | #li{class=[next], body=#link{body=[#i{class=["icon-chevron-right"]}, <<" Newer">> ]}}
41 | ]}
42 | ]},
43 | #aside{class=[span3, sidebar], body=[
44 | #panel{class=["sidebar-widget"], body=[
45 | #h2{class=["sidebar-header"], body= <<"Search">>},
46 | #panel{class=["input-append"], body=[
47 | #textbox{id="search-button"},
48 | #button{class=[btn], body= <<"Go!">>}
49 | ]}
50 | ]},
51 | #panel{class=["sidebar-widget"], body=[
52 | #h2{class=["sidebar-header"], body= <<"About SmartBiz">>},
53 | #p{body= <<"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.">>}
54 | ]},
55 | #panel{class=["sidebar-widget"], body=[
56 | #h2{class=["sidebar-header"], body= <<"Recent posts">>},
57 | #list{class=[unstyled], body=[
58 | #li{body=[#h4{body=#link{body = <<"Lorem ipsum dolor sit">>}},
59 | #p{body=#small{body= <<"November 12, 2012">>}}]},
60 | #li{body=[#h4{body=#link{body = <<"Ed do eiusmod tempor">>}},
61 | #p{body=#small{body= <<"August 12, 2012">>}}]},
62 | #li{body=[#h4{body=#link{body = <<"Incididunt ut labore">>}},
63 | #p{body=#small{body= <<"June 12, 2012">>}}]},
64 | #li{body=[#h4{body=#link{body = <<"Quis nostrud exercitation">>}},
65 | #p{body=#small{body= <<"June 12, 2012">>}}]},
66 | #li{body=[#h4{body=#link{body = <<"Quis nostrud exercitation">>}},
67 | #p{body=#small{body= <<"June 12, 2012">>}}]}
68 | ]}
69 | ]},
70 | #panel{class=["sidebar-widget"], body=[
71 | #h2{class=["sidebar-header"], body= <<"Popular posts">>},
72 | #list{class=[unstyled], body=[
73 | #li{body=[#h4{body=#link{body = <<"Lorem ipsum dolor sit">>}},
74 | #p{body=#small{body= <<"November 12, 2012">>}}]},
75 | #li{body=[#h4{body=#link{body = <<"Ed do eiusmod tempor">>}},
76 | #p{body=#small{body= <<"August 12, 2012">>}}]},
77 | #li{body=[#h4{body=#link{body = <<"Quis nostrud exercitation">>}},
78 | #p{body=#small{body= <<"June 12, 2012">>}}]}
79 | ]}
80 | ]}
81 | ]}
82 |
83 | ]}}}
84 |
85 | ]++index:footer().
86 |
87 | blog_post()-> % feed entry
88 | #article{class=["blog-post"], body=[
89 | #header{class=["blog-header"], body=[
90 | #h2{body=[<<"Lorem ipsum dolor">>, #small{body=[<<" by">>, #link{body= <<" John Doe">>}, <<" 12 Sep 2012.">>]}]}
91 | ]},
92 | #figure{class=["thumbnail-figure"], body=[
93 | #link{url= <<"/feed?id=1">>, body=[#image{image= <<"/static/img/crysis3-bg1.png">>} ]},
94 | #figcaption{class=["thumbnail-title"], body=[
95 | #h3{body=#span{body= <<"Lorem ipsum dolor sit amet">>}}
96 | ]}
97 | ]},
98 | #p{body= <<"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.">>},
99 | #footer{class=["blog-footer", "row-fluid"], body=[
100 | #panel{class=[span4, "blog-categories"], body=[#i{class=["icon-pushpin"]}, #link{body= <<" consectetur">>}]},
101 | #panel{class=[span4, "blog-tags"], body=[#i{class=["icon-tags"]}, #link{body= <<" fugiat, nulla, pariatur">>}]},
102 | #panel{class=[span4, "blog-more"], body=[#i{class=["icon-link"]}, #link{body= <<" read more">>, url="/feed"}]}
103 | ]}
104 | ]}.
105 |
106 | blog_post_expanded()->
107 | #article{class=["blog-post"], body=[
108 | #header{class=["blog-header"], body=[
109 | #h2{body=[<<"Lorem ipsum dolor">>, #small{body=[<<" by">>, #link{body= <<" John Doe">>}, <<" 12 Sep 2012.">>]}]}
110 | ]},
111 | #figure{class=["thumbnail-figure"], body=[
112 | #link{url= <<"/feed?id=1">>, body=[#image{image= <<"/static/img/crysis3-bg1.png">>} ]},
113 | #figcaption{class=["thumbnail-title"], body=[
114 | #h3{body=#span{body= <<"Lorem ipsum dolor sit amet">>}}
115 | ]}
116 | ]},
117 | #p{body= <<"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.">>},
118 | #p{body= <<"Nullam eget suscipit turpis. Suspendisse nec magna et velit elementum vulputate. Suspendisse ac nibh lectus, at sollicitudin turpis. Aenean ut tortor a felis consectetur pulvinar. Phasellus mattis viverra luctus. Pellentesque tempor bibendum arcu non vestibulum. In bibendum mattis nibh, nec laoreet enim pretium a. Donec augue sem, convallis euismod pellentesque non, facilisis non nulla. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Duis blandit cursus mi, malesuada euismod enim accumsan nec. Pellentesque nisl enim, elementum non molestie eu, lobortis sed odio. Mauris vehicula commodo neque, nec viverra libero accumsan in.">>},
119 | #panel{class=["row-fluid"], body=[
120 | #panel{class=[span6], body=#p{body= <<"Vestibulum et dapibus orci. Vivamus non elit sed quam egestas egestas. Donec interdum ultrices ante ac pharetra. Praesent euismod augue erat, vel ornare sem. Morbi ante nisl, fringilla at commodo vitae, cursus aliquet lacus. Maecenas nec orci at est venenatis congue vitae eget justo. Aenean dui odio, eleifend sed viverra et, eleifend vitae tortor. Duis ac diam vitae risus aliquam tempor. Phasellus volutpat, metus porttitor ornare gravida, erat lacus bibendum lectus, et dictum tortor ligula a est. Proin id purus eget mi vestibulum accumsan. Nam scelerisque malesuada tellus vel laoreet. Vestibulum eleifend, risus ut faucibus iaculis">>}},
121 | #panel{class=[span6], body=[#image{image= <<"/static/img/crysis3-bg2.png">>}]}
122 | ]},
123 | #p{body= <<"Quisque diam libero, aliquam eget blandit et, vulputate vel felis. Quisque ut purus at justo mattis volutpat. Curabitur nibh neque, sodales feugiat suscipit vel, vulputate nec quam. Sed quam nulla, sollicitudin non pulvinar in, viverra ac nunc. Maecenas a neque quis mauris vehicula viverra eu eget elit. Suspendisse potenti. Donec tincidunt sollicitudin elementum. Nunc volutpat purus ac lectus tincidunt et bibendum quam sollicitudin. Pellentesque rutrum ultricies porttitor. Suspendisse pellentesque rutrum mollis. Integer varius nulla quis metus varius imperdiet. ">>},
124 | #footer{class=["blog-footer", "row-fluid"], body=[
125 | #panel{class=[span4, "blog-categories"], body=[#i{class=["icon-pushpin"]}, #link{body= <<" consectetur">>}]},
126 | #panel{class=[span4, "blog-tags"], body=[#i{class=["icon-tags"]}, #link{body= <<" fugiat, nulla, pariatur">>}]},
127 | #panel{class=[span4, "blog-more"], body=[#i{class=["icon-link"]}, #link{body= <<" read more">>}]}
128 | ]}
129 | ]}.
130 |
131 | comment() -> comment([]).
132 | comment(InnerComment)->
133 | #panel{class=[media, "media-comment"], body=[
134 | #link{class=["pull-left"], body=[
135 | #image{class=["media-objects","img-circle"], data_fields=[{<<"data-src">>, <<"holder.js/64x64">>}]}
136 | ]},
137 | #panel{class=["media-body"], body=[
138 | #p{class=["media-heading"], body=[
139 | <<"John Doe, 12 Sep 2012.">>,
140 | #link{class=["comment-reply","pull-right"], body= <<"reply">>}
141 | ]},
142 | #p{body= <<"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.">>},
143 | InnerComment
144 | ]}
145 | ]}.
146 |
147 | feed() -> [#feed_entry{entry=E} || E <- entries(), _I <- lists:seq(1, 5)].
148 |
149 | render_element(#product_figure{product=P})->
150 | {PriceHead, PriceClass, BtnClass} = case P#product.price of % case for featured product
151 | true -> {<<"Featured">>, ["pricing-table-featured", "product-price-featured"], []};
152 | false -> {<<"Featured">>, ["pricing-table-featured", "product-price-featured", "featured-orange"], []};
153 | _ -> {<<"Standard">>, [], ["btn-info"]}
154 | end,
155 |
156 | L = #link{url= list_to_binary("/product?id="++ integer_to_list(P#product.id)), body=#figure{class=[product, "thumbnail-figure"], body=[
157 | #image{image=P#product.cover},
158 | #figcaption{class=["row-fluid", "product-caption"], body=[
159 | #panel{class=["product-title", "thumbnail-title" ], body=[
160 | #h3{body=#span{body=P#product.title}},
161 | #p{body=#span{body=P#product.brief}},
162 | #span{class=[badges],body=[
163 | #i{class=["icon-user"]}, #span{class=["badge badge-info"], body= <<"1024">>},
164 | #i{class=["icon-comment"]}, #span{class=["badge badge-info"], body= <<"10">>}
165 | ]} ]},
166 | #panel{class=["well","pricing-table", "product-price", span3, "text-center"]++PriceClass, body=[
167 | #h3{body=#span{body=PriceHead}},
168 | #h2{class=["pricing-table-price", "product-price-price"], body=[#span{body= <<"$">>}, list_to_binary(io_lib:format("~.2f", [P#product.price]))]},
169 |
170 | #list{class=["pricing-table-list", "product-price-list"], body=[
171 | #li{body= <<"Lorem ipsum">>},
172 | #li{body= <<"dolor sit amet">>}
173 | ]},
174 | #button{class=[btn, "btn-large"]++BtnClass, body= <<"buy it">>, postback={product, integer_to_list(P#product.id)}}
175 | ]}
176 | ]} ]} },
177 | element_link:render_element(L);
178 |
179 | render_element(#feed_entry{entry=E, id=Id}) ->
180 | {{Y, Mm, D}, {_H, _M, _S}} = E#entry.created,
181 |
182 | Li = #li{class=[thumbnail, span12, clearfix, "product-review"], body=[
183 | #panel{class=[span3, "review-author"], body=[
184 | #link{class=[avatar], body=#image{class=["img-circle"], data_fields=[{<<"data-src">>, <<"holder.js/100x100">>}]}},
185 | #p{body=[
186 | #link{url="#", body=[ #i{class=["icon-user"]}, #span{body =E#entry.from}]},
187 | #span{class=["review-date"],body=[#i{class=["icon-calendar"]}, io_lib:format("~p/~p/~p",[Mm, D, Y]) ]},
188 | #link{url="#",body=[ #i{class=["icon-thumbs-up"]}, #span{class=["badge badge-info"], body= <<"3">>} ]},
189 | #link{url="#",body=[ #i{class=["icon-comment"]}, #span{class=["badge badge-info"], body= <<"10">>} ]},
190 | #link{url="#",body=[ #i{class=["icon-share"]}, #span{class=["badge badge-info"], body= <<"5">>} ]}
191 | ]}
192 | ]},
193 |
194 | #panel{class=[span3], body=[#feed_media{media=M} || M <- E#entry.media]},
195 |
196 | #panel{class=[span6], body=[
197 | #h4{body = title()},
198 | description(wf:temp_id(), E#entry.description)
199 | ]},
200 |
201 | #list{class=[comments],body=list_comments(Id)}
202 | ]},
203 | element_li:render_element(Li);
204 | render_element(_R = #feed_comment{comment=C}) ->
205 | #li{body=[
206 | #panel{body=#link{body= <<"comment">>}},
207 | #p{body=C#comment.content},
208 | #panel{class=[media], body=list_medias(C)}
209 | ]};
210 | render_element(FeedMedia = #feed_media{media = Media}) ->
211 | case Media#media.type of
212 | image -> image_media(FeedMedia);
213 | _ -> image_media(FeedMedia)
214 | end.
215 |
216 | list_comments(_Eid)->
217 | Comments =[],
218 | [#feed_comment{comment=C}|| C <- Comments].
219 |
220 | title()-> <<"Review title">>.
221 |
222 | description(Id, Description) -> [
223 | #panel{id="description"++Id, body=[
224 | #panel{class=[collapse, in], body= <<"Description head">>},
225 | #panel{id=Id, class=collapse, body= Description}
226 | ]},
227 | #button{class=[btn, "btn-link"], data_fields=[
228 | {<<"data-toggle">>, <<"collapse">>},
229 | {<<"data-target">>, list_to_binary("#"++Id) },
230 | {<<"data-parent">>, list_to_binary("#description"++Id)}], body= <<"Read...">>}].
231 |
232 | list_medias(C)->
233 | {Cid, Fid} = C#comment.id,
234 | [#feed_media{media=M, target=wf:temp_id(), fid = Fid, cid = Cid} || M <- C#comment.media].
235 |
236 | image_media(_Media)-> element_image:render_element(#image{image= "/static/img/item-bg.png"}).
237 |
238 | event(init) -> [];
239 | event({counter,C}) -> wf:update(onlinenumber,wf:to_list(C));
240 | event(Event) -> error_logger:info_msg("Page event: ~p", [Event]), [].
241 |
242 | api_event(Name,Tag,Term) -> error_logger:info_msg("Name ~p, Tag ~p, Term ~p",[Name,Tag,Term]), event(change_me).
243 |
244 | control_event(Id, Tag) ->
245 | error_logger:info_msg("Tinymce editor control event ~p: ~p", [Id, Tag]),
246 | Ed = wf:q(mcecontent),
247 | error_logger:info_msg("Data: ~p", [Ed]),
248 | ok.
249 |
250 | entries()-> [
251 | #entry{
252 | id={1,1},
253 | description= <<"The award-winning developer Crytek is back with Crysis 3, the first blockbuster shooter of 2013!">>,
254 | from= <<"Pupkin">>,
255 | created = calendar:local_time(),
256 | type= {product, normal},
257 | media= [
258 | #media{
259 | id=1,
260 | type = image,
261 | title= <<"Media1">>,
262 | html= <<"Media1 ">>,
263 | url = <<"/static/img/p1.jpg">>,
264 | thumbnail_url = <<"/static/img/p1.jpg">> }] }].
265 |
266 | product() -> product(1,1).
267 | product(Id, Pic)->
268 | #product{
269 | id=Id,
270 | title = <<"Crysis 3">>,
271 | categories= [1],
272 | brief= <<"Crytek is back with Crysis 3 The award-winning developer Crytek is back with Crysis 3, the first blockbuster shooter of 2013!Return to the fight as Prophet, the Nanosuit soldier on a quest to rediscover his humanity. Adapt on the fly with the stealth and armor abilities of your unique Nanosuit as you battle through the seven wonders of New York’s Liberty Dome. Unleash the firepower of your all-new, Predator bow and alien weaponry to hunt both human and alien enemies. Crysis 3 is the ultimate sandbox shooter, realized in the stunning visuals only Crytek and the latest version of CryENGINE can deliver. Available now on Xbox 360, PlayStation 3, and PC">>,
273 | cover = "/static/img/crysis3-bg" ++ integer_to_list(Pic)++".png",
274 | publish_start_date = calendar:local_time(),
275 | publish_end_date = calendar:local_time(),
276 | price=22.95}.
277 |
--------------------------------------------------------------------------------
/apps/web/priv/static/js/bootstrap.min.js:
--------------------------------------------------------------------------------
1 | !function($){"use strict";var Tooltip=function(element,options){this.init("tooltip",element,options)};Tooltip.prototype={constructor:Tooltip,init:function(type,element,options){var eventIn,eventOut,triggers,trigger,i;this.type=type;this.$element=$(element);this.options=this.getOptions(options);this.enabled=true;triggers=this.options.trigger.split(" ");for(i=triggers.length;i--;){trigger=triggers[i];if(trigger=="click"){this.$element.on("click."+this.type,this.options.selector,$.proxy(this.toggle,this))}else if(trigger!="manual"){eventIn=trigger=="hover"?"mouseenter":"focus";eventOut=trigger=="hover"?"mouseleave":"blur";this.$element.on(eventIn+"."+this.type,this.options.selector,$.proxy(this.enter,this));this.$element.on(eventOut+"."+this.type,this.options.selector,$.proxy(this.leave,this))}}this.options.selector?this._options=$.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(options){options=$.extend({},$.fn[this.type].defaults,this.$element.data(),options);if(options.delay&&typeof options.delay=="number"){options.delay={show:options.delay,hide:options.delay}}return options},enter:function(e){var defaults=$.fn[this.type].defaults,options={},self;this._options&&$.each(this._options,function(key,value){if(defaults[key]!=value)options[key]=value},this);self=$(e.currentTarget)[this.type](options).data(this.type);if(!self.options.delay||!self.options.delay.show)return self.show();clearTimeout(this.timeout);self.hoverState="in";this.timeout=setTimeout(function(){if(self.hoverState=="in")self.show()},self.options.delay.show)},leave:function(e){var self=$(e.currentTarget)[this.type](this._options).data(this.type);if(this.timeout)clearTimeout(this.timeout);if(!self.options.delay||!self.options.delay.hide)return self.hide();self.hoverState="out";this.timeout=setTimeout(function(){if(self.hoverState=="out")self.hide()},self.options.delay.hide)},show:function(){var $tip,pos,actualWidth,actualHeight,placement,tp,e=$.Event("show");if(this.hasContent()&&this.enabled){this.$element.trigger(e);if(e.isDefaultPrevented())return;$tip=this.tip();this.setContent();if(this.options.animation){$tip.addClass("fade")}placement=typeof this.options.placement=="function"?this.options.placement.call(this,$tip[0],this.$element[0]):this.options.placement;$tip.detach().css({top:0,left:0,display:"block"});this.options.container?$tip.appendTo(this.options.container):$tip.insertAfter(this.$element);pos=this.getPosition();actualWidth=$tip[0].offsetWidth;actualHeight=$tip[0].offsetHeight;switch(placement){case"bottom":tp={top:pos.top+pos.height,left:pos.left+pos.width/2-actualWidth/2};break;case"top":tp={top:pos.top-actualHeight,left:pos.left+pos.width/2-actualWidth/2};break;case"left":tp={top:pos.top+pos.height/2-actualHeight/2,left:pos.left-actualWidth};break;case"right":tp={top:pos.top+pos.height/2-actualHeight/2,left:pos.left+pos.width};break}this.applyPlacement(tp,placement);this.$element.trigger("shown")}},applyPlacement:function(offset,placement){var $tip=this.tip(),width=$tip[0].offsetWidth,height=$tip[0].offsetHeight,actualWidth,actualHeight,delta,replace;$tip.offset(offset).addClass(placement).addClass("in");actualWidth=$tip[0].offsetWidth;actualHeight=$tip[0].offsetHeight;if(placement=="top"&&actualHeight!=height){offset.top=offset.top+height-actualHeight;replace=true}if(placement=="bottom"||placement=="top"){delta=0;if(offset.left<0){delta=offset.left*-2;offset.left=0;$tip.offset(offset);actualWidth=$tip[0].offsetWidth;actualHeight=$tip[0].offsetHeight}this.replaceArrow(delta-width+actualWidth,actualWidth,"left")}else{this.replaceArrow(actualHeight-height,actualHeight,"top")}if(replace)$tip.offset(offset)},replaceArrow:function(delta,dimension,position){this.arrow().css(position,delta?50*(1-delta/dimension)+"%":"")},setContent:function(){var $tip=this.tip(),title=this.getTitle();$tip.find(".tooltip-inner")[this.options.html?"html":"text"](title);$tip.removeClass("fade in top bottom left right")},hide:function(){var that=this,$tip=this.tip(),e=$.Event("hide");this.$element.trigger(e);if(e.isDefaultPrevented())return;$tip.removeClass("in");function removeWithAnimation(){var timeout=setTimeout(function(){$tip.off($.support.transition.end).detach()},500);$tip.one($.support.transition.end,function(){clearTimeout(timeout);$tip.detach()})}$.support.transition&&this.$tip.hasClass("fade")?removeWithAnimation():$tip.detach();this.$element.trigger("hidden");return this},fixTitle:function(){var $e=this.$element;if($e.attr("title")||typeof $e.attr("data-original-title")!="string"){$e.attr("data-original-title",$e.attr("title")||"").attr("title","")}},hasContent:function(){return this.getTitle()},getPosition:function(){var el=this.$element[0];return $.extend({},typeof el.getBoundingClientRect=="function"?el.getBoundingClientRect():{width:el.offsetWidth,height:el.offsetHeight},this.$element.offset())},getTitle:function(){var title,$e=this.$element,o=this.options;title=$e.attr("data-original-title")||(typeof o.title=="function"?o.title.call($e[0]):o.title);return title},tip:function(){return this.$tip=this.$tip||$(this.options.template)},arrow:function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},validate:function(){if(!this.$element[0].parentNode){this.hide();this.$element=null;this.options=null}},enable:function(){this.enabled=true},disable:function(){this.enabled=false},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(e){var self=e?$(e.currentTarget)[this.type](this._options).data(this.type):this;self.tip().hasClass("in")?self.hide():self.show()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var old=$.fn.tooltip;$.fn.tooltip=function(option){return this.each(function(){var $this=$(this),data=$this.data("tooltip"),options=typeof option=="object"&&option;if(!data)$this.data("tooltip",data=new Tooltip(this,options));if(typeof option=="string")data[option]()})};$.fn.tooltip.Constructor=Tooltip;$.fn.tooltip.defaults={animation:true,placement:"top",selector:false,template:'',trigger:"hover focus",title:"",delay:0,html:false,container:false};$.fn.tooltip.noConflict=function(){$.fn.tooltip=old;return this}}(window.jQuery);!function($){"use strict";var Typeahead=function(element,options){this.$element=$(element);this.options=$.extend({},$.fn.typeahead.defaults,options);this.matcher=this.options.matcher||this.matcher;this.sorter=this.options.sorter||this.sorter;this.highlighter=this.options.highlighter||this.highlighter;this.updater=this.options.updater||this.updater;this.source=this.options.source;this.$menu=$(this.options.menu);this.shown=false;this.listen()};Typeahead.prototype={constructor:Typeahead,select:function(){var val=this.$menu.find(".active").attr("data-value");this.$element.val(this.updater(val)).change();return this.hide()},updater:function(item){return item},show:function(){var pos=$.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});this.$menu.insertAfter(this.$element).css({top:pos.top+pos.height,left:pos.left}).show();this.shown=true;return this},hide:function(){this.$menu.hide();this.shown=false;return this},lookup:function(event){var items;this.query=this.$element.val();if(!this.query||this.query.length"+match+""})},render:function(items){var that=this;items=$(items).map(function(i,item){i=$(that.options.item).attr("data-value",item);i.find("a").html(that.highlighter(item));return i[0]});items.first().addClass("active");this.$menu.html(items);return this},next:function(event){var active=this.$menu.find(".active").removeClass("active"),next=active.next();if(!next.length){next=$(this.$menu.find("li")[0])}next.addClass("active")},prev:function(event){var active=this.$menu.find(".active").removeClass("active"),prev=active.prev();if(!prev.length){prev=this.$menu.find("li").last()}prev.addClass("active")},listen:function(){this.$element.on("focus",$.proxy(this.focus,this)).on("blur",$.proxy(this.blur,this)).on("keypress",$.proxy(this.keypress,this)).on("keyup",$.proxy(this.keyup,this));if(this.eventSupported("keydown")){this.$element.on("keydown",$.proxy(this.keydown,this))}this.$menu.on("click",$.proxy(this.click,this)).on("mouseenter","li",$.proxy(this.mouseenter,this)).on("mouseleave","li",$.proxy(this.mouseleave,this))},eventSupported:function(eventName){var isSupported=eventName in this.$element;if(!isSupported){this.$element.setAttribute(eventName,"return;");isSupported=typeof this.$element[eventName]==="function"}return isSupported},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault();this.prev();break;case 40:e.preventDefault();this.next();break}e.stopPropagation()},keydown:function(e){this.suppressKeyPressRepeat=~$.inArray(e.keyCode,[40,38,9,13,27]);this.move(e)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation();e.preventDefault()},focus:function(e){this.focused=true},blur:function(e){this.focused=false;if(!this.mousedover&&this.shown)this.hide()},click:function(e){e.stopPropagation();e.preventDefault();this.select();this.$element.focus()},mouseenter:function(e){this.mousedover=true;this.$menu.find(".active").removeClass("active");$(e.currentTarget).addClass("active")},mouseleave:function(e){this.mousedover=false;if(!this.focused&&this.shown)this.hide()}};var old=$.fn.typeahead;$.fn.typeahead=function(option){return this.each(function(){var $this=$(this),data=$this.data("typeahead"),options=typeof option=="object"&&option;if(!data)$this.data("typeahead",data=new Typeahead(this,options));if(typeof option=="string")data[option]()})};$.fn.typeahead.defaults={source:[],items:8,menu:'',item:' ',minLength:1};$.fn.typeahead.Constructor=Typeahead;$.fn.typeahead.noConflict=function(){$.fn.typeahead=old;return this};$(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(e){var $this=$(this);if($this.data("typeahead"))return;$this.typeahead($this.data())})}(window.jQuery);!function($){"use strict";var Modal=function(element,options){this.options=options;this.$element=$(element).delegate('[data-dismiss="modal"]',"click.dismiss.modal",$.proxy(this.hide,this));this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};Modal.prototype={constructor:Modal,toggle:function(){return this[!this.isShown?"show":"hide"]()},show:function(){var that=this,e=$.Event("show");this.$element.trigger(e);if(this.isShown||e.isDefaultPrevented())return;this.isShown=true;this.escape();this.backdrop(function(){var transition=$.support.transition&&that.$element.hasClass("fade");if(!that.$element.parent().length){that.$element.appendTo(document.body)}that.$element.show();if(transition){that.$element[0].offsetWidth}that.$element.addClass("in").attr("aria-hidden",false);that.enforceFocus();transition?that.$element.one($.support.transition.end,function(){that.$element.focus().trigger("shown")}):that.$element.focus().trigger("shown")})},hide:function(e){e&&e.preventDefault();var that=this;e=$.Event("hide");this.$element.trigger(e);if(!this.isShown||e.isDefaultPrevented())return;this.isShown=false;this.escape();$(document).off("focusin.modal");this.$element.removeClass("in").attr("aria-hidden",true);$.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var that=this;$(document).on("focusin.modal",function(e){if(that.$element[0]!==e.target&&!that.$element.has(e.target).length){that.$element.focus()}})},escape:function(){var that=this;if(this.isShown&&this.options.keyboard){this.$element.on("keyup.dismiss.modal",function(e){e.which==27&&that.hide()})}else if(!this.isShown){this.$element.off("keyup.dismiss.modal")}},hideWithTransition:function(){var that=this,timeout=setTimeout(function(){that.$element.off($.support.transition.end);that.hideModal()},500);this.$element.one($.support.transition.end,function(){clearTimeout(timeout);that.hideModal()})},hideModal:function(){var that=this;this.$element.hide();this.backdrop(function(){that.removeBackdrop();that.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop&&this.$backdrop.remove();this.$backdrop=null},backdrop:function(callback){var that=this,animate=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var doAnimate=$.support.transition&&animate;this.$backdrop=$('
').appendTo(document.body);this.$backdrop.click(this.options.backdrop=="static"?$.proxy(this.$element[0].focus,this.$element[0]):$.proxy(this.hide,this));if(doAnimate)this.$backdrop[0].offsetWidth;this.$backdrop.addClass("in");if(!callback)return;doAnimate?this.$backdrop.one($.support.transition.end,callback):callback()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");$.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one($.support.transition.end,callback):callback()}else if(callback){callback()}}};var old=$.fn.modal;$.fn.modal=function(option){return this.each(function(){var $this=$(this),data=$this.data("modal"),options=$.extend({},$.fn.modal.defaults,$this.data(),typeof option=="object"&&option);if(!data)$this.data("modal",data=new Modal(this,options));if(typeof option=="string")data[option]();else if(options.show)data.show()})};$.fn.modal.defaults={backdrop:true,keyboard:true,show:true};$.fn.modal.Constructor=Modal;$.fn.modal.noConflict=function(){$.fn.modal=old;return this};$(document).on("click.modal.data-api",'[data-toggle="modal"]',function(e){var $this=$(this),href=$this.attr("href"),$target=$($this.attr("data-target")||href&&href.replace(/.*(?=#[^\s]+$)/,"")),option=$target.data("modal")?"toggle":$.extend({remote:!/#/.test(href)&&href},$target.data(),$this.data());e.preventDefault();$target.modal(option).one("hide",function(){$this.focus()})})}(window.jQuery);!function($){"use strict";var Carousel=function(element,options){this.$element=$(element);this.$indicators=this.$element.find(".carousel-indicators");this.options=options;this.options.pause=="hover"&&this.$element.on("mouseenter",$.proxy(this.pause,this)).on("mouseleave",$.proxy(this.cycle,this))};Carousel.prototype={cycle:function(e){if(!e)this.paused=false;if(this.interval)clearInterval(this.interval);this.options.interval&&!this.paused&&(this.interval=setInterval($.proxy(this.next,this),this.options.interval));return this},getActiveIndex:function(){this.$active=this.$element.find(".item.active");this.$items=this.$active.parent().children();return this.$items.index(this.$active)},to:function(pos){var activeIndex=this.getActiveIndex(),that=this;if(pos>this.$items.length-1||pos<0)return;if(this.sliding){return this.$element.one("slid",function(){that.to(pos)})}if(activeIndex==pos){return this.pause().cycle()}return this.slide(pos>activeIndex?"next":"prev",$(this.$items[pos]))},pause:function(e){if(!e)this.paused=true;if(this.$element.find(".next, .prev").length&&$.support.transition.end){this.$element.trigger($.support.transition.end);this.cycle(true)}clearInterval(this.interval);this.interval=null;return this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(type,next){var $active=this.$element.find(".item.active"),$next=next||$active[type](),isCycling=this.interval,direction=type=="next"?"left":"right",fallback=type=="next"?"first":"last",that=this,e;this.sliding=true;isCycling&&this.pause();$next=$next.length?$next:this.$element.find(".item")[fallback]();e=$.Event("slide",{relatedTarget:$next[0],direction:direction});if($next.hasClass("active"))return;if(this.$indicators.length){this.$indicators.find(".active").removeClass("active");this.$element.one("slid",function(){var $nextIndicator=$(that.$indicators.children()[that.getActiveIndex()]);$nextIndicator&&$nextIndicator.addClass("active")})}if($.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(e);if(e.isDefaultPrevented())return;$next.addClass(type);$next[0].offsetWidth;$active.addClass(direction);$next.addClass(direction);this.$element.one($.support.transition.end,function(){$next.removeClass([type,direction].join(" ")).addClass("active");$active.removeClass(["active",direction].join(" "));that.sliding=false;setTimeout(function(){that.$element.trigger("slid")},0)})}else{this.$element.trigger(e);if(e.isDefaultPrevented())return;$active.removeClass("active");$next.addClass("active");this.sliding=false;this.$element.trigger("slid")}isCycling&&this.cycle();return this}};var old=$.fn.carousel;$.fn.carousel=function(option){return this.each(function(){var $this=$(this),data=$this.data("carousel"),options=$.extend({},$.fn.carousel.defaults,typeof option=="object"&&option),action=typeof option=="string"?option:options.slide;if(!data)$this.data("carousel",data=new Carousel(this,options));if(typeof option=="number")data.to(option);else if(action)data[action]();else if(options.interval)data.pause().cycle()})};$.fn.carousel.defaults={interval:5e3,pause:"hover"};$.fn.carousel.Constructor=Carousel;$.fn.carousel.noConflict=function(){$.fn.carousel=old;return this};$(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(e){var $this=$(this),href,$target=$($this.attr("data-target")||(href=$this.attr("href"))&&href.replace(/.*(?=#[^\s]+$)/,"")),options=$.extend({},$target.data(),$this.data()),slideIndex;$target.carousel(options);if(slideIndex=$this.attr("data-slide-to")){$target.data("carousel").pause().to(slideIndex).cycle()}e.preventDefault()})}(window.jQuery);!function($){"use strict";var Collapse=function(element,options){this.$element=$(element);this.options=$.extend({},$.fn.collapse.defaults,options);if(this.options.parent){this.$parent=$(this.options.parent)}this.options.toggle&&this.toggle()};Collapse.prototype={constructor:Collapse,dimension:function(){var hasWidth=this.$element.hasClass("width");return hasWidth?"width":"height"},show:function(){var dimension,scroll,actives,hasData;if(this.transitioning||this.$element.hasClass("in"))return;dimension=this.dimension();scroll=$.camelCase(["scroll",dimension].join("-"));actives=this.$parent&&this.$parent.find("> .accordion-group > .in");if(actives&&actives.length){hasData=actives.data("collapse");if(hasData&&hasData.transitioning)return;actives.collapse("hide");hasData||actives.data("collapse",null)}this.$element[dimension](0);this.transition("addClass",$.Event("show"),"shown");$.support.transition&&this.$element[dimension](this.$element[0][scroll])},hide:function(){var dimension;if(this.transitioning||!this.$element.hasClass("in"))return;dimension=this.dimension();this.reset(this.$element[dimension]());this.transition("removeClass",$.Event("hide"),"hidden");this.$element[dimension](0)},reset:function(size){var dimension=this.dimension();this.$element.removeClass("collapse")[dimension](size||"auto")[0].offsetWidth;this.$element[size!==null?"addClass":"removeClass"]("collapse");return this},transition:function(method,startEvent,completeEvent){var that=this,complete=function(){if(startEvent.type=="show")that.reset();that.transitioning=0;that.$element.trigger(completeEvent)};this.$element.trigger(startEvent);if(startEvent.isDefaultPrevented())return;this.transitioning=1;this.$element[method]("in");$.support.transition&&this.$element.hasClass("collapse")?this.$element.one($.support.transition.end,complete):complete()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var old=$.fn.collapse;$.fn.collapse=function(option){return this.each(function(){var $this=$(this),data=$this.data("collapse"),options=$.extend({},$.fn.collapse.defaults,$this.data(),typeof option=="object"&&option);if(!data)$this.data("collapse",data=new Collapse(this,options));if(typeof option=="string")data[option]()})};$.fn.collapse.defaults={toggle:true};$.fn.collapse.Constructor=Collapse;$.fn.collapse.noConflict=function(){$.fn.collapse=old;return this};$(document).on("click.collapse.data-api","[data-toggle=collapse]",function(e){var $this=$(this),href,target=$this.attr("data-target")||e.preventDefault()||(href=$this.attr("href"))&&href.replace(/.*(?=#[^\s]+$)/,""),option=$(target).data("collapse")?"toggle":$this.data();$this[$(target).hasClass("in")?"addClass":"removeClass"]("collapsed");$(target).collapse(option)})}(window.jQuery);!function($){"use strict";function ScrollSpy(element,options){var process=$.proxy(this.process,this),$element=$(element).is("body")?$(window):$(element),href;this.options=$.extend({},$.fn.scrollspy.defaults,options);this.$scrollElement=$element.on("scroll.scroll-spy.data-api",process);this.selector=(this.options.target||(href=$(element).attr("href"))&&href.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a";this.$body=$("body");this.refresh();this.process()}ScrollSpy.prototype={constructor:ScrollSpy,refresh:function(){var self=this,$targets;this.offsets=$([]);this.targets=$([]);$targets=this.$body.find(this.selector).map(function(){var $el=$(this),href=$el.data("target")||$el.attr("href"),$href=/^#\w/.test(href)&&$(href);return $href&&$href.length&&[[$href.position().top+(!$.isWindow(self.$scrollElement.get(0))&&self.$scrollElement.scrollTop()),href]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){self.offsets.push(this[0]);self.targets.push(this[1])})},process:function(){var scrollTop=this.$scrollElement.scrollTop()+this.options.offset,scrollHeight=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,maxScroll=scrollHeight-this.$scrollElement.height(),offsets=this.offsets,targets=this.targets,activeTarget=this.activeTarget,i;if(scrollTop>=maxScroll){return activeTarget!=(i=targets.last()[0])&&this.activate(i)}for(i=offsets.length;i--;){activeTarget!=targets[i]&&scrollTop>=offsets[i]&&(!offsets[i+1]||scrollTop<=offsets[i+1])&&this.activate(targets[i])}},activate:function(target){var active,selector;this.activeTarget=target;$(this.selector).parent(".active").removeClass("active");selector=this.selector+'[data-target="'+target+'"],'+this.selector+'[href="'+target+'"]';active=$(selector).parent("li").addClass("active");if(active.parent(".dropdown-menu").length){active=active.closest("li.dropdown").addClass("active")}active.trigger("activate")}};var old=$.fn.scrollspy;$.fn.scrollspy=function(option){return this.each(function(){var $this=$(this),data=$this.data("scrollspy"),options=typeof option=="object"&&option;if(!data)$this.data("scrollspy",data=new ScrollSpy(this,options));if(typeof option=="string")data[option]()})};$.fn.scrollspy.Constructor=ScrollSpy;$.fn.scrollspy.defaults={offset:10};$.fn.scrollspy.noConflict=function(){$.fn.scrollspy=old;return this};$(window).on("load",function(){$('[data-spy="scroll"]').each(function(){var $spy=$(this);$spy.scrollspy($spy.data())})})}(window.jQuery);!function($){"use strict";var toggle="[data-toggle=dropdown]",Dropdown=function(element){var $el=$(element).on("click.dropdown.data-api",this.toggle);$("html").on("click.dropdown.data-api",function(){$el.parent().removeClass("open")})};Dropdown.prototype={constructor:Dropdown,toggle:function(e){var $this=$(this),$parent,isActive;if($this.is(".disabled, :disabled"))return;$parent=getParent($this);isActive=$parent.hasClass("open");clearMenus();if(!isActive){if("ontouchstart"in document.documentElement){$('
').insertBefore($(this)).on("click",clearMenus)}$parent.toggleClass("open")}$this.focus();return false},keydown:function(e){var $this,$items,$active,$parent,isActive,index;if(!/(38|40|27)/.test(e.keyCode))return;$this=$(this);e.preventDefault();e.stopPropagation();if($this.is(".disabled, :disabled"))return;$parent=getParent($this);isActive=$parent.hasClass("open");if(!isActive||isActive&&e.keyCode==27){if(e.which==27)$parent.find(toggle).focus();return $this.click()}$items=$("[role=menu] li:not(.divider):visible a",$parent);if(!$items.length)return;index=$items.index($items.filter(":focus"));if(e.keyCode==38&&index>0)index--;if(e.keyCode==40&&index<$items.length-1)index++;if(!~index)index=0;$items.eq(index).focus()}};function clearMenus(){$(".dropdown-backdrop").remove();$(toggle).each(function(){getParent($(this)).removeClass("open")})}function getParent($this){var selector=$this.attr("data-target"),$parent;if(!selector){selector=$this.attr("href");selector=selector&&/#/.test(selector)&&selector.replace(/.*(?=#[^\s]*$)/,"")}$parent=selector&&$(selector);if(!$parent||!$parent.length)$parent=$this.parent();return $parent}var old=$.fn.dropdown;$.fn.dropdown=function(option){return this.each(function(){var $this=$(this),data=$this.data("dropdown");if(!data)$this.data("dropdown",data=new Dropdown(this));if(typeof option=="string")data[option].call($this)})};$.fn.dropdown.Constructor=Dropdown;$.fn.dropdown.noConflict=function(){$.fn.dropdown=old;return this};$(document).on("click.dropdown.data-api",clearMenus).on("click.dropdown.data-api",".dropdown form",function(e){e.stopPropagation()}).on("click.dropdown.data-api",toggle,Dropdown.prototype.toggle).on("keydown.dropdown.data-api",toggle+", [role=menu]",Dropdown.prototype.keydown)}(window.jQuery);!function($){"use strict";var Tab=function(element){this.element=$(element)};Tab.prototype={constructor:Tab,show:function(){var $this=this.element,$ul=$this.closest("ul:not(.dropdown-menu)"),selector=$this.attr("data-target"),previous,$target,e;if(!selector){selector=$this.attr("href");selector=selector&&selector.replace(/.*(?=#[^\s]*$)/,"")}if($this.parent("li").hasClass("active"))return;previous=$ul.find(".active:last a")[0];e=$.Event("show",{relatedTarget:previous});$this.trigger(e);if(e.isDefaultPrevented())return;$target=$(selector);this.activate($this.parent("li"),$ul);this.activate($target,$target.parent(),function(){$this.trigger({type:"shown",relatedTarget:previous})})},activate:function(element,container,callback){var $active=container.find("> .active"),transition=callback&&$.support.transition&&$active.hasClass("fade");function next(){$active.removeClass("active").find("> .dropdown-menu > .active").removeClass("active");element.addClass("active");if(transition){element[0].offsetWidth;element.addClass("in")}else{element.removeClass("fade")}if(element.parent(".dropdown-menu")){element.closest("li.dropdown").addClass("active")}callback&&callback()}transition?$active.one($.support.transition.end,next):next();$active.removeClass("in")}};var old=$.fn.tab;$.fn.tab=function(option){return this.each(function(){var $this=$(this),data=$this.data("tab");if(!data)$this.data("tab",data=new Tab(this));if(typeof option=="string")data[option]()})};$.fn.tab.Constructor=Tab;$.fn.tab.noConflict=function(){$.fn.tab=old;return this};$(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(e){e.preventDefault();$(this).tab("show")})}(window.jQuery);!function($){"use strict";var Affix=function(element,options){this.options=$.extend({},$.fn.affix.defaults,options);this.$window=$(window).on("scroll.affix.data-api",$.proxy(this.checkPosition,this)).on("click.affix.data-api",$.proxy(function(){setTimeout($.proxy(this.checkPosition,this),1)},this));this.$element=$(element);this.checkPosition()};Affix.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var scrollHeight=$(document).height(),scrollTop=this.$window.scrollTop(),position=this.$element.offset(),offset=this.options.offset,offsetBottom=offset.bottom,offsetTop=offset.top,reset="affix affix-top affix-bottom",affix;if(typeof offset!="object")offsetBottom=offsetTop=offset;if(typeof offsetTop=="function")offsetTop=offset.top();if(typeof offsetBottom=="function")offsetBottom=offset.bottom();affix=this.unpin!=null&&scrollTop+this.unpin<=position.top?false:offsetBottom!=null&&position.top+this.$element.height()>=scrollHeight-offsetBottom?"bottom":offsetTop!=null&&scrollTop<=offsetTop?"top":false;if(this.affixed===affix)return;this.affixed=affix;this.unpin=affix=="bottom"?position.top-scrollTop:null;this.$element.removeClass(reset).addClass("affix"+(affix?"-"+affix:""))};var old=$.fn.affix;$.fn.affix=function(option){return this.each(function(){var $this=$(this),data=$this.data("affix"),options=typeof option=="object"&&option;if(!data)$this.data("affix",data=new Affix(this,options));if(typeof option=="string")data[option]()})};$.fn.affix.Constructor=Affix;$.fn.affix.defaults={offset:0};$.fn.affix.noConflict=function(){$.fn.affix=old;return this};$(window).on("load",function(){$('[data-spy="affix"]').each(function(){var $spy=$(this),data=$spy.data();data.offset=data.offset||{};data.offsetBottom&&(data.offset.bottom=data.offsetBottom);data.offsetTop&&(data.offset.top=data.offsetTop);$spy.affix(data)})})}(window.jQuery);!function($){"use strict";var Popover=function(element,options){this.init("popover",element,options)};Popover.prototype=$.extend({},$.fn.tooltip.Constructor.prototype,{constructor:Popover,setContent:function(){var $tip=this.tip(),title=this.getTitle(),content=this.getContent();$tip.find(".popover-title")[this.options.html?"html":"text"](title);$tip.find(".popover-content")[this.options.html?"html":"text"](content);$tip.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var content,$e=this.$element,o=this.options;content=(typeof o.content=="function"?o.content.call($e[0]):o.content)||$e.attr("data-content");return content},tip:function(){if(!this.$tip){this.$tip=$(this.options.template)}return this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var old=$.fn.popover;$.fn.popover=function(option){return this.each(function(){var $this=$(this),data=$this.data("popover"),options=typeof option=="object"&&option;if(!data)$this.data("popover",data=new Popover(this,options));if(typeof option=="string")data[option]()})};$.fn.popover.Constructor=Popover;$.fn.popover.defaults=$.extend({},$.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:''});$.fn.popover.noConflict=function(){$.fn.popover=old;return this}}(window.jQuery);!function($){"use strict";var Button=function(element,options){this.$element=$(element);this.options=$.extend({},$.fn.button.defaults,options)};Button.prototype.setState=function(state){var d="disabled",$el=this.$element,data=$el.data(),val=$el.is("input")?"val":"html";state=state+"Text";data.resetText||$el.data("resetText",$el[val]());$el[val](data[state]||this.options[state]);setTimeout(function(){state=="loadingText"?$el.addClass(d).attr(d,d):$el.removeClass(d).removeAttr(d)},0)};Button.prototype.toggle=function(){var $parent=this.$element.closest('[data-toggle="buttons-radio"]');$parent&&$parent.find(".active").removeClass("active");this.$element.toggleClass("active")};var old=$.fn.button;$.fn.button=function(option){return this.each(function(){var $this=$(this),data=$this.data("button"),options=typeof option=="object"&&option;if(!data)$this.data("button",data=new Button(this,options));if(option=="toggle")data.toggle();else if(option)data.setState(option)})};$.fn.button.defaults={loadingText:"loading..."};$.fn.button.Constructor=Button;$.fn.button.noConflict=function(){$.fn.button=old;return this};$(document).on("click.button.data-api","[data-toggle^=button]",function(e){var $btn=$(e.target);if(!$btn.hasClass("btn"))$btn=$btn.closest(".btn");$btn.button("toggle")})}(window.jQuery);!function($){"use strict";var dismiss='[data-dismiss="alert"]',Alert=function(el){$(el).on("click",dismiss,this.close)};Alert.prototype.close=function(e){var $this=$(this),selector=$this.attr("data-target"),$parent;if(!selector){selector=$this.attr("href");selector=selector&&selector.replace(/.*(?=#[^\s]*$)/,"")}$parent=$(selector);e&&e.preventDefault();$parent.length||($parent=$this.hasClass("alert")?$this:$this.parent());$parent.trigger(e=$.Event("close"));if(e.isDefaultPrevented())return;$parent.removeClass("in");function removeElement(){$parent.trigger("closed").remove()}$.support.transition&&$parent.hasClass("fade")?$parent.on($.support.transition.end,removeElement):removeElement()};var old=$.fn.alert;$.fn.alert=function(option){return this.each(function(){var $this=$(this),data=$this.data("alert");if(!data)$this.data("alert",data=new Alert(this));if(typeof option=="string")data[option].call($this)})};$.fn.alert.Constructor=Alert;$.fn.alert.noConflict=function(){$.fn.alert=old;return this};$(document).on("click.alert.data-api",dismiss,Alert.prototype.close)}(window.jQuery);!function($){"use strict";$(function(){$.support.transition=function(){var transitionEnd=function(){var el=document.createElement("bootstrap"),transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},name;for(name in transEndEventNames){if(el.style[name]!==undefined){return transEndEventNames[name]}}}();return transitionEnd&&{end:transitionEnd}}()})}(window.jQuery);
--------------------------------------------------------------------------------
/apps/web/priv/static/css/theme.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /*
4 | * SmartBiz - ver 2.0
5 | *
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | *
8 | * (c) 2013 Oxygenna.com
9 | *
10 | */
11 | #style-switcher {
12 | position: absolute;
13 | right: 100px;
14 | top: 50%;
15 | right: -35px;
16 | margin: -17px 0 0;
17 | z-index: 10000;
18 | }
19 |
20 | #style-switcher .btn, #style-switcher .btn-group.open .dropdown-toggle {
21 | font-size: 13px;
22 | -webkit-border-radius: 50%;
23 | -moz-border-radius: 50%;
24 | -ms-border-radius: 50%;
25 | -o-border-radius: 50%;
26 | border-radius: 50%;
27 | width: 2.5em;
28 | height: 2.5em;
29 | padding: 0;
30 | }
31 | #style-switcher .dropdown-menu {
32 | width: 250px;
33 | left: -200px;
34 | margin-top: 26px;
35 | background-color: rgba(253, 253, 253, 0.8);
36 | border-color: #e9e9e9;
37 | -webkit-box-shadow: 0px 1px 1px rgba(153, 153, 153, 0.4), 0px 0px 30px rgba(233, 233, 233, 0.4) inset;
38 | -moz-box-shadow: 0px 1px 1px rgba(153, 153, 153, 0.4), 0px 0px 30px rgba(233, 233, 233, 0.4) inset;
39 | box-shadow: 0px 1px 1px rgba(153, 153, 153, 0.4), 0px 0px 30px rgba(233, 233, 233, 0.4) inset;
40 | }
41 | #style-switcher .dropdown-menu ul {
42 | list-style-type: none;
43 | margin: 0;
44 | }
45 | #style-switcher .dropdown-menu ul:after {
46 | content: ".";
47 | display: block;
48 | height: 0;
49 | clear: both;
50 | visibility: hidden;
51 | }
52 | #style-switcher .theme-colors, #style-switcher .theme-patterns {
53 | text-align: center;
54 | }
55 | #style-switcher .theme-colors li, #style-switcher .theme-patterns li {
56 | display: inline-block;
57 | }
58 | #style-switcher .theme-colors li a, #style-switcher .theme-patterns li a {
59 | display: inline-block;
60 | text-indent: -999em;
61 | width: 42px;
62 | height: 42px;
63 | margin: 10px;
64 | padding: 0;
65 | -webkit-transition: all, 0.2s;
66 | -moz-transition: all, 0.2s;
67 | -o-transition: all, 0.2s;
68 | transition: all, 0.2s;
69 | cursor: pointer;
70 | }
71 | #style-switcher .theme-colors a {
72 | -webkit-border-radius: 50%;
73 | -moz-border-radius: 50%;
74 | -ms-border-radius: 50%;
75 | -o-border-radius: 50%;
76 | border-radius: 50%;
77 | }
78 | #style-switcher .theme-colors .color-green {
79 | background-color: #779922;
80 | -webkit-box-shadow: 0px 2px 4px #576f19 inset;
81 | -moz-box-shadow: 0px 2px 4px #576f19 inset;
82 | box-shadow: 0px 2px 4px #576f19 inset;
83 | }
84 | #style-switcher .theme-colors .color-green:hover {
85 | background-color: #6d8c1f;
86 | background-image: none;
87 | -webkit-box-shadow: 0px 3px 6px #36460f inset;
88 | -moz-box-shadow: 0px 3px 6px #36460f inset;
89 | box-shadow: 0px 3px 6px #36460f inset;
90 | }
91 | #style-switcher .theme-colors .color-red {
92 | background-color: #e8481d;
93 | -webkit-box-shadow: 0px 2px 4px #bf3813 inset;
94 | -moz-box-shadow: 0px 2px 4px #bf3813 inset;
95 | box-shadow: 0px 2px 4px #bf3813 inset;
96 | }
97 | #style-switcher .theme-colors .color-red:hover {
98 | background-color: #df4117;
99 | background-image: none;
100 | -webkit-box-shadow: 0px 3px 6px #902a0f inset;
101 | -moz-box-shadow: 0px 3px 6px #902a0f inset;
102 | box-shadow: 0px 3px 6px #902a0f inset;
103 | }
104 | #style-switcher .theme-colors .color-blue {
105 | background-color: #41b7d8;
106 | -webkit-box-shadow: 0px 2px 4px #279ebf inset;
107 | -moz-box-shadow: 0px 2px 4px #279ebf inset;
108 | box-shadow: 0px 2px 4px #279ebf inset;
109 | }
110 | #style-switcher .theme-colors .color-blue:hover {
111 | background-color: #34b2d5;
112 | background-image: none;
113 | -webkit-box-shadow: 0px 3px 6px #1e7b95 inset;
114 | -moz-box-shadow: 0px 3px 6px #1e7b95 inset;
115 | box-shadow: 0px 3px 6px #1e7b95 inset;
116 | }
117 | #style-switcher .theme-patterns li {
118 | display: block;
119 | float: left;
120 | }
121 | #style-switcher .theme-patterns li:nth-child(4n+1) {
122 | clear: both;
123 | }
124 | #style-switcher .theme-patterns a {
125 | -webkit-box-shadow: 0px 1px 4px rgba(85, 85, 85, 0.5) inset;
126 | -moz-box-shadow: 0px 1px 4px rgba(85, 85, 85, 0.5) inset;
127 | box-shadow: 0px 1px 4px rgba(85, 85, 85, 0.5) inset;
128 | }
129 | #style-switcher .theme-patterns a:hover {
130 | background-color: transparent;
131 | -webkit-box-shadow: 0px 1px 6px rgba(85, 85, 85, 0.7) inset;
132 | -moz-box-shadow: 0px 1px 6px rgba(85, 85, 85, 0.7) inset;
133 | box-shadow: 0px 1px 6px rgba(85, 85, 85, 0.7) inset;
134 | }
135 | #style-switcher .theme-patterns .pattern-lightmesh {
136 | background-image: url(/static/img/theme/lghtmesh.png);
137 | }
138 | #style-switcher .theme-patterns .pattern-bedge-grunge {
139 | background-image: url(/static/img/theme/bedge_grunge.png);
140 | }
141 | #style-switcher .theme-patterns .pattern-grid {
142 | background-image: url(/static/img/theme/grid.png);
143 | }
144 | #style-switcher .theme-patterns .pattern-noisy-grid {
145 | background-image: url(/static/img/theme/noisy_grid.png);
146 | }
147 | #style-switcher .theme-patterns .pattern-subtle-grey {
148 | background-image: url(/static/img/theme/grey.png);
149 | }
150 | #style-switcher .theme-patterns .pattern-retina-wood {
151 | background-image: url(/static/img/theme/retina_wood.png);
152 | }
153 | #style-switcher .theme-patterns .pattern-noise-lines {
154 | background-image: url(/static/img/theme/noise_lines.png);
155 | }
156 | #style-switcher .theme-patterns .pattern-tiny-grid {
157 | background-image: url(/static/img/theme/tiny_grid.png);
158 | }
159 | #style-switcher .theme-patterns .pattern-clean-paper {
160 | background-image: url(/static/img/theme/extra_clean_paper.png);
161 | }
162 | #style-switcher .theme-patterns .pattern-farmer {
163 | background-image: url(/static/img/theme/farmer.png);
164 | }
165 | #style-switcher .theme-patterns .pattern-project-papper {
166 | background-image: url(/static/img/theme/project_papper.png);
167 | }
168 | #style-switcher .theme-patterns .pattern-concrete-wall {
169 | background-image: url(/static/img/theme/concrete_wall_2.png);
170 | }
171 | #style-switcher .theme-patterns .pattern-wavecut {
172 | background-image: url(/static/img/theme/wavecut.png);
173 | }
174 | #style-switcher .theme-patterns .pattern-little-pluses {
175 | background-image: url(/static/img/theme/little_pluses.png);
176 | }
177 | #style-switcher .theme-patterns .pattern-light-honeycomp {
178 | background-image: url(/static/img/theme/light_honeycomb.png);
179 | }
180 | #style-switcher .theme-patterns .pattern-old-mathematics {
181 | background-image: url(/static/img/theme/old_mathematics.png);
182 | }
183 | #style-switcher .theme-patterns .pattern-45-degree-fabric {
184 | background-image: url(/static/img/theme/45degreee_fabric.png);
185 | }
186 | #style-switcher .theme-patterns .pattern-strange-bullseyes {
187 | background-image: url(/static/img/theme/strange_bullseyes.png);
188 | }
189 | #style-switcher .theme-patterns .pattern-diamond-upholstery {
190 | background-image: url(/static/img/theme/diamond_upholstery.png);
191 | }
192 | #style-switcher .theme-patterns .pattern-subtle-stripes {
193 | background-image: url(/static/img/theme/subtle_stripes.png);
194 | }
195 |
196 | /* GENERAL MARKUP RULES */
197 | /* -------------------- */
198 | body {
199 | padding-top: 80px;
200 | background-position: 0 100px;
201 | }
202 |
203 | /* Header */
204 | h1, h2, h3, h4, h5 {
205 | text-transform: uppercase;
206 | margin: 0;
207 | }
208 | h1 small, h2 small, h3 small, h4 small, h5 small {
209 | text-transform: none;
210 | }
211 |
212 | h1 {
213 | font-size: 30px;
214 | line-height: 48px;
215 | }
216 |
217 | h1 small {
218 | font-size: 18px;
219 | }
220 |
221 | h2 {
222 | font-size: 24px;
223 | line-height: 48px;
224 | }
225 |
226 | h2 small {
227 | font-size: 18px;
228 | }
229 |
230 | h3 {
231 | font-size: 18px;
232 | line-height: 36px;
233 | }
234 |
235 | h3 small {
236 | font-size: 14px;
237 | }
238 |
239 | h4, h5, h6 {
240 | line-height: 24px;
241 | }
242 |
243 | h4 {
244 | font-size: 14px;
245 | }
246 |
247 | h4 small {
248 | font-size: 12px;
249 | }
250 |
251 | h5 {
252 | font-size: 12px;
253 | }
254 |
255 | h6 {
256 | font-size: 11px;
257 | color: #999999;
258 | text-transform: uppercase;
259 | }
260 |
261 | /* Links */
262 | a {
263 | color: #41b7d8;
264 | text-decoration: none;
265 | }
266 | a:hover {
267 | color: #6bc7e1;
268 | text-decoration: none;
269 | }
270 |
271 | /* figures */
272 | figure {
273 | margin-bottom: 24px;
274 | }
275 |
276 | /* PAGE SECTIONS */
277 | /* ------------- */
278 | .section {
279 | padding: 30px 0px;
280 | margin: 0;
281 | position: relative;
282 | }
283 | .section.alt {
284 | background-repeat: repeat;
285 | -webkit-box-shadow: 0 -1px 3px rgba(0, 0, 0, 0.25) inset, 0 1px 3px rgba(0, 0, 0, 0.25) inset;
286 | -moz-box-shadow: 0 -1px 3px rgba(0, 0, 0, 0.25) inset, 0 1px 3px rgba(0, 0, 0, 0.25) inset;
287 | box-shadow: 0 -1px 3px rgba(0, 0, 0, 0.25) inset, 0 1px 3px rgba(0, 0, 0, 0.25) inset;
288 | text-shadow: 1px 1px 1px white;
289 | }
290 |
291 | /* HEADER SECTION */
292 | /* -------------- */
293 | #masthead .brand {
294 | font-weight: 800;
295 | font-size: 30px;
296 | line-height: 30px;
297 | padding: 23px 20px 27px;
298 | margin-top: 0;
299 | margin-bottom: 0;
300 | }
301 | #masthead .brand a {
302 | color: #555555;
303 | }
304 | #masthead .brand i {
305 | line-height: 20px;
306 | -webkit-transition: all 0.2s;
307 | -moz-transition: all 0.2s;
308 | -o-transition: all 0.2s;
309 | transition: all 0.2s;
310 | }
311 | #masthead .brand:hover i {
312 | -webkit-transform: rotate(8deg);
313 | -moz-transform: rotate(8deg);
314 | -ms-transform: rotate(8deg);
315 | -o-transform: rotate(8deg);
316 | transform: rotate(8deg);
317 | color: #41b7d8;
318 | }
319 |
320 | .navbar-inner {
321 | background: white;
322 | -webkit-box-shadow: none;
323 | -moz-box-shadow: none;
324 | box-shadow: none;
325 | border-bottom: 1px solid #e9e9e9;
326 | }
327 |
328 | .navbar .nav > li > a {
329 | text-shadow: none;
330 | text-transform: uppercase;
331 | font-weight: bold;
332 | padding: 29px 10px 31px;
333 | line-height: 19px;
334 | }
335 |
336 | .navbar .nav > .active > a, .navbar .nav > .active > a:hover, .navbar .nav > .active > a:focus {
337 | -webkit-box-shadow: none;
338 | -moz-box-shadow: none;
339 | box-shadow: none;
340 | }
341 |
342 | .dropdown-menu {
343 | font-size: 14px;
344 | background: white;
345 | /* background: rgba(255, 255, 255, 0.9);*/
346 | }
347 |
348 | .navbar .nav li.dropdown .dropdown-toggle .caret, .navbar .nav li.dropdown.open .caret {
349 | border-top-color: #555555;
350 | border-bottom-color: #555555;
351 | }
352 |
353 | .navbar .nav li.dropdown.active > .dropdown-toggle:hover {
354 | color: #41b7d8;
355 | }
356 |
357 | .navbar .btn-navbar {
358 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #333333), color-stop(100%, #555555));
359 | background-image: -webkit-linear-gradient(#333333, #555555);
360 | background-image: -moz-linear-gradient(#333333, #555555);
361 | background-image: -o-linear-gradient(#333333, #555555);
362 | background-image: linear-gradient(#333333, #555555);
363 | background-color: #555555;
364 | }
365 | .navbar .btn-navbar:hover {
366 | color: white;
367 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
368 | background-color: #0e0e0e;
369 | background-image: -moz-linear-gradient(top, #151515, #040404);
370 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));
371 | background-image: -webkit-linear-gradient(top, #151515, #040404);
372 | background-image: -o-linear-gradient(top, #151515, #040404);
373 | background-image: linear-gradient(to bottom, #151515, #040404);
374 | background-repeat: repeat-x;
375 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF151515', endColorstr='#FF040404', GradientType=0);
376 | border-color: #040404 #040404 black;
377 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
378 | *background-color: #040404;
379 | /* Darken IE7 buttons by default so they stand out more given they won't have borders */
380 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
381 | }
382 | .navbar .btn-navbar:hover:hover, .navbar .btn-navbar:hover:active, .navbar .btn-navbar:hover.active, .navbar .btn-navbar:hover.disabled, .navbar .btn-navbar:hover[disabled] {
383 | color: white;
384 | background-color: #040404;
385 | *background-color: black;
386 | }
387 | .navbar .btn-navbar:hover:active, .navbar .btn-navbar:hover.active {
388 | background-color: black \9;
389 | }
390 |
391 | .navbar .nav.pull-right {
392 | margin-left: 10px;
393 | margin-right: 0;
394 | }
395 |
396 | .navbar .nav li.dropdown.open > .dropdown-toggle, .navbar .nav li.dropdown.active > .dropdown-toggle, .navbar .nav li.dropdown.open.active > .dropdown-toggle {
397 | color: #41b7d8;
398 | }
399 |
400 | /* FOOTER SECTION */
401 | /* --------------- */
402 | #footer {
403 | background: #333333;
404 | color: #e9e9e9;
405 | border-top: 1px solid black;
406 | text-shadow: 1px 1px 1px #222222;
407 | -webkit-box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.25) inset;
408 | -moz-box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.25) inset;
409 | box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.25) inset;
410 | }
411 | #footer small {
412 | color: #e9e9e9;
413 | font-style: italic;
414 | }
415 |
416 | /* BOOTSTRAP UTILITIES */
417 | /* --------------------*/
418 | /* hero unit */
419 | .hero-unit {
420 | margin-bottom: 0;
421 | }
422 | .alt .hero-unit {
423 | padding-left: 0;
424 | padding-right: 0;
425 | background: none;
426 | }
427 |
428 | .hero-huge h1 {
429 | font-size: 20em;
430 | }
431 |
432 | /* fancy blockquote */
433 | .blockquote-fancy {
434 | padding-left: 0;
435 | border-left: 0;
436 | margin-bottom: 0;
437 | position: relative;
438 | z-index: 1;
439 | overflow: hidden;
440 | border-bottom: 1px solid #e9e9e9;
441 | }
442 | .section.alt .blockquote-fancy {
443 | border-bottom: 0;
444 | }
445 | .blockquote-fancy p {
446 | font-size: 30px;
447 | padding: 30px 30px 30px 210px;
448 | line-height: 1.5em;
449 | }
450 | .blockquote-fancy .blockquote-img {
451 | display: block;
452 | width: 180px;
453 | height: 180px;
454 | position: absolute;
455 | top: 30px;
456 | left: 0;
457 | -webkit-border-radius: 50%;
458 | -moz-border-radius: 50%;
459 | -ms-border-radius: 50%;
460 | -o-border-radius: 50%;
461 | border-radius: 50%;
462 | -webkit-box-shadow: 0 0 10px rgba(51, 51, 51, 0.9) inset;
463 | -moz-box-shadow: 0 0 10px rgba(51, 51, 51, 0.9) inset;
464 | box-shadow: 0 0 10px rgba(51, 51, 51, 0.9) inset;
465 | border: 10px solid #e9e9e9;
466 | -webkit-transition: all 0.2s;
467 | -moz-transition: all 0.2s;
468 | -o-transition: all 0.2s;
469 | transition: all 0.2s;
470 | z-index: -1;
471 | }
472 | .blockquote-fancy .blockquote-img img {
473 | -webkit-transition: all 0.2s;
474 | -moz-transition: all 0.2s;
475 | -o-transition: all 0.2s;
476 | transition: all 0.2s;
477 | -webkit-border-radius: 50%;
478 | -moz-border-radius: 50%;
479 | -ms-border-radius: 50%;
480 | -o-border-radius: 50%;
481 | border-radius: 50%;
482 | opacity: .4;
483 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";
484 | }
485 | .blockquote-fancy:hover .blockquote-img {
486 | border-color: rgba(153, 153, 153, 0.3);
487 | }
488 | .blockquote-fancy:hover .blockquote-img img {
489 | opacity: .8;
490 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";
491 | }
492 | .blockquote-fancy a {
493 | font-size: 24px;
494 | display: block;
495 | margin-top: 10px;
496 | font-weight: bold;
497 | }
498 | .blockquote-fancy.blockquote-fancy-small p {
499 | font-size: 24px;
500 | padding: 30px 30px 30px 110px;
501 | }
502 | .blockquote-fancy.blockquote-fancy-small:before {
503 | font-size: 10em;
504 | }
505 | .blockquote-fancy.blockquote-fancy-small .blockquote-img {
506 | width: 80px;
507 | height: 80px;
508 | }
509 | .blockquote-fancy.blockquote-fancy-small a {
510 | font-size: 16px;
511 | }
512 | .blockquote-fancy.blockquote-fancy-icon p {
513 | padding: 30px;
514 | }
515 | .blockquote-fancy.blockquote-fancy-icon:before {
516 | font-family: "FontAwesome";
517 | position: absolute;
518 | top: 0;
519 | left: 0;
520 | line-height: 1;
521 | content: "\f075";
522 | font-size: 15em;
523 | color: #e9e9e9;
524 | z-index: -1;
525 | opacity: .5;
526 | }
527 | .alt .blockquote-fancy.blockquote-fancy-icon:before {
528 | color: white;
529 | }
530 |
531 | /* well */
532 | .well {
533 | background: white;
534 | background: rgba(255, 255, 255, 0.8);
535 | border: 1px solid white;
536 | -webkit-box-shadow: 0px 0px 3px rgba(51, 51, 51, 0.2);
537 | -moz-box-shadow: 0px 0px 3px rgba(51, 51, 51, 0.2);
538 | box-shadow: 0px 0px 3px rgba(51, 51, 51, 0.2);
539 | }
540 | .well h3 {
541 | text-align: center;
542 | border-bottom: 1px solid white;
543 | -webkit-box-shadow: 0px 1px 0px #e9e9e9;
544 | -moz-box-shadow: 0px 1px 0px #e9e9e9;
545 | box-shadow: 0px 1px 0px #e9e9e9;
546 | margin-bottom: 10px;
547 | padding-bottom: 10px;
548 | }
549 |
550 | /* page header */
551 | .page-header {
552 | margin: 24px 0;
553 | padding-bottom: 23px;
554 | }
555 | .page-header h1 {
556 | line-height: 1;
557 | }
558 | .page-header a {
559 | color: #999999;
560 | }
561 | .page-header a:hover {
562 | color: #555555;
563 | text-decoration: none;
564 | }
565 | .alt .page-header {
566 | border-color: #d0d0d0;
567 | }
568 |
569 | .pager a {
570 | color: #555555;
571 | }
572 |
573 | /* Docks Afix navigation */
574 | .docs-sidebar-nav {
575 | list-style-type: none;
576 | margin: 24px 20px 0 0;
577 | padding: 0;
578 | width: 210px;
579 | }
580 | .docs-sidebar-nav li a {
581 | color: #555555;
582 | margin: 0 0 10px;
583 | text-align: right;
584 | text-transform: uppercase;
585 | padding-right: 20px;
586 | background-color: transparent;
587 | border-right: 3px solid #555555;
588 | text-shadow: none;
589 | }
590 | .docs-sidebar-nav li.active a, .docs-sidebar-nav li.active a:hover, .docs-sidebar-nav li a:hover {
591 | color: #41b7d8;
592 | border-right: 3px solid #41b7d8;
593 | background-color: transparent;
594 | text-shadow: none;
595 | }
596 |
597 | /* affix bottom */
598 | .affix-bottom {
599 | position: absolute;
600 | bottom: 20px;
601 | margin-bottom: 20px;
602 | }
603 |
604 | .docs-header {
605 | padding-top: 100px;
606 | }
607 |
608 | /* tolltips */
609 | .tooltip-inner {
610 | background-color: #41b7d8;
611 | color: white;
612 | }
613 |
614 | .tooltip.top .tooltip-arrow {
615 | border-top-color: #41b7d8;
616 | }
617 | .tooltip.right .tooltip-arrow {
618 | border-right-color: #41b7d8;
619 | }
620 | .tooltip.left .tooltip-arrow {
621 | border-left-color: #41b7d8;
622 | }
623 | .tooltip.bottom .tooltip-arrow {
624 | border-bottom-color: #41b7d8;
625 | }
626 |
627 | /* THEME UTILITIES */
628 | /* ----------------*/
629 | /* align center inline elements */
630 | .pull-center {
631 | text-align: center;
632 | margin-left: auto;
633 | margin-right: auto;
634 | }
635 |
636 | /* Bottom bordered lists */
637 | .bordered {
638 | margin-bottom: 0;
639 | }
640 | .bordered > li {
641 | border-bottom: 1px solid #e9e9e9;
642 | }
643 | .alt .bordered > li {
644 | border-color: #d0d0d0;
645 | }
646 |
647 | /* Block display class */
648 | .blocked {
649 | display: block;
650 | }
651 |
652 | /* icon lists */
653 | .icons {
654 | list-style-type: none;
655 | margin-left: 2em;
656 | text-indent: -1em;
657 | }
658 | .icons li [class^="icon-"], .icons li [class*=" icon-"] {
659 | display: inline-block;
660 | text-align: center;
661 | width: 1em;
662 | }
663 | .icons li small {
664 | display: block;
665 | text-indent: 0;
666 | }
667 |
668 | /* big icons */
669 | .huge-icon {
670 | font-size: 3em;
671 | }
672 |
673 | .enormous-icon {
674 | font-size: 5em;
675 | line-height: 1;
676 | }
677 | .enormous-icon.circled {
678 | display: block;
679 | width: 1.4em;
680 | height: 1.4em;
681 | line-height: 1.4em;
682 | -webkit-border-radius: 50%;
683 | -moz-border-radius: 50%;
684 | -ms-border-radius: 50%;
685 | -o-border-radius: 50%;
686 | border-radius: 50%;
687 | background-color: #333333;
688 | color: white;
689 | }
690 |
691 | /* thumbnail figures */
692 | .thumbnail-figure {
693 | margin: 0 0 24px;
694 | position: relative;
695 | background: #333333;
696 | }
697 | .thumbnail-figure img {
698 | -webkit-transition: all 0.2s;
699 | -moz-transition: all 0.2s;
700 | -o-transition: all 0.2s;
701 | transition: all 0.2s;
702 | }
703 | .thumbnail-figure img:hover {
704 | opacity: .4;
705 | }
706 |
707 | .thumbnail-title {
708 | position: absolute;
709 | top: 50%;
710 | margin-top: 30px;
711 | -webkit-transition: all 0.2s;
712 | -moz-transition: all 0.2s;
713 | -o-transition: all 0.2s;
714 | transition: all 0.2s;
715 | }
716 | .thumbnail-title span {
717 | display: inline-block;
718 | background: white;
719 | background: rgba(255, 255, 255, 0.8);
720 | color: black;
721 | padding: 5px 10px;
722 | text-shadow: 1px 1px 1px white;
723 | margin-top: 1px;
724 | }
725 |
726 | .inactive .thumbnail-figure img {
727 | opacity: .4;
728 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)";
729 | }
730 | .inactive .thumbnail-title {
731 | opacity: 0;
732 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
733 | }
734 | .inactive a {
735 | cursor: default;
736 | }
737 |
738 | /* Pricing tables */
739 | .pricing-table {
740 | position: relative;
741 | -webkit-box-shadow: 0px 0px 10px rgba(153, 153, 153, 0.5), 0px 0px 20px rgba(153, 153, 153, 0.2) inset;
742 | -moz-box-shadow: 0px 0px 10px rgba(153, 153, 153, 0.5), 0px 0px 20px rgba(153, 153, 153, 0.2) inset;
743 | box-shadow: 0px 0px 10px rgba(153, 153, 153, 0.5), 0px 0px 20px rgba(153, 153, 153, 0.2) inset;
744 | }
745 |
746 | .pricing-table-price {
747 | font-size: 30px;
748 | margin: -10px -20px 0 -20px;
749 | padding: 8px 0 10px;
750 | background-color: #eeeeee;
751 | -webkit-box-shadow: 0px 0px 10px rgba(153, 153, 153, 0.2) inset;
752 | -moz-box-shadow: 0px 0px 10px rgba(153, 153, 153, 0.2) inset;
753 | box-shadow: 0px 0px 10px rgba(153, 153, 153, 0.2) inset;
754 | color: #41b7d8;
755 | text-shadow: 1px 1px 0 white;
756 | }
757 | .pricing-table-price span {
758 | font-weight: normal;
759 | }
760 |
761 | .pricing-table-list {
762 | list-style-type: none;
763 | margin: 0 0 20px;
764 | border-bottom: 1px solid white;
765 | -webkit-box-shadow: 0px 1px 0px #e9e9e9;
766 | -moz-box-shadow: 0px 1px 0px #e9e9e9;
767 | box-shadow: 0px 1px 0px #e9e9e9;
768 | }
769 | .pricing-table-list li {
770 | border-top: 1px solid white;
771 | -webkit-box-shadow: 0px -1px 0px #e9e9e9;
772 | -moz-box-shadow: 0px -1px 0px #e9e9e9;
773 | box-shadow: 0px -1px 0px #e9e9e9;
774 | padding: 8px;
775 | }
776 | .pricing-table-list li:first-child {
777 | border-color: transparent;
778 | -webkit-box-shadow: none;
779 | -moz-box-shadow: none;
780 | box-shadow: none;
781 | }
782 |
783 | .pricing-table-featured {
784 | background: #41b7d8;
785 | border-color: #238caa;
786 | color: white;
787 | text-shadow: 0px 1px 0px #279ebf;
788 | }
789 | .pricing-table-featured .pricing-table-price {
790 | text-shadow: 1px 1px 0 white;
791 | color: #41b7d8;
792 | }
793 | .pricing-table-featured h3 {
794 | border-bottom: 0 none;
795 | }
796 | .pricing-table-featured h3 span:after {
797 | display: inline-block;
798 | font-family: "FontAwesome";
799 | content: "\f069";
800 | padding-left: 10px;
801 | }
802 | .pricing-table-featured .pricing-table-list {
803 | border-color: #279ebf;
804 | -webkit-box-shadow: 0px 1px 0px #6bc7e1;
805 | -moz-box-shadow: 0px 1px 0px #6bc7e1;
806 | box-shadow: 0px 1px 0px #6bc7e1;
807 | }
808 | .pricing-table-featured li {
809 | border-color: #6bc7e1;
810 | -webkit-box-shadow: 0px -1px 0px #279ebf;
811 | -moz-box-shadow: 0px -1px 0px #279ebf;
812 | box-shadow: 0px -1px 0px #279ebf;
813 | }
814 | .pricing-table-featured li:first-child {
815 | border-color: transparent;
816 | -webkit-box-shadow: none;
817 | -moz-box-shadow: none;
818 | box-shadow: none;
819 | }
820 |
821 | .pricing-table-featured.featured-orange {
822 | background: #f89406;
823 | border-color: #c67605;
824 | color: white;
825 | text-shadow: 0px 1px 0px #c67605;
826 | }
827 | .pricing-table-featured.featured-orange .pricing-table-price {
828 | text-shadow: 1px 1px 0 white;
829 | color: #f89406;
830 | }
831 | .pricing-table-featured.featured-orange h3 {
832 | border-bottom: 0 none;
833 | }
834 | .pricing-table-featured.featured-orange .pricing-table-list {
835 | border-color: #c67605;
836 | -webkit-box-shadow: 0px 1px 0px #faa937;
837 | -moz-box-shadow: 0px 1px 0px #faa937;
838 | box-shadow: 0px 1px 0px #faa937;
839 | }
840 | .pricing-table-featured.featured-orange li {
841 | border-color: #faa937;
842 | -webkit-box-shadow: 0px -1px 0px #c67605;
843 | -moz-box-shadow: 0px -1px 0px #c67605;
844 | box-shadow: 0px -1px 0px #c67605;
845 | }
846 | .pricing-table-featured.featured-orange li:first-child {
847 | border-color: transparent;
848 | -webkit-box-shadow: none;
849 | -moz-box-shadow: none;
850 | box-shadow: none;
851 | }
852 |
853 | /* progress bars */
854 | .progress-striped .bar {
855 | background-color: #ababab;
856 | }
857 |
858 | /* filters */
859 | .thumbnail-filters .active {
860 | color: #555555;
861 | }
862 |
863 | /* 404 PAGE */
864 | /* ---------- */
865 | .hero-404 {
866 | position: relative;
867 | }
868 | .hero-404 h1 {
869 | position: relative;
870 | z-index: 1;
871 | }
872 | .hero-404 h1:after {
873 | font-family: fontAwesome;
874 | content: "\f0e7";
875 | color: rgba(255, 255, 255, 0.1);
876 | font-size: 1.3em;
877 | width: 1em;
878 | position: absolute;
879 | display: inline-block;
880 | text-align: center;
881 | top: 0;
882 | left: 50%;
883 | margin-left: -0.5em;
884 | z-index: -1;
885 | opacity: 0.5;
886 | }
887 | .hero-404 p {
888 | position: relative;
889 | z-index: 2;
890 | }
891 |
892 | /* BLOG PAGES */
893 | /* ---------- */
894 | .blog-post {
895 | padding-bottom: 24px;
896 | }
897 |
898 | .blog-header {
899 | padding-bottom: 23px;
900 | margin: 24px 0;
901 | border-bottom: 1px solid #eeeeee;
902 | }
903 | .blog-header h2 {
904 | line-height: 1;
905 | }
906 | .blog-header h2 small {
907 | font-size: 14px;
908 | }
909 | .blog-header a {
910 | color: #999999;
911 | }
912 | .blog-header a:hover {
913 | color: #555555;
914 | text-decoration: none;
915 | }
916 |
917 | .blog-footer {
918 | margin: 24px 0;
919 | padding: 12px 0;
920 | background-color: white;
921 | border-top: 1px solid #e9e9e9;
922 | border-bottom: 1px solid #e9e9e9;
923 | font-size: 14px;
924 | color: #555555;
925 | }
926 | .blog-footer a {
927 | color: #555555;
928 | }
929 | .blog-footer a:hover {
930 | color: #333333;
931 | }
932 |
933 | .blog-tags {
934 | text-align: center;
935 | }
936 |
937 | .blog-more {
938 | text-align: right;
939 | }
940 |
941 | /* comments */
942 | .comments {
943 | padding-bottom: 24px;
944 | margin-bottom: 24px;
945 | border-bottom: 1px solid #e9e9e9;
946 | }
947 |
948 | .media-comment {
949 | margin-top: 24px;
950 | }
951 | .media-comment .media {
952 | margin-top: 24px;
953 | }
954 | .media-comment .media-heading {
955 | position: relative;
956 | font-size: 14px;
957 | color: #555555;
958 | }
959 |
960 | .comments-form h3 {
961 | margin-bottom: 24px;
962 | }
963 | .comments-form textarea {
964 | height: 200px;
965 | }
966 |
967 | /* SIDEBAR */
968 | /* ------- */
969 | .sidebar-widget {
970 | margin-bottom: 48px;
971 | }
972 |
973 | .sidebar-header {
974 | margin: 24px 0;
975 | padding-bottom: 23px;
976 | border-bottom: 1px solid #e9e9e9;
977 | line-height: 1;
978 | }
979 |
980 | /* sidebar search */
981 | #search-button {
982 | width: auto;
983 | }
984 |
985 | /* CAROUSEL */
986 | /* -------- */
987 | .carousel, .carousel .slider {
988 | line-height: inherit;
989 | -webkit-transition: all 0.2s;
990 | -moz-transition: all 0.2s;
991 | -o-transition: all 0.2s;
992 | transition: all 0.2s;
993 | }
994 |
995 | .carousel-control {
996 | background: none;
997 | border: 0 none;
998 | top: 50%;
999 | color: #333333;
1000 | left: -30px;
1001 | text-align: left;
1002 | width: 20px;
1003 | }
1004 | .carousel-control.right {
1005 | right: -30px;
1006 | left: auto;
1007 | text-align: right;
1008 | }
1009 | .carousel-control:hover {
1010 | color: #41b7d8;
1011 | }
1012 |
1013 | .theme-color-green .carousel-control:hover {
1014 | color: #779922;
1015 | }
1016 |
1017 | /* MAP AREA */
1018 | /* -------- */
1019 | #map {
1020 | height: 500px;
1021 | margin: -30px 0px;
1022 | position: relative;
1023 | z-index: 0;
1024 | }
1025 | #map img {
1026 | max-width: none;
1027 | }
1028 |
1029 | .map-top-shadow, .map-bottom-shadow {
1030 | position: absolute;
1031 | height: 10px;
1032 | left: 0;
1033 | width: 100%;
1034 | z-index: 1;
1035 | }
1036 |
1037 | .map-top-shadow {
1038 | top: 0;
1039 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25) inset;
1040 | -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25) inset;
1041 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25) inset;
1042 | }
1043 |
1044 | .map-bottom-shadow {
1045 | bottom: 0;
1046 | -webkit-box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.25) inset;
1047 | -moz-box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.25) inset;
1048 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.25) inset;
1049 | }
1050 |
1051 | /* MODALS */
1052 | /* ------ */
1053 | /* login modal */
1054 | .modal.modal-login {
1055 | position: relative;
1056 | top: auto;
1057 | left: 0;
1058 | margin: 50px auto 20px;
1059 | z-index: 1;
1060 | max-width: 100%;
1061 | border: 1px solid #cccccc;
1062 | -webkit-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
1063 | -moz-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
1064 | box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
1065 | -webkit-border-radius: 0;
1066 | -moz-border-radius: 0;
1067 | -ms-border-radius: 0;
1068 | -o-border-radius: 0;
1069 | border-radius: 0;
1070 | background-color: transparent;
1071 | }
1072 | .modal.modal-login .modal-header {
1073 | background-color: #f5f5f5;
1074 | background-color: rgba(245, 245, 245, 0.7);
1075 | border-bottom: 1px solid #ddd;
1076 | -webkit-box-shadow: 0px -1px 0px white inset;
1077 | -moz-box-shadow: 0px -1px 0px white inset;
1078 | box-shadow: 0px -1px 0px white inset;
1079 | }
1080 | .modal.modal-login .modal-header h3 {
1081 | text-transform: none;
1082 | text-align: center;
1083 | font-weight: normal;
1084 | line-height: 45px;
1085 | }
1086 | .modal.modal-login .modal-header .close {
1087 | margin-top: 10px;
1088 | }
1089 | .modal.modal-login .modal-body {
1090 | background-color: white;
1091 | background-color: rgba(255, 255, 255, 0.8);
1092 | overflow: visible;
1093 | }
1094 | .modal.modal-login .modal-footer {
1095 | background-color: #f5f5f5;
1096 | background-color: rgba(245, 245, 245, 0.7);
1097 | -webkit-border-radius: 0;
1098 | -moz-border-radius: 0;
1099 | -ms-border-radius: 0;
1100 | -o-border-radius: 0;
1101 | border-radius: 0;
1102 | }
1103 | .modal.modal-login form {
1104 | margin: 0px;
1105 | }
1106 | .modal.modal-login form .add-on i {
1107 | color: #999999;
1108 | }
1109 | .modal.modal-login .link-forgot {
1110 | font-size: 14px;
1111 | line-height: 34px;
1112 | }
1113 |
1114 | /* THEME PATTERNS */
1115 | /* -------------- */
1116 | .theme-pattern-lightmesh .section.alt, .theme-pattern-lightmesh.alt {
1117 | background-image: url(/static/img/theme/lghtmesh.png);
1118 | background-size: 256px 256px;
1119 | }
1120 |
1121 | .theme-pattern-bedge-grunge .section.alt, .theme-pattern-bedge-grunge.alt {
1122 | background-image: url(/static/img/theme/bedge_grunge.png);
1123 | background-size: 588px 375px;
1124 | }
1125 |
1126 | .theme-pattern-grid .section.alt, .theme-pattern-grid.alt {
1127 | background-image: url(/static/img/theme/grid.png);
1128 | background-size: 310px 310px;
1129 | }
1130 |
1131 | .theme-pattern-noisy-grid .section.alt, .theme-pattern-noisy-grid.alt {
1132 | background-image: url(/static/img/theme/noisy_grid.png);
1133 | background-size: 150px 150px;
1134 | }
1135 |
1136 | .theme-pattern-subtle-grey .section.alt, .theme-pattern-subtle-grey.alt {
1137 | background-image: url(/static/img/theme/grey.png);
1138 | background-size: 397px 322px;
1139 | }
1140 |
1141 | .theme-pattern-retina-wood .section.alt, .theme-pattern-retina-wood.alt {
1142 | background-image: url(/static/img/theme/retina_wood.png);
1143 | background-size: 512px 512px;
1144 | }
1145 |
1146 | .theme-pattern-noise-lines .section.alt, .theme-pattern-noise-lines.alt {
1147 | background-image: url(/static/img/theme/noise_lines.png);
1148 | background-size: 60px 59px;
1149 | }
1150 |
1151 | .theme-pattern-tiny-grid .section.alt, .theme-pattern-tiny-grid.alt {
1152 | background-image: url(/static/img/theme/tiny_grid.png);
1153 | background-size: 26px 26px;
1154 | }
1155 |
1156 | .theme-pattern-clean-paper .section.alt, .theme-pattern-clean-paper.alt {
1157 | background-image: url(/static/img/theme/extra_clean_paper.png);
1158 | background-size: 512px 512px;
1159 | }
1160 |
1161 | .theme-pattern-farmer .section.alt, .theme-pattern-farmer.alt {
1162 | background-image: url(/static/img/theme/farmer.png);
1163 | background-size: 349px 349px;
1164 | }
1165 |
1166 | .theme-pattern-project-papper .section.alt, .theme-pattern-project-papper.alt {
1167 | background-image: url(/static/img/theme/project_papper.png);
1168 | background-size: 105px 105px;
1169 | }
1170 |
1171 | .theme-pattern-concrete-wall .section.alt, .theme-pattern-concrete-wall.alt {
1172 | background-image: url(/static/img/theme/concrete_wall_2.png);
1173 | background-size: 597px 545px;
1174 | }
1175 |
1176 | .theme-pattern-wavecut .section.alt, .theme-pattern-wavecut.alt {
1177 | background-image: url(/static/img/theme/wavecut.png);
1178 | background-size: 162px 15px;
1179 | }
1180 |
1181 | .theme-pattern-little-pluses .section.alt, .theme-pattern-little-pluses.alt {
1182 | background-image: url(/static/img/theme/little_pluses.png);
1183 | background-size: 300px 300px;
1184 | }
1185 |
1186 | .theme-pattern-light-honeycomp .section.alt, .theme-pattern-light-honeycomp.alt {
1187 | background-image: url(/static/img/theme/light_honeycomb.png);
1188 | background-size: 270px 289px;
1189 | }
1190 |
1191 | .theme-pattern-old-mathematics .section.alt, .theme-pattern-old-mathematics.alt {
1192 | background-image: url(/static/img/theme/old_mathematics.png);
1193 | background-size: 200px 200px;
1194 | }
1195 |
1196 | .theme-pattern-45-degree-fabric .section.alt, .theme-pattern-45-degree-fabric.alt {
1197 | background-image: url(/static/img/theme/45degreee_fabric.png);
1198 | background-size: 315px 315px;
1199 | }
1200 |
1201 | .theme-pattern-strange-bullseyes .section.alt, .theme-pattern-strange-bullseyes.alt {
1202 | background-image: url(/static/img/theme/strange_bullseyes.png);
1203 | background-size: 300px 300px;
1204 | }
1205 |
1206 | .theme-pattern-diamond-upholstery .section.alt, .theme-pattern-diamond-upholstery.alt {
1207 | background-image: url(/static/img/theme/diamond_upholstery.png);
1208 | background-size: 200px 200px;
1209 | }
1210 |
1211 | .theme-pattern-subtle-stripes .section.alt, .theme-pattern-subtle-stripes.alt {
1212 | background-image: url(/static/img/theme/subtle_stripes.png);
1213 | background-size: 40px 40px;
1214 | }
1215 |
1216 | /* THEME COLORS */
1217 | /* ------------ */
1218 | /* Green color */
1219 | .theme-color-green {
1220 | /* Docks Afix navigation */
1221 | /* tolltips */
1222 | }
1223 | .theme-color-green a {
1224 | color: #779922;
1225 | }
1226 | .theme-color-green a:hover {
1227 | color: #97c32b;
1228 | }
1229 | .theme-color-green #masthead .brand:hover i {
1230 | color: #779922;
1231 | }
1232 | .theme-color-green .navbar .nav li.dropdown.active > .dropdown-toggle:hover,
1233 | .theme-color-green .navbar .nav li.dropdown.open > .dropdown-toggle, .theme-color-green .navbar .nav li.dropdown.active > .dropdown-toggle, .theme-color-green .navbar .nav li.dropdown.open.active > .dropdown-toggle,
1234 | .theme-color-green .navbar .nav > .active > a, .theme-color-green .navbar .nav > .active > a:hover, .theme-color-green .navbar .nav > .active > a:focus,
1235 | .theme-color-green .navbar .nav > li > a:focus, .theme-color-green .navbar .nav > li > a:hover {
1236 | color: #779922;
1237 | }
1238 | .theme-color-green .dropdown-menu a {
1239 | color: #333333;
1240 | }
1241 | .theme-color-green .dropdown-menu li > a:hover, .theme-color-green .dropdown-menu li > a:focus, .theme-color-green .dropdown-submenu:hover > a {
1242 | background-color: #709020;
1243 | background-image: -moz-linear-gradient(top, #779922, #67841d);
1244 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#779922), to(#67841d));
1245 | background-image: -webkit-linear-gradient(top, #779922, #67841d);
1246 | background-image: -o-linear-gradient(top, #779922, #67841d);
1247 | background-image: linear-gradient(to bottom, #779922, #67841d);
1248 | background-repeat: repeat-x;
1249 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF779922', endColorstr='#FF67841D', GradientType=0);
1250 | }
1251 | .theme-color-green .page-header a {
1252 | color: #999999;
1253 | }
1254 | .theme-color-green .page-header a:hover {
1255 | color: #555555;
1256 | }
1257 | .theme-color-green .pricing-table-price {
1258 | color: #779922;
1259 | }
1260 | .theme-color-green .pricing-table-featured {
1261 | background: #779922;
1262 | border-color: #465a14;
1263 | text-shadow: 0px 1px 0px #576f19;
1264 | }
1265 | .theme-color-green .pricing-table-featured .pricing-table-price {
1266 | color: #779922;
1267 | }
1268 | .theme-color-green .pricing-table-featured .pricing-table-list {
1269 | border-color: #576f19;
1270 | -webkit-box-shadow: 0px 1px 0px #97c32b;
1271 | -moz-box-shadow: 0px 1px 0px #97c32b;
1272 | box-shadow: 0px 1px 0px #97c32b;
1273 | }
1274 | .theme-color-green .pricing-table-featured li {
1275 | border-color: #97c32b;
1276 | -webkit-box-shadow: 0px -1px 0px #576f19;
1277 | -moz-box-shadow: 0px -1px 0px #576f19;
1278 | box-shadow: 0px -1px 0px #576f19;
1279 | }
1280 | .theme-color-green .pricing-table-featured li:first-child {
1281 | border-color: transparent;
1282 | -webkit-box-shadow: none;
1283 | -moz-box-shadow: none;
1284 | box-shadow: none;
1285 | }
1286 | .theme-color-green .btn-primary {
1287 | color: white;
1288 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
1289 | background-color: #83a925;
1290 | background-image: -moz-linear-gradient(top, #779922, #97c32b);
1291 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#779922), to(#97c32b));
1292 | background-image: -webkit-linear-gradient(top, #779922, #97c32b);
1293 | background-image: -o-linear-gradient(top, #779922, #97c32b);
1294 | background-image: linear-gradient(to bottom, #779922, #97c32b);
1295 | background-repeat: repeat-x;
1296 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF779922', endColorstr='#FF97C32B', GradientType=0);
1297 | border-color: #97c32b #97c32b #67841d;
1298 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
1299 | *background-color: #97c32b;
1300 | /* Darken IE7 buttons by default so they stand out more given they won't have borders */
1301 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
1302 | }
1303 | .theme-color-green .btn-primary:hover, .theme-color-green .btn-primary:active, .theme-color-green .btn-primary.active, .theme-color-green .btn-primary.disabled, .theme-color-green .btn-primary[disabled] {
1304 | color: white;
1305 | background-color: #97c32b;
1306 | *background-color: #87ae27;
1307 | }
1308 | .theme-color-green .btn-primary:active, .theme-color-green .btn-primary.active {
1309 | background-color: #779922 \9;
1310 | }
1311 | .theme-color-green .docs-sidebar-nav li.active a, .theme-color-green .docs-sidebar-nav li.active a:hover, .theme-color-green .docs-sidebar-nav li a:hover {
1312 | color: #779922;
1313 | border-right: 3px solid #779922;
1314 | }
1315 | .theme-color-green .tooltip-inner {
1316 | background-color: #779922;
1317 | }
1318 | .theme-color-green .tooltip.top .tooltip-arrow {
1319 | border-top-color: #779922;
1320 | }
1321 | .theme-color-green .tooltip.right .tooltip-arrow {
1322 | border-right-color: #779922;
1323 | }
1324 | .theme-color-green .tooltip.left .tooltip-arrow {
1325 | border-left-color: #779922;
1326 | }
1327 | .theme-color-green .tooltip.bottom .tooltip-arrow {
1328 | border-bottom-color: #779922;
1329 | }
1330 |
1331 | /* Red color */
1332 | .theme-color-red {
1333 | /* Docks Afix navigation */
1334 | /* tolltips */
1335 | }
1336 | .theme-color-red a {
1337 | color: #e8481d;
1338 | }
1339 | .theme-color-red a:hover {
1340 | color: #ed6d4b;
1341 | }
1342 | .theme-color-red #masthead .brand:hover i {
1343 | color: #e8481d;
1344 | }
1345 | .theme-color-red .navbar .nav li.dropdown.active > .dropdown-toggle:hover,
1346 | .theme-color-red .navbar .nav li.dropdown.open > .dropdown-toggle, .theme-color-red .navbar .nav li.dropdown.active > .dropdown-toggle, .theme-color-red .navbar .nav li.dropdown.open.active > .dropdown-toggle,
1347 | .theme-color-red .navbar .nav > .active > a, .theme-color-red .navbar .nav > .active > a:hover, .theme-color-red .navbar .nav > .active > a:focus,
1348 | .theme-color-red .navbar .nav > li > a:focus, .theme-color-red .navbar .nav > li > a:hover {
1349 | color: #e8481d;
1350 | }
1351 | .theme-color-red .dropdown-menu a {
1352 | color: #333333;
1353 | }
1354 | .theme-color-red .dropdown-menu li > a:hover, .theme-color-red .dropdown-menu li > a:focus, .theme-color-red .dropdown-submenu:hover > a {
1355 | background-color: #e0441a;
1356 | background-image: -moz-linear-gradient(top, #e8481d, #d63e16);
1357 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#e8481d), to(#d63e16));
1358 | background-image: -webkit-linear-gradient(top, #e8481d, #d63e16);
1359 | background-image: -o-linear-gradient(top, #e8481d, #d63e16);
1360 | background-image: linear-gradient(to bottom, #e8481d, #d63e16);
1361 | background-repeat: repeat-x;
1362 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFE8481D', endColorstr='#FFD63E16', GradientType=0);
1363 | }
1364 | .theme-color-red .page-header a {
1365 | color: #999999;
1366 | }
1367 | .theme-color-red .page-header a:hover {
1368 | color: #555555;
1369 | }
1370 | .theme-color-red .pricing-table-price {
1371 | color: #e8481d;
1372 | }
1373 | .theme-color-red .pricing-table-featured {
1374 | background: #e8481d;
1375 | border-color: #a73111;
1376 | text-shadow: 0px 1px 0px #bf3813;
1377 | }
1378 | .theme-color-red .pricing-table-featured .pricing-table-price {
1379 | color: #e8481d;
1380 | }
1381 | .theme-color-red .pricing-table-featured .pricing-table-list {
1382 | border-color: #bf3813;
1383 | -webkit-box-shadow: 0px 1px 0px #ed6d4b;
1384 | -moz-box-shadow: 0px 1px 0px #ed6d4b;
1385 | box-shadow: 0px 1px 0px #ed6d4b;
1386 | }
1387 | .theme-color-red .pricing-table-featured li {
1388 | border-color: #ed6d4b;
1389 | -webkit-box-shadow: 0px -1px 0px #bf3813;
1390 | -moz-box-shadow: 0px -1px 0px #bf3813;
1391 | box-shadow: 0px -1px 0px #bf3813;
1392 | }
1393 | .theme-color-red .pricing-table-featured li:first-child {
1394 | border-color: transparent;
1395 | -webkit-box-shadow: none;
1396 | -moz-box-shadow: none;
1397 | box-shadow: none;
1398 | }
1399 | .theme-color-red .btn-primary {
1400 | color: white;
1401 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
1402 | background-color: #ea562f;
1403 | background-image: -moz-linear-gradient(top, #e8481d, #ed6d4b);
1404 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#e8481d), to(#ed6d4b));
1405 | background-image: -webkit-linear-gradient(top, #e8481d, #ed6d4b);
1406 | background-image: -o-linear-gradient(top, #e8481d, #ed6d4b);
1407 | background-image: linear-gradient(to bottom, #e8481d, #ed6d4b);
1408 | background-repeat: repeat-x;
1409 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFE8481D', endColorstr='#FFED6D4B', GradientType=0);
1410 | border-color: #ed6d4b #ed6d4b #d63e16;
1411 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
1412 | *background-color: #ed6d4b;
1413 | /* Darken IE7 buttons by default so they stand out more given they won't have borders */
1414 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
1415 | }
1416 | .theme-color-red .btn-primary:hover, .theme-color-red .btn-primary:active, .theme-color-red .btn-primary.active, .theme-color-red .btn-primary.disabled, .theme-color-red .btn-primary[disabled] {
1417 | color: white;
1418 | background-color: #ed6d4b;
1419 | *background-color: #ea5b34;
1420 | }
1421 | .theme-color-red .btn-primary:active, .theme-color-red .btn-primary.active {
1422 | background-color: #e8481d \9;
1423 | }
1424 | .theme-color-red .docs-sidebar-nav li.active a, .theme-color-red .docs-sidebar-nav li.active a:hover, .theme-color-red .docs-sidebar-nav li a:hover {
1425 | color: #e8481d;
1426 | border-right: 3px solid #e8481d;
1427 | }
1428 | .theme-color-red .tooltip-inner {
1429 | background-color: #e8481d;
1430 | }
1431 | .theme-color-red .tooltip.top .tooltip-arrow {
1432 | border-top-color: #e8481d;
1433 | }
1434 | .theme-color-red .tooltip.right .tooltip-arrow {
1435 | border-right-color: #e8481d;
1436 | }
1437 | .theme-color-red .tooltip.left .tooltip-arrow {
1438 | border-left-color: #e8481d;
1439 | }
1440 | .theme-color-red .tooltip.bottom .tooltip-arrow {
1441 | border-bottom-color: #e8481d;
1442 | }
1443 |
1444 | /* MEDIA QUERIES */
1445 | /* ------------- */
1446 | /* Big screens */
1447 | @media (min-width: 1200px) {
1448 | /* Docks Afix navigation */
1449 | .docs-sidebar-nav {
1450 | width: 250px;
1451 | }
1452 | }
1453 | /* Up to default desktop */
1454 | @media (max-width: 979px) {
1455 | body {
1456 | padding-top: 0;
1457 | }
1458 |
1459 | .section {
1460 | padding: 30px 20px;
1461 | }
1462 |
1463 | #map {
1464 | height: 200px;
1465 | margin-left: -20px;
1466 | margin-right: -20px;
1467 | }
1468 |
1469 | .navbar-fixed-top {
1470 | margin-bottom: 0;
1471 | }
1472 |
1473 | .navbar-fixed-top .navbar-inner, .navbar-fixed-bottom .navbar-inner {
1474 | position: relative;
1475 | }
1476 |
1477 | .navbar .nav .active > a, .navbar .nav a:hover, .nav-collapse .nav > li > a:hover, .nav-collapse .dropdown-menu a:hover {
1478 | background: #f6f6f6;
1479 | -webkit-box-shadow: #e9e9e9 0px 0px 5px inset;
1480 | -moz-box-shadow: #e9e9e9 0px 0px 5px inset;
1481 | box-shadow: #e9e9e9 0px 0px 5px inset;
1482 | color: #41b7d8;
1483 | }
1484 |
1485 | .theme-color-red .navbar .nav .active > a, .theme-color-red .navbar .nav a:hover, .theme-color-red .nav-collapse .nav > li > a:hover, .theme-color-red .nav-collapse .dropdown-menu a:hover {
1486 | color: #e8481d;
1487 | background: #f6f6f6;
1488 | -webkit-box-shadow: #e9e9e9 0px 0px 5px inset;
1489 | -moz-box-shadow: #e9e9e9 0px 0px 5px inset;
1490 | box-shadow: #e9e9e9 0px 0px 5px inset;
1491 | }
1492 |
1493 | .nav-collapse .nav > li > a, .nav-collapse .dropdown-menu a {
1494 | padding: 6px 15px;
1495 | }
1496 |
1497 | .navbar .nav > li > .dropdown-menu::before {
1498 | display: none;
1499 | }
1500 |
1501 | .navbar .dropdown-menu {
1502 | -webkit-box-shadow: 0px 0px 20px rgba(233, 233, 233, 0.9) inset;
1503 | -moz-box-shadow: 0px 0px 20px rgba(233, 233, 233, 0.9) inset;
1504 | box-shadow: 0px 0px 20px rgba(233, 233, 233, 0.9) inset;
1505 | -webkit-border-radius: 3px;
1506 | -moz-border-radius: 3px;
1507 | -ms-border-radius: 3px;
1508 | -o-border-radius: 3px;
1509 | border-radius: 3px;
1510 | }
1511 |
1512 | .thumbnail-filters {
1513 | text-align: center;
1514 | }
1515 |
1516 | .carousel-control, .carousel-control.right {
1517 | text-align: center;
1518 | left: -20px;
1519 | }
1520 | .carousel-control.right, .carousel-control.right.right {
1521 | right: -20px;
1522 | left: auto;
1523 | }
1524 |
1525 | /* fancy blockquote */
1526 | .blockquote-fancy p {
1527 | padding: 10px 30px;
1528 | }
1529 | .blockquote-fancy .blockquote-img {
1530 | margin: 20px auto;
1531 | position: relative;
1532 | top: 0px;
1533 | text-align: center;
1534 | }
1535 | .blockquote-fancy.blockquote-fancy-small p {
1536 | padding: 30px;
1537 | }
1538 |
1539 | .blog-more, .blog-tags {
1540 | text-align: left;
1541 | }
1542 |
1543 | /* handle large inputs for contact forms */
1544 | .input-xlarge {
1545 | width: 90%;
1546 | }
1547 |
1548 | .docs-sidebar-nav {
1549 | width: 150px;
1550 | }
1551 | }
1552 | /* portrait tablet to default desctop */
1553 | @media (min-width: 768px) and (max-width: 979px) {
1554 | .thumbnail-title {
1555 | display: none;
1556 | }
1557 | }
1558 | /* landscape phone to small desktop & porttrait tablet */
1559 | @media (max-width: 767px) {
1560 | .section {
1561 | margin: 0 -20px;
1562 | }
1563 |
1564 | .thumbnails > li {
1565 | margin-left: 0;
1566 | }
1567 |
1568 | .brand:hover i {
1569 | color: #779922;
1570 | }
1571 |
1572 | .sidebar {
1573 | margin-top: 20px;
1574 | border-top: 1px solid #e9e9e9;
1575 | }
1576 |
1577 | .modal.modal-login {
1578 | max-width: 560px;
1579 | }
1580 |
1581 | .docs-sidebar-nav {
1582 | position: relative;
1583 | width: 100%;
1584 | margin-bottom: 24px;
1585 | }
1586 | .docs-sidebar-nav li a {
1587 | text-align: left;
1588 | border-bottom: 1px solid #e9e9e9;
1589 | border-right: 0;
1590 | }
1591 | .docs-sidebar-nav li.active a, .docs-sidebar-nav li.active a:hover, .docs-sidebar-nav li a:hover {
1592 | border-bottom: 1px solid #41b7d8;
1593 | border-right: 0;
1594 | }
1595 |
1596 | .docs-header {
1597 | padding-top: 0;
1598 | }
1599 | }
1600 | /* up to landscape phone */
1601 | @media (max-width: 480px) {
1602 | .hero-unit h1 {
1603 | font-size: 48px;
1604 | }
1605 |
1606 | .thumbnails > li {
1607 | margin-left: 0;
1608 | }
1609 |
1610 | .thumbnail-title {
1611 | display: none;
1612 | }
1613 |
1614 | .thumbnail-filters {
1615 | display: block;
1616 | }
1617 |
1618 | .media-comment .pull-left {
1619 | text-align: center;
1620 | }
1621 |
1622 | .media-comment .media-heading a {
1623 | float: right;
1624 | }
1625 | }
1626 | /* retina displays backgrounds */
1627 | @media only screen and (-Webkit-min-device-pixel-ratio: 1.5), only screen and (-moz-min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3 / 2), only screen and (min-device-pixel-ratio: 1.5) {
1628 | .theme-pattern-lightmesh .section.alt, .theme-pattern-lightmesh.alt {
1629 | background-image: url(/static/img/theme/lghtmesh_@2X.png);
1630 | }
1631 |
1632 | .theme-pattern-bedge-grunge .section.alt, .theme-pattern-bedge-grunge.alt {
1633 | background-image: url(/static/img/theme/bedge_grunge_@2X.png);
1634 | }
1635 |
1636 | .theme-pattern-grid .section.alt, .theme-pattern-grid.alt {
1637 | background-image: url(/static/img/theme/grid_@2X.png);
1638 | }
1639 |
1640 | .theme-pattern-noisy-grid .section.alt, .theme-pattern-noisy-grid.alt {
1641 | background-image: url(/static/img/theme/noisy_grid_@2X.png);
1642 | }
1643 |
1644 | .theme-pattern-subtle-grey .section.alt, .theme-pattern-subtle-grey.alt {
1645 | background-image: url(/static/img/theme/grey_@2X.png);
1646 | }
1647 |
1648 | .theme-pattern-retina-wood .section.alt, .theme-pattern-retina-wood.alt {
1649 | background-image: url(/static/img/theme/retina_wood_@2X.png);
1650 | }
1651 |
1652 | .theme-pattern-noise-lines .section.alt, .theme-pattern-noise-lines.alt {
1653 | background-image: url(/static/img/theme/noise_lines_@2X.png);
1654 | }
1655 |
1656 | .theme-pattern-tiny-grid .section.alt, .theme-pattern-tiny-grid.alt {
1657 | background-image: url(/static/img/theme/tiny_grid_@2X.png);
1658 | }
1659 |
1660 | .theme-pattern-clean-paper .section.alt, .theme-pattern-clean-paper.alt {
1661 | background-image: url(/static/img/theme/extra_clean_paper_@2X.png);
1662 | }
1663 |
1664 | .theme-pattern-farmer .section.alt, .theme-pattern-farmer.alt {
1665 | background-image: url(/static/img/theme/farmer_@2X.png);
1666 | }
1667 |
1668 | .theme-pattern-project-papper .section.alt, .theme-pattern-project-papper.alt {
1669 | background-image: url(/static/img/theme/project_papper_@2X.png);
1670 | }
1671 |
1672 | .theme-pattern-concrete-wall .section.alt, .theme-pattern-concrete-wall.alt {
1673 | background-image: url(/static/img/theme/concrete_wall_2_@2X.png);
1674 | }
1675 |
1676 | .theme-pattern-wavecut .section.alt, .theme-pattern-wavecut.alt {
1677 | background-image: url(/static/img/theme/wavecut_@2X.png);
1678 | }
1679 |
1680 | .theme-pattern-little-pluses .section.alt, .theme-pattern-little-pluses.alt {
1681 | background-image: url(/static/img/theme/little_pluses_@2X.png);
1682 | }
1683 |
1684 | .theme-pattern-light-honeycomp .section.alt, .theme-pattern-light-honeycomp.alt {
1685 | background-image: url(/static/img/theme/light_honeycomb_@2X.png);
1686 | }
1687 |
1688 | .theme-pattern-old-mathematics .section.alt, .theme-pattern-old-mathematics.alt {
1689 | background-image: url(/static/img/theme/old_mathematics_@2X.png);
1690 | }
1691 |
1692 | .theme-pattern-45-degree-fabric .section.alt, .theme-pattern-45-degree-fabric.alt {
1693 | background-image: url(/static/img/theme/45degreee_fabric_@2X.png);
1694 | }
1695 |
1696 | .theme-pattern-strange-bullseyes .section.alt, .theme-pattern-strange-bullseyes.alt {
1697 | background-image: url(/static/img/theme/strange_bullseyes_@2X.png);
1698 | }
1699 |
1700 | .theme-pattern-diamond-upholstery .section.alt, .theme-pattern-diamond-upholstery.alt {
1701 | background-image: url(/static/img/theme/diamond_upholstery_@2X.png);
1702 | }
1703 |
1704 | .theme-pattern-subtle-stripes .section.alt, .theme-pattern-subtle-stripes.alt {
1705 | background-image: url(/static/img/theme/subtle_stripes_@2X.png);
1706 | }
1707 | }
1708 |
--------------------------------------------------------------------------------