<commit_before>'use strict';

/*!
 * Snakeskin
 * https://github.com/SnakeskinTpl/Snakeskin
 *
 * Released under the MIT license
 * https://github.com/SnakeskinTpl/Snakeskin/blob/master/LICENSE
 */

import Snakeskin from '../core';

// The base directive separators
// >>>

export const
	LEFT_BOUND = '{',
	RIGHT_BOUND = '}',
	ADV_LEFT_BOUND = '#';

// <<<
// The additional directive separators
// >>>

export const
	I18N = '`';

export const
	JS_DOC = '/**',
	SINGLE_COMMENT = '///',
	MULT_COMMENT_START = '/*',
	MULT_COMMENT_END = '*/';

export const COMMENTS = {
	[SINGLE_COMMENT]: SINGLE_COMMENT,
	[MULT_COMMENT_START]: MULT_COMMENT_START,
	[MULT_COMMENT_END]: MULT_COMMENT_END
};

export const
	MICRO_TEMPLATE = '${';

export const BASE_SHORTS = {
	'-': true,
	[ADV_LEFT_BOUND]: true
};

export const
	SHORTS = {};

Snakeskin.forEach(BASE_SHORTS, (el, key) =>
	SHORTS[key] = true);

// <<<
// The context modifiers
// >>>

export const
	G_MOD = '@';

// <<<
// Jade-Like
// >>>

export const
	CONCAT = '&',
	CONCAT_END = '.',
	IGNORE = '|',
	INLINE = ' :: ';

// <<<
// The filter modifiers
// >>>

export const
	FILTER = '|';

// <<<
// Escaping
// >>>

export const BASE_SYS_ESCAPES = {
	'\\': true,
	[I18N]: true,
	[LEFT_BOUND]: true,
	[SINGLE_COMMENT.charAt(0)]: true,
	[MULT_COMMENT_START.charAt(0)]: true
};

export const SYS_ESCAPES = {
	'\\': true,
	[I18N]: true,
	[LEFT_BOUND]: true,
	[ADV_LEFT_BOUND]: true,
	[SINGLE_COMMENT.charAt(0)]: true,
	[MULT_COMMENT_START.charAt(0)]: true,
	[CONCAT]: true,
	[CONCAT_END]: true,
	[IGNORE]: true,
	[INLINE.trim().charAt(0)]: true
};

Snakeskin.forEach(BASE_SHORTS, (el, key) =>
	SYS_ESCAPES[key.charAt(0)] = true);

export const STRONG_SYS_ESCAPES = {
	'\\': true,
	[I18N]: true,
	[SINGLE_COMMENT.charAt(0)]: true,
	[MULT_COMMENT_START.charAt(0)]: true
};

export const MICRO_TEMPLATE_ESCAPES = {
	'\\': true,
	[MICRO_TEMPLATE.charAt(0)]: true
};

export const ESCAPES = {
	'"': true,
	'\'': true,
	'/': true
};

export const ESCAPES_END = {
	'-': true,
	'+': true,
	'*': true,
	'%': true,
	'~': true,
	'>': true,
	'<': true,
	'^': true,
	',': true,
	';': true,
	'=': true,
	'|': true,
	'&': true,
	'!': true,
	'?': true,
	':': true,
	'(': true,
	'{': true,
	'[': true
};

export const ESCAPES_END_WORD = {
	'return': true,
	'yield': true,
	'await': true,
	'typeof': true,
	'void': true,
	'instanceof': true,
	'delete': true,
	'in': true,
	'new': true
};

export const B_OPEN = {
	'(': true,
	'[': true,
	'{': true
};

export const B_CLOSE = {
	')': true,
	']': true,
	'}': true
};

export const P_OPEN = {
	'(': true,
	'[': true
};

export const P_CLOSE = {
	')': true,
	']': true
};

// <<<
// The reserved names
// >>>

export const SYS_CONSTS = {
	'__REQUIRE__': true,
	'__RESULT__': true,
	'__STRING_RESULT__': true,
	'__CDATA__': true,
	'__RETURN__': true,
	'__RETURN_VAL__': true,
	'__LENGTH__': true,
	'__ESCAPE_D_Q__': true,
	'__ATTR_STR__': true,
	'__ATTR_CONCAT_MAP__': true,
	'__TARGET_REF__': true,
	'__CALL_POS__': true,
	'__CALL_TMP__': true,
	'__CALL_CACHE__': true,
	'__FILTERS__': true,
	'__VARS__': true,
	'__LOCAL__': true,
	'__THIS__': true,
	'__INCLUDE__': true,
	'__INLINE_TAG__': true,
	'__INLINE_TAGS__': true,
	'__NODE__': true,
	'__JOIN__': true,
	'__GET_XML_ATTR_KEY_DECL__': true,
	'__APPEND_XML_ATTR_VAL__': true,
	'__GET_XML_ATTRS_DECL_START__': true,
	'__GET_XML_TAG_DECL_END__': true,
	'__GET_END_XML_TAG_DECL__': true,
	'__TARGET_END__': true,
	'__PUTIN_CALL__': true,
	'__PUTIN_TARGET__': true,
	'__SNAKESKIN_MODULES__': true,
	'__SNAKESKIN_MODULES_DECL__': true,
	'GLOBAL': true,
	'TRUE': true,
	'FALSE': true,
	'module': true,
	'exports': true,
	'require': true,
	'__dirname': true,
	'__filename': true,
	'TPL_NAME': true,
	'PARENT_TPL_NAME': true,
	'EOL': true,
	'Raw': true,
	'Unsafe': true,
	'Snakeskin': true,
	'getTplResult': true,
	'clearTplResult': true,
	'arguments': true,
	'self': true,
	'callee': true,
	'$_': true,
	'$0': true,
	'$class': true,
	'$tagName': true,
	'$attrKey': true,
	'$attrType': true,
	'$attrs': true
};
<commit_msg>:wrench:<commit_after>'use strict';

/*!
 * Snakeskin
 * https://github.com/SnakeskinTpl/Snakeskin
 *
 * Released under the MIT license
 * https://github.com/SnakeskinTpl/Snakeskin/blob/master/LICENSE
 */

import Snakeskin from '../core';

// The base directive separators
// >>>

export const
	LEFT_BOUND = '{',
	RIGHT_BOUND = '}',
	ADV_LEFT_BOUND = '#';

// <<<
// The additional directive separators
// >>>

export const
	I18N = '`';

export const
	JS_DOC = '/**',
	SINGLE_COMMENT = '///',
	MULT_COMMENT_START = '/*',
	MULT_COMMENT_END = '*/';

export const COMMENTS = {
	[SINGLE_COMMENT]: SINGLE_COMMENT,
	[MULT_COMMENT_START]: MULT_COMMENT_START,
	[MULT_COMMENT_END]: MULT_COMMENT_END
};

export const
	MICRO_TEMPLATE = '${';

export const BASE_SHORTS = {
	'-': true,
	[ADV_LEFT_BOUND]: true
};

export const
	SHORTS = {};

Snakeskin.forEach(BASE_SHORTS, (el, key) =>
	SHORTS[key] = true);

// <<<
// The context modifiers
// >>>

export const
	G_MOD = '@';

// <<<
// Jade-Like
// >>>

export const
	CONCAT = '&',
	CONCAT_END = '.',
	IGNORE = '|',
	INLINE = ' :: ';

// <<<
// The filter modifiers
// >>>

export const
	FILTER = '|';

// <<<
// Escaping
// >>>

export const BASE_SYS_ESCAPES = {
	'\\': true,
	'"': true,
	'\'': true,
	'/': true,
	[I18N]: true,
	[LEFT_BOUND]: true,
	[SINGLE_COMMENT.charAt(0)]: true,
	[MULT_COMMENT_START.charAt(0)]: true
};

export const SYS_ESCAPES = {
	'\\': true,
	[I18N]: true,
	[LEFT_BOUND]: true,
	[ADV_LEFT_BOUND]: true,
	[SINGLE_COMMENT.charAt(0)]: true,
	[MULT_COMMENT_START.charAt(0)]: true,
	[CONCAT]: true,
	[CONCAT_END]: true,
	[IGNORE]: true,
	[INLINE.trim().charAt(0)]: true
};

Snakeskin.forEach(BASE_SHORTS, (el, key) =>
	SYS_ESCAPES[key.charAt(0)] = true);

export const STRONG_SYS_ESCAPES = {
	'\\': true,
	[I18N]: true,
	[SINGLE_COMMENT.charAt(0)]: true,
	[MULT_COMMENT_START.charAt(0)]: true
};

export const MICRO_TEMPLATE_ESCAPES = {
	'\\': true,
	[MICRO_TEMPLATE.charAt(0)]: true
};

export const ESCAPES = {
	'"': true,
	'\'': true,
	'/': true
};

export const ESCAPES_END = {
	'-': true,
	'+': true,
	'*': true,
	'%': true,
	'~': true,
	'>': true,
	'<': true,
	'^': true,
	',': true,
	';': true,
	'=': true,
	'|': true,
	'&': true,
	'!': true,
	'?': true,
	':': true,
	'(': true,
	'{': true,
	'[': true
};

export const ESCAPES_END_WORD = {
	'return': true,
	'yield': true,
	'await': true,
	'typeof': true,
	'void': true,
	'instanceof': true,
	'delete': true,
	'in': true,
	'new': true
};

export const B_OPEN = {
	'(': true,
	'[': true,
	'{': true
};

export const B_CLOSE = {
	')': true,
	']': true,
	'}': true
};

export const P_OPEN = {
	'(': true,
	'[': true
};

export const P_CLOSE = {
	')': true,
	']': true
};

// <<<
// The reserved names
// >>>

export const SYS_CONSTS = {
	'__REQUIRE__': true,
	'__RESULT__': true,
	'__STRING_RESULT__': true,
	'__CDATA__': true,
	'__RETURN__': true,
	'__RETURN_VAL__': true,
	'__LENGTH__': true,
	'__ESCAPE_D_Q__': true,
	'__ATTR_STR__': true,
	'__ATTR_CONCAT_MAP__': true,
	'__TARGET_REF__': true,
	'__CALL_POS__': true,
	'__CALL_TMP__': true,
	'__CALL_CACHE__': true,
	'__FILTERS__': true,
	'__VARS__': true,
	'__LOCAL__': true,
	'__THIS__': true,
	'__INCLUDE__': true,
	'__INLINE_TAG__': true,
	'__INLINE_TAGS__': true,
	'__NODE__': true,
	'__JOIN__': true,
	'__GET_XML_ATTR_KEY_DECL__': true,
	'__APPEND_XML_ATTR_VAL__': true,
	'__GET_XML_ATTRS_DECL_START__': true,
	'__GET_XML_TAG_DECL_END__': true,
	'__GET_END_XML_TAG_DECL__': true,
	'__TARGET_END__': true,
	'__PUTIN_CALL__': true,
	'__PUTIN_TARGET__': true,
	'__SNAKESKIN_MODULES__': true,
	'__SNAKESKIN_MODULES_DECL__': true,
	'GLOBAL': true,
	'TRUE': true,
	'FALSE': true,
	'module': true,
	'exports': true,
	'require': true,
	'__dirname': true,
	'__filename': true,
	'TPL_NAME': true,
	'PARENT_TPL_NAME': true,
	'EOL': true,
	'Raw': true,
	'Unsafe': true,
	'Snakeskin': true,
	'getTplResult': true,
	'clearTplResult': true,
	'arguments': true,
	'self': true,
	'callee': true,
	'$_': true,
	'$0': true,
	'$class': true,
	'$tagName': true,
	'$attrKey': true,
	'$attrType': true,
	'$attrs': true
};
<|endoftext|>


<commit_before>var deckNotes;
var deckFields;
var deckName;
var ankiSeparator = '\x1f';

// Huge props to http://stackoverflow.com/a/9507713/500207
function tabulate(data, columns, containerString) {
    var table = d3.select(containerString).append("table"),
        thead = table.append("thead"),
        tbody = table.append("tbody");

    // append the header row
    thead.append("tr")
        .selectAll("th")
        .data(columns)
        .enter()
        .append("th")
            .text(function(column) { return column; });

    // create a row for each object in the data
    var rows = tbody.selectAll("tr")
        .data(data)
        .enter()
        .append("tr");

    // create a cell in each row for each column
    var cells = rows.selectAll("td")
        .data(function(row) {
            return columns.map(function(column) {
                return {column: column, value: row[column]};
            });
        })
        .enter()
        .append("td")
            .html(function(d) { return d.value; });

    return table;
}

function sqlToTable(uInt8ArraySQLdb) {
    var db = new SQL.Database(uInt8ArraySQLdb);

    col = db.exec("SELECT * FROM col");
    var modelsFunction = Function('return ' + col[0].values[0][9]);
    var models = modelsFunction();

    var fnames = [];
    for (key in models) {
        if (models.hasOwnProperty(key)) {
            // This should happen only once.
            deckName = models[key].name;
            models[key].flds.forEach(function (val, idx, arr) {
                fnames.push(val.name);
            });
        }
    }
    deckFields = fnames;

    // Notes table
    deckNotes = db.exec("SELECT * FROM notes");

    // Visualize!
    d3.select("body").append("div").attr("id", "anki").append("h1").text(deckName);
    //d3.select("#anki").append("div").text(deckFields);

    // Actual notes
    var notes = [];
    var arrayToObj = function(facts) {
        var myObj = {};
        for (var i = 0; i < facts.length; i++) {
            myObj[deckFields[i]] = facts[i];
        }
        return myObj;
    }
    deckNotes[0].values.forEach(function (val) {
        notes.push(arrayToObj(val[6].split(ankiSeparator)));
    });
    deckNotes = notes;
    tabulate(deckNotes, deckFields, "#anki");
}

function ankiBinaryToTable(ankiArray) {
    var compressed = new Uint8Array(ankiArray);
    var unzip = new Zlib.Unzip(compressed);
    var filenames = unzip.getFilenames();
    if (filenames.indexOf("collection.anki2") >= 0) {
        var plain = unzip.decompress("collection.anki2");
        sqlToTable(plain);
    }
}
function ankiURLToTable(ankiURL) {
    var zipxhr = new XMLHttpRequest();
    zipxhr.open('GET', ankiURL, true);
    zipxhr.responseType = 'arraybuffer';
    zipxhr.onload = function(e) {ankiBinaryToTable(this.response);}
    zipxhr.send();
}<commit_msg>Select only columns that are needed<commit_after>var deckNotes;
var deckFields;
var deckName;
var ankiSeparator = '\x1f';

// Huge props to http://stackoverflow.com/a/9507713/500207
function tabulate(data, columns, containerString) {
    var table = d3.select(containerString).append("table"),
        thead = table.append("thead"),
        tbody = table.append("tbody");

    // append the header row
    thead.append("tr")
        .selectAll("th")
        .data(columns)
        .enter()
        .append("th")
            .text(function(column) { return column; });

    // create a row for each object in the data
    var rows = tbody.selectAll("tr")
        .data(data)
        .enter()
        .append("tr");

    // create a cell in each row for each column
    var cells = rows.selectAll("td")
        .data(function(row) {
            return columns.map(function(column) {
                return {column: column, value: row[column]};
            });
        })
        .enter()
        .append("td")
            .html(function(d) { return d.value; });

    return table;
}

function sqlToTable(uInt8ArraySQLdb) {
    var db = new SQL.Database(uInt8ArraySQLdb);

    col = db.exec("SELECT models FROM col");
    var modelsFunction = Function('return ' + col[0].values[0][0]);
    var models = modelsFunction();

    var fnames = [];
    for (key in models) {
        if (models.hasOwnProperty(key)) {
            // This should happen only once.
            deckName = models[key].name;
            models[key].flds.forEach(function (val, idx, arr) {
                fnames.push(val.name);
            });
        }
    }
    deckFields = fnames;

    // Visualize!
    d3.select("#anki").append("h1").text(deckName);

    // Notes table
    deckNotes = db.exec("SELECT flds FROM notes");

    // Actual notes
    var notes = [];
    var arrayToObj = function(facts) {
        var myObj = {};
        for (var i = 0; i < facts.length; i++) {
            myObj[deckFields[i]] = facts[i];
        }
        return myObj;
    }
    deckNotes[0].values.forEach(function (val) {
        notes.push(arrayToObj(val[0].split(ankiSeparator)));
    });
    deckNotes = notes;
    tabulate(deckNotes, deckFields, "#anki");
}

function ankiBinaryToTable(ankiArray) {
    var compressed = new Uint8Array(ankiArray);
    var unzip = new Zlib.Unzip(compressed);
    var filenames = unzip.getFilenames();
    if (filenames.indexOf("collection.anki2") >= 0) {
        var plain = unzip.decompress("collection.anki2");
        sqlToTable(plain);
    }
}
function ankiURLToTable(ankiURL) {
    var zipxhr = new XMLHttpRequest();
    zipxhr.open('GET', ankiURL, true);
    zipxhr.responseType = 'arraybuffer';
    zipxhr.onload = function(e) {ankiBinaryToTable(this.response);}
    zipxhr.send();
}<|endoftext|>


<commit_before>function show_edit(comment_id, csrf_token){
  var comment_classname = "comment-" + comment_id;
  var old_comment = $(".comment-" + comment_id).html();
  $("." + comment_classname).replaceWith(
      '
' + old_comment +
      '
<textarea class="form-control" maxlength="3000" id="new_comment_field_' + comment_id + '">' +
      '</textarea>
' + '<button class="btn btn-primary update-confirm" onclick="edit_comment(' + comment_id +
      ', ' + '\'' + csrf_token + '\'' + ')">' +
      'Update Comment' + '</button><button class="btn btn-default update-cancel" onclick="cancel_edit(' + comment_id +
    ')"> Cancel</button>

'
  );
  $(".edit-button").hide();
  $('form[name=comment-form]').hide();
}
function cancel_edit(comment_id){
  $(".edit_area").remove();
  $(".edit-button").show();
  $("form[name=comment-form]").show();
}
function new_comment_text(comment_id){
  return document.getElementById("new_comment_field_" + comment_id).value;
}
function edit_comment(comment_id, csrf_token){
  $.ajax({
    dataType: "json"
    url: "/commentajax/",
    type: "POST",
    data: JSON.stringify({"comment_id": comment_id,
                          "csrf_token": csrf_token,
                          "new_text": new_comment_text(comment_id)})
  })
  .done(function( response ) {
    var comment_class = "comment-content-" + comment_id;
    var newdiv = '
';
    $('.' + comment_class).replaceWith(newdiv + response['new_text'] + '
');
    $(".edit_area").remove();
    $('form[name=comment-form]').show();
    $(".edit-button").show();
  });
};
<commit_msg>style: Remove remaining single quotes from js<commit_after>function show_edit(comment_id, csrf_token){
  var comment_classname = "comment-" + comment_id;
  var old_comment = $(".comment-" + comment_id).html();
  $("." + comment_classname).replaceWith(
      "
" + old_comment +
      "
<textarea class=\"form-control\" maxlength=\"3000\" id=\"new_comment_field_" + comment_id + "\">" +
      "</textarea>
" + "<button class=\"btn btn-primary update-confirm\" onclick=\"edit_comment(" + comment_id +
      ", " + "\"" + csrf_token + "\"" + ")\">" +
      "Update Comment" + "</button><button class=\"btn btn-default update-cancel\" onclick=\"cancel_edit(" + comment_id +
      ")\"> Cancel</button>

"
  );
  $(".edit-button").hide();
  $("form[name=comment-form]").hide();
}
function cancel_edit(comment_id){
  $(".edit_area").remove();
  $(".edit-button").show();
  $("form[name=comment-form]").show();
}
function new_comment_text(comment_id){
  return document.getElementById("new_comment_field_" + comment_id).value;
}
function edit_comment(comment_id, csrf_token){
  $.ajax({
    dataType: "json",
    url: "/commentajax/",
    type: "POST",
    data: JSON.stringify({"comment_id": comment_id,
                          "csrf_token": csrf_token,
                          "new_text": new_comment_text(comment_id)})
  })
  .done(function( response ) {
    var comment_class = "comment-content-" + comment_id;
    var newdiv = "
";
    $("." + comment_class).replaceWith(newdiv + response.new_text + "
");
    $(".edit_area").remove();
    $("form[name=comment-form]").show();
    $(".edit-button").show();
  });
}
<|endoftext|>


<commit_before>import koa from 'koa';
import route from 'koa-router';
import koaLogger from 'koa-logger';
import logger from './utils/logger';
import json from 'koa-json';
import views from 'koa-views';
import onerror from 'koa-onerror';
import koaStatic from 'koa-static';
import koaBodyparser from 'koa-bodyparser';
import session from 'koa-generic-session';
import redisStore from 'koa-redis';
import render from './utils/render';
//导入全局设置
import S from './conf/setting'
//导入路由配置
import index from './routes/index';
import users from './routes/users';
import admin from './routes/admin';
import content from './routes/content';
import list from './routes/list';
import api from './routes/api';
//导入控制部分
import userInfo from './controller/getUserInfo';
//实例化
let app = koa();
let R = route();
//设置模板相关参数
app.use(views('views', {
  root: __dirname + '/views',
  default: 'jade'
}));
//设置body-parser先关参数
app.use(koaBodyparser({
  formLimit:'5mb',
  jsonLimit:'200kb'
}));
//链接数据库
app.use(json());
app.use(koaLogger());
//设置静态资源相关参数
app.use(koaStatic(__dirname + '/public'));
//设置seeion相关册数
app.use(session({
  key: 'kaola.sid',
  prefix: 'kaola:sess:',
  store: redisStore({
    host:S.REDIS_HOST,
    port:S.REDIS_PORT,
    socket:S.REDIS_SOCKET, //socket
    pass:S.REDIS_PASSWORD,   //redis连接密码
    db:S.REDIS_DB
  }),
  cookie:{
    maxAge: 24 * 60 * 60 * 3000 //3 day in ms
  }
}));
//设置应用名称
app.name = S.NAME;
//设置cookies相关key
app.keys = [S.COOKIE_NAME, S.ENCRYPT_KEY];
//404&500
app.use(function *(next){
  try {
    yield next;
  } catch (err) {
    let status = err.status || 500;
    // 根据 status 渲染不同的页面
    if (status == 404) {
      yield render('error',{
        debug: S.DEBUG,
        title: '页面未找到',
        referer: this.request.header.referer,
        error: {
          status : 404
        }
      },this);
    }
    if (status == 500) {
      if(this.request.method === 'GET'){
        yield render('error',{
          debug: S.DEBUG,
          title: '系统发生错误',
          referer:this.request.header.referer,
          error: {
            status : 500,
            data: err
          }
        },this);
      }else{
        this.body = {
          status : 'FAIL::系统发生错误',
          error : err
        }
      }
      // 触发 koa 统一错误事件，可以打印出详细的错误堆栈 log
      this.app.emit('error', err, this);
    }
  }
})
//过滤非法URL请求
app.use(function *(next){
  let allow = false;
  for(let item in S.ALLOW_DOMAIN){
    if(this.hostname === S.ALLOW_DOMAIN[item]){
      allow = true;
    }
  }
  if(allow){
    yield next;
  }
})
R.use(userInfo);
//路由设置
R.use('/', index.routes(), index.allowedMethods());
R.use('/api', api.routes(), api.allowedMethods());
R.use('/content', content.routes(), content.allowedMethods());
R.use('/list', list.routes(), list.allowedMethods());
R.use('/users', users.routes(), users.allowedMethods());
R.use('/'+S.ADMIN_DOMAIN, admin.routes(), admin.allowedMethods());

//绑定路由
app.use(R.routes());

//错误监听
app.on('error', function(err, ctx){
  logger('error',err);
});

export default app;
<commit_msg>调试搜索接口<commit_after>import koa from 'koa';
import route from 'koa-router';
import koaLogger from 'koa-logger';
import logger from './utils/logger';
import json from 'koa-json';
import views from 'koa-views';
import onerror from 'koa-onerror';
import koaStatic from 'koa-static';
import koaBodyparser from 'koa-bodyparser';
import session from 'koa-generic-session';
import redisStore from 'koa-redis';
import render from './utils/render';
//导入全局设置
import S from './conf/setting'
//导入路由配置
import index from './routes/index';
import users from './routes/users';
import admin from './routes/admin';
import content from './routes/content';
import list from './routes/list';
import search from './routes/search';
import api from './routes/api';
//导入控制部分
import userInfo from './controller/getUserInfo';
//实例化
let app = koa();
let R = route();
//设置模板相关参数
app.use(views('views', {
  root: __dirname + '/views',
  default: 'jade'
}));
//设置body-parser先关参数
app.use(koaBodyparser({
  formLimit:'5mb',
  jsonLimit:'200kb'
}));
//链接数据库
app.use(json());
app.use(koaLogger());
//设置静态资源相关参数
app.use(koaStatic(__dirname + '/public'));
//设置seeion相关册数
app.use(session({
  key: 'kaola.sid',
  prefix: 'kaola:sess:',
  store: redisStore({
    host:S.REDIS_HOST,
    port:S.REDIS_PORT,
    socket:S.REDIS_SOCKET, //socket
    pass:S.REDIS_PASSWORD,   //redis连接密码
    db:S.REDIS_DB
  }),
  cookie:{
    maxAge: 24 * 60 * 60 * 3000 //3 day in ms
  }
}));
//设置应用名称
app.name = S.NAME;
//设置cookies相关key
app.keys = [S.COOKIE_NAME, S.ENCRYPT_KEY];
//404&500
app.use(function *(next){
  try {
    yield next;
  } catch (err) {
    let status = err.status || 500;
    // 根据 status 渲染不同的页面
    if (status == 404) {
      yield render('error',{
        debug: S.DEBUG,
        title: '页面未找到',
        referer: this.request.header.referer,
        error: {
          status : 404
        }
      },this);
    }
    if (status == 500) {
      if(this.request.method === 'GET'){
        yield render('error',{
          debug: S.DEBUG,
          title: '系统发生错误',
          referer:this.request.header.referer,
          error: {
            status : 500,
            data: err
          }
        },this);
      }else{
        this.body = {
          status : 'FAIL::系统发生错误',
          error : err
        }
      }
      // 触发 koa 统一错误事件，可以打印出详细的错误堆栈 log
      this.app.emit('error', err, this);
    }
  }
})
//过滤非法URL请求
app.use(function *(next){
  let allow = false;
  for(let item in S.ALLOW_DOMAIN){
    if(this.hostname === S.ALLOW_DOMAIN[item]){
      allow = true;
    }
  }
  if(allow){
    yield next;
  }
})
R.use(userInfo);
//路由设置
R.use('/', index.routes(), index.allowedMethods());
R.use('/api', api.routes(), api.allowedMethods());
R.use('/content', content.routes(), content.allowedMethods());
R.use('/list', list.routes(), list.allowedMethods());
R.use('/search', search.routes(), search.allowedMethods());
R.use('/users', users.routes(), users.allowedMethods());
R.use('/'+S.ADMIN_DOMAIN, admin.routes(), admin.allowedMethods());

//绑定路由
app.use(R.routes());

//错误监听
app.on('error', function(err, ctx){
  logger('error',err);
});

export default app;
<|endoftext|>


<commit_before>/**
 * Web Worker to handle communications between the front-end and the core.
 *
 * @author n1474335 [n1474335@gmail.com]
 * @copyright Crown Copyright 2017
 * @license Apache-2.0
 */

import Chef from "./Chef";
import OperationConfig from "./config/OperationConfig.json";
import OpModules from "./config/modules/OpModules";

// Add ">" to the start of all log messages in the Chef Worker
import loglevelMessagePrefix from "loglevel-message-prefix";

loglevelMessagePrefix(log, {
    prefixes: [],
    staticPrefixes: [">"],
    prefixFormat: "%p"
});

// Set up Chef instance
self.chef = new Chef();

self.OpModules = OpModules;
self.OperationConfig = OperationConfig;
self.inputNum = -1;

// Tell the app that the worker has loaded and is ready to operate
self.postMessage({
    action: "workerLoaded",
    data: {}
});

/**
 * Respond to message from parent thread.
 *
 * Messages should have the following format:
 * {
 *     action: "bake" | "silentBake",
 *     data: {
 *         input: {string},
 *         recipeConfig: {[Object]},
 *         options: {Object},
 *         progress: {number},
 *         step: {boolean}
 *     } | undefined
 * }
 */
self.addEventListener("message", function(e) {
    // Handle message
    const r = e.data;
    log.debug("ChefWorker receiving command '" + r.action + "'");

    switch (r.action) {
        case "bake":
            bake(r.data);
            break;
        case "silentBake":
            silentBake(r.data);
            break;
        case "getDishAs":
            getDishAs(r.data);
            break;
        case "docURL":
            // Used to set the URL of the current document so that scripts can be
            // imported into an inline worker.
            self.docURL = r.data;
            break;
        case "highlight":
            calculateHighlights(
                r.data.recipeConfig,
                r.data.direction,
                r.data.pos
            );
            break;
        case "setLogLevel":
            log.setLevel(r.data, false);
            break;
        default:
            break;
    }
});

/**
 * Baking handler
 *
 * @param {Object} data
 */
async function bake(data) {
    // Ensure the relevant modules are loaded
    self.loadRequiredModules(data.recipeConfig);
    try {
        self.inputNum = parseInt(data.inputNum, 10);
        const response = await self.chef.bake(
            data.input,          // The user's input
            data.recipeConfig,   // The configuration of the recipe
            data.options,        // Options set by the user
            data.progress,       // The current position in the recipe
            data.step            // Whether or not to take one step or execute the whole recipe
        );

        if (data.input instanceof ArrayBuffer) {
            self.postMessage({
                action: "bakeComplete",
                data: Object.assign(response, {
                    id: data.id,
                    inputNum: data.inputNum,
                    bakeId: data.bakeId
                })
            }, [data.input]);
        } else {
            self.postMessage({
                action: "bakeComplete",
                data: Object.assign(response, {
                    id: data.id,
                    inputNum: data.inputNum,
                    bakeId: data.bakeId
                })
            });
        }
    } catch (err) {
        self.postMessage({
            action: "bakeError",
            data: {
                error: err.message || err,
                id: data.id,
                inputNum: data.inputNum
            }
        });
    }
    self.inputNum = -1;
}

/**
 * Silent baking handler
 */
function silentBake(data) {
    const duration = self.chef.silentBake(data.recipeConfig);

    self.postMessage({
        action: "silentBakeComplete",
        data: duration
    });
}

/**
 * Translates the dish to a given type.
 */
async function getDishAs(data) {
    const value = await self.chef.getDishAs(data.dish, data.type);

    if (data.type === "ArrayBuffer") {
        self.postMessage({
            action: "dishReturned",
            data: {
                value: value,
                id: data.id
            }
        }, [value]);
    } else {
        self.postMessage({
            action: "dishReturned",
            data: {
                value: value,
                id: data.id
            }
        });
    }
}

/**
 * Calculates highlight offsets if possible.
 *
 * @param {Object[]} recipeConfig
 * @param {string} direction
 * @param {Object} pos - The position object for the highlight.
 * @param {number} pos.start - The start offset.
 * @param {number} pos.end - The end offset.
 */
async function calculateHighlights(recipeConfig, direction, pos) {
    pos = await self.chef.calculateHighlights(recipeConfig, direction, pos);

    self.postMessage({
        action: "highlightsCalculated",
        data: pos
    });
}

/**
 * Checks that all required modules are loaded and loads them if not.
 *
 * @param {Object} recipeConfig
 */
self.loadRequiredModules = function(recipeConfig) {
    recipeConfig.forEach(op => {
        const module = self.OperationConfig[op.op].module;

        if (!OpModules.hasOwnProperty(module)) {
            log.info(`Loading ${module} module`);
            self.sendStatusMessage(`Loading ${module} module`);
            self.importScripts(`${self.docURL}/modules/${module}.js`);
            self.sendStatusMessage("");
        }
    });
};

/**
 * Send status update to the app.
 *
 * @param {string} msg
 */
self.sendStatusMessage = function(msg) {
    self.postMessage({
        action: "statusMessage",
        data: {
            message: msg,
            inputNum: self.inputNum || -1
        }
    });
};

/**
 * Send an option value update to the app.
 *
 * @param {string} option
 * @param {*} value
 */
self.setOption = function(option, value) {
    self.postMessage({
        action: "optionUpdate",
        data: {
            option: option,
            value: value
        }
    });
};

/**
 * Send register values back to the app.
 *
 * @param {number} opIndex
 * @param {number} numPrevRegisters
 * @param {string[]} registers
 */
self.setRegisters = function(opIndex, numPrevRegisters, registers) {
    self.postMessage({
        action: "setRegisters",
        data: {
            opIndex: opIndex,
            numPrevRegisters: numPrevRegisters,
            registers: registers
        }
    });
};
<commit_msg>Add documentation for inputNum. Fix syntax for transferable objects.<commit_after>/**
 * Web Worker to handle communications between the front-end and the core.
 *
 * @author n1474335 [n1474335@gmail.com]
 * @copyright Crown Copyright 2017
 * @license Apache-2.0
 */

import Chef from "./Chef";
import OperationConfig from "./config/OperationConfig.json";
import OpModules from "./config/modules/OpModules";

// Add ">" to the start of all log messages in the Chef Worker
import loglevelMessagePrefix from "loglevel-message-prefix";

loglevelMessagePrefix(log, {
    prefixes: [],
    staticPrefixes: [">"],
    prefixFormat: "%p"
});

// Set up Chef instance
self.chef = new Chef();

self.OpModules = OpModules;
self.OperationConfig = OperationConfig;
self.inputNum = -1;

// Tell the app that the worker has loaded and is ready to operate
self.postMessage({
    action: "workerLoaded",
    data: {}
});

/**
 * Respond to message from parent thread.
 *
 * An inputNum only needs to be sent when baking.
 * (The background ChefWorker doesn't send one, but as
 * it only deals with one input at a time it isn't needed)
 *
 * Messages should have the following format:
 * {
 *     action: "bake" | "silentBake",
 *     data: {
 *         input: {string},
 *         recipeConfig: {[Object]},
 *         options: {Object},
 *         progress: {number},
 *         step: {boolean},
 *         inputNum: {number} | undefined
 *     } | undefined
 * }
 */
self.addEventListener("message", function(e) {
    // Handle message
    const r = e.data;
    log.debug("ChefWorker receiving command '" + r.action + "'");

    switch (r.action) {
        case "bake":
            bake(r.data);
            break;
        case "silentBake":
            silentBake(r.data);
            break;
        case "getDishAs":
            getDishAs(r.data);
            break;
        case "docURL":
            // Used to set the URL of the current document so that scripts can be
            // imported into an inline worker.
            self.docURL = r.data;
            break;
        case "highlight":
            calculateHighlights(
                r.data.recipeConfig,
                r.data.direction,
                r.data.pos
            );
            break;
        case "setLogLevel":
            log.setLevel(r.data, false);
            break;
        default:
            break;
    }
});

/**
 * Baking handler
 *
 * @param {Object} data
 */
async function bake(data) {
    // Ensure the relevant modules are loaded
    self.loadRequiredModules(data.recipeConfig);
    try {
        self.inputNum = data.inputNum;
        const response = await self.chef.bake(
            data.input,          // The user's input
            data.recipeConfig,   // The configuration of the recipe
            data.options,        // Options set by the user
            data.progress,       // The current position in the recipe
            data.step            // Whether or not to take one step or execute the whole recipe
        );

        const transferable = (data.input instanceof ArrayBuffer) ? [data.input] : undefined;
        self.postMessage({
            action: "bakeComplete",
            data: Object.assign(response, {
                id: data.id,
                inputNum: data.inputNum,
                bakeId: data.bakeId
            })
        }, transferable);

    } catch (err) {
        self.postMessage({
            action: "bakeError",
            data: {
                error: err.message || err,
                id: data.id,
                inputNum: data.inputNum
            }
        });
    }
    self.inputNum = -1;
}

/**
 * Silent baking handler
 */
function silentBake(data) {
    const duration = self.chef.silentBake(data.recipeConfig);

    self.postMessage({
        action: "silentBakeComplete",
        data: duration
    });
}

/**
 * Translates the dish to a given type.
 */
async function getDishAs(data) {
    const value = await self.chef.getDishAs(data.dish, data.type);
    const transferable = (data.type === "ArrayBuffer") ? [value] : undefined;
    self.postMessage({
        action: "dishReturned",
        data: {
            value: value,
            id: data.id
        }
    }, transferable);
}

/**
 * Calculates highlight offsets if possible.
 *
 * @param {Object[]} recipeConfig
 * @param {string} direction
 * @param {Object} pos - The position object for the highlight.
 * @param {number} pos.start - The start offset.
 * @param {number} pos.end - The end offset.
 */
async function calculateHighlights(recipeConfig, direction, pos) {
    pos = await self.chef.calculateHighlights(recipeConfig, direction, pos);

    self.postMessage({
        action: "highlightsCalculated",
        data: pos
    });
}

/**
 * Checks that all required modules are loaded and loads them if not.
 *
 * @param {Object} recipeConfig
 */
self.loadRequiredModules = function(recipeConfig) {
    recipeConfig.forEach(op => {
        const module = self.OperationConfig[op.op].module;

        if (!OpModules.hasOwnProperty(module)) {
            log.info(`Loading ${module} module`);
            self.sendStatusMessage(`Loading ${module} module`);
            self.importScripts(`${self.docURL}/modules/${module}.js`);
            self.sendStatusMessage("");
        }
    });
};

/**
 * Send status update to the app.
 *
 * @param {string} msg
 */
self.sendStatusMessage = function(msg) {
    self.postMessage({
        action: "statusMessage",
        data: {
            message: msg,
            inputNum: self.inputNum
        }
    });
};

/**
 * Send an option value update to the app.
 *
 * @param {string} option
 * @param {*} value
 */
self.setOption = function(option, value) {
    self.postMessage({
        action: "optionUpdate",
        data: {
            option: option,
            value: value
        }
    });
};

/**
 * Send register values back to the app.
 *
 * @param {number} opIndex
 * @param {number} numPrevRegisters
 * @param {string[]} registers
 */
self.setRegisters = function(opIndex, numPrevRegisters, registers) {
    self.postMessage({
        action: "setRegisters",
        data: {
            opIndex: opIndex,
            numPrevRegisters: numPrevRegisters,
            registers: registers
        }
    });
};
<|endoftext|>


<commit_before>
"use strict";

let route;
let auth;
let loc;

class Controller {

    constructor($location, $rootScope, $route, $translate) {
        auth = angular.injector(['monad.Authentication']).get('Service');
        loc = $location;
        this.title = 'Default generic administrator';
        let reload = $route.reload;
        $route.reload = () => {
            this.modal = false;
            reload();
        };
        this.loginRequired = this.loginRequired || true;
        this.language = 'en';
        this.paths = {
            root: '/monad/',
            theme: 'monad/dist/default.css'
        };
        this.navigation = {
            main: [
                {url: '/', title: 'Site'}
            ]
        };
        $rootScope.$on('$routeChangeStart', () => this.Authentication.read().success(result => {
            if (!this.Authentication.isAuthenticated() && this.loginRequired) {
                loc.path('/' + this.language + '/login/');
            }
        }));
        $rootScope.$on('$routeChangeSuccess', (event, target) => {
            this.language = target.params.language;
            if (!this.language) {
                loc.path('/en/');
            }
            $translate.use(this.language);
        });
        route = $route;
        this.config();
        this.navigation.main.map(item => item.selected = item.url != '/' && ('#' + $location.path()).indexOf(item.url) != -1);
    }

    get Authentication() {
        return auth;
    }

    /**
     * This is for overriding in an extending root controller, so we don't
     * have to remember to re-inject all dependencies which would suck
     * pretty badly.
     */
    config() {
    }

    logout() {
        this.Authentication.logout().success(() => loc.path('/' + this.language + '/login/'));
    }

    select(menu, item = {}) {
        this.navigation[menu].map(item => item.selected = false);
        item.selected = true;
    }

    path(controller, params = {}) {
        params.language = params.language || this.language;
        for (let path in route.routes) {
            let pathController = route.routes[path].controller;
            if (pathController == controller) {
                let result = path;
                for (let param in params) {
                    result = result.replace(':' + param, params[param]);
                }
                return '#' + result.replace(/^#/, '');
            }
        }
        let result = controller;
        for (let param in params) {
            result = result.replace(':' + param, params[param]);
        }
        return '#' + result.replace(/^#/, '');
    }

    url() {
        return loc.path();
    }

    reload() {
        route.reload();
    }

};

Controller.$inject = ['$location', '$rootScope', '$route', '$translate'];

export {Controller};

<commit_msg>this can go, we can use ...args to prevent repetition<commit_after>
"use strict";

let route;
let auth;
let loc;

class Controller {

    constructor($location, $rootScope, $route, $translate) {
        auth = angular.injector(['monad.Authentication']).get('Service');
        loc = $location;
        this.title = 'Default generic administrator';
        let reload = $route.reload;
        $route.reload = () => {
            this.modal = false;
            reload();
        };
        this.loginRequired = this.loginRequired || true;
        this.language = 'en';
        this.paths = {
            root: '/monad/',
            theme: 'monad/dist/default.css'
        };
        this.navigation = {
            main: [
                {url: '/', title: 'Site'}
            ]
        };
        $rootScope.$on('$routeChangeStart', () => this.Authentication.read().success(result => {
            if (!this.Authentication.isAuthenticated() && this.loginRequired) {
                loc.path('/' + this.language + '/login/');
            }
        }));
        $rootScope.$on('$routeChangeSuccess', (event, target) => {
            this.language = target.params.language;
            if (!this.language) {
                loc.path('/en/');
            }
            $translate.use(this.language);
        });
        route = $route;
        this.config();
        this.navigation.main.map(item => item.selected = item.url != '/' && ('#' + $location.path()).indexOf(item.url) != -1);
    }

    get Authentication() {
        return auth;
    }

    logout() {
        this.Authentication.logout().success(() => loc.path('/' + this.language + '/login/'));
    }

    select(menu, item = {}) {
        this.navigation[menu].map(item => item.selected = false);
        item.selected = true;
    }

    path(controller, params = {}) {
        params.language = params.language || this.language;
        for (let path in route.routes) {
            let pathController = route.routes[path].controller;
            if (pathController == controller) {
                let result = path;
                for (let param in params) {
                    result = result.replace(':' + param, params[param]);
                }
                return '#' + result.replace(/^#/, '');
            }
        }
        let result = controller;
        for (let param in params) {
            result = result.replace(':' + param, params[param]);
        }
        return '#' + result.replace(/^#/, '');
    }

    url() {
        return loc.path();
    }

    reload() {
        route.reload();
    }

};

Controller.$inject = ['$location', '$rootScope', '$route', '$translate'];

export {Controller};

<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * @name PaperScope
 *
 * @class The {@code PaperScope} class represents the scope associated with a
 * Paper context. When working with PaperScript, these scopes are automatically
 * created and their fields and methods become part of the global scope. When
 * working with normal JavaScript files, {@code PaperScope} objects need to be
 * manually created and handled.
 * The global {@link _global_#paper} object is simply a reference to the
 * currently active {@code PaperScope}.
 */
var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
	initialize: function(id) {
		this.project = null;
		this.projects = [];
		this.view = null;
		this.views = [];
		this.tool = null;
		this.tools = [];
		this.id = id;
		PaperScope._scopes[id] = this;
	},

	/**
	 * The version of Paper.js, as a float number.
	 *
	 * @type Number
	 */
	version: /*#=*/ options.version,

	/**
	 * The currently active project.
	 * @name PaperScope#project
	 * @type Project
	 */

	/**
	 * The list of all open projects within the current Paper.js context.
	 * @name PaperScope#projects
	 * @type Project[]
	 */

	/**
	 * The active view of the active project.
	 * @name PaperScope#view
	 * @type View
	 */

	/**
	 * The list of view of the active project.
	 * @name PaperScope#views
	 * @type View[]
	 */

	/**
	 * The reference to the active tool.
	 * @name PaperScope#tool
	 * @type Tool
	 */

	/**
	 * The list of available tools.
	 * @name PaperScope#tools
	 * @type Tool[]
	 */

	evaluate: function(code) {
		var res = PaperScript.evaluate(code, this);
		View.updateFocus();
		return res;
	},

	/**
	 * Sets up the scope for a standard project, by creating an empty
	 * {@link Project} object for us, along with a {@link View} for the passed
	 * canvas, both linked to this scope.
	 */
	setup: function(canvas) {
		// We need to set the global paper reference to this scope,
		// since that will be used in the Project constructor to set
		// internal references.
		paper = this;
		new Project();
		if (canvas) {
			// Activate the newly created view straight away
			new View(canvas).activate();
		}
	},

	/**
	 * Injects the paper scope into any other given scope. Can be used for
	 * examle to inject the currently active PaperScope into the window's global
	 * scope, to emulate PaperScript-style globally accessible Paper classes and
	 * objects:
	 *
	 * @example
	 * paper.install(window);
	 */
	install: function(scope) {
		// Use scope as side-car (= 'this' inside iterator), and have it
		// returned at the end.
		return Base.each(this, function(value, key) {
			this[key] = value;
		}, scope);
	},

	clear: function() {
		// Remove all projects, views and tools.
		for (var i = this.projects.length - 1; i >= 0; i--)
			this.projects[i].remove();
		// This also removes the installed event handlers.
		for (var i = this.views.length - 1; i >= 0; i--)
			this.views[i].remove();
		for (var i = this.tools.length - 1; i >= 0; i--)
			this.tools[i].remove();
	},

	remove: function() {
		this.clear();
		delete PaperScope._scopes[this.id];
	},

	_needsRedraw: function() {
		// Make sure we're not looping through the view list each time...
		if (!this._redrawNotified) {
			for (var i = this.views.length - 1; i >= 0; i--)
				this.views[i]._redrawNeeded = true;
			this._redrawNotified = true;
		}
	},

	statics: /** @lends PaperScope */{
		_scopes: {},

		/**
		 * Retrieves a PaperScope object with the given id or associated with
		 * the passed canvas element.
		 *
		 * @param id
		 */
		get: function(id) {
			// If a script tag is passed, get the id from it.
			if (typeof id === 'object')
				id = id.getAttribute('id');
			return this._scopes[id] || null;
		},

		/**
		 * Iterates over all active scopes and calls the passed iterator
		 * function for each of them.
		 *
		 * @param iter the iterator function.
		 */
		each: function(iter) {
			Base.each(this._scopes, iter);
		}
	}
});
<commit_msg>Fix link to global paper variable.<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * @name PaperScope
 *
 * @class The {@code PaperScope} class represents the scope associated with a
 * Paper context. When working with PaperScript, these scopes are automatically
 * created and their fields and methods become part of the global scope. When
 * working with normal JavaScript files, {@code PaperScope} objects need to be
 * manually created and handled.
 * The global {@link paper} object is simply a reference to the
 * currently active {@code PaperScope}.
 */
var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
	initialize: function(id) {
		this.project = null;
		this.projects = [];
		this.view = null;
		this.views = [];
		this.tool = null;
		this.tools = [];
		this.id = id;
		PaperScope._scopes[id] = this;
	},

	/**
	 * The version of Paper.js, as a float number.
	 *
	 * @type Number
	 */
	version: /*#=*/ options.version,

	/**
	 * The currently active project.
	 * @name PaperScope#project
	 * @type Project
	 */

	/**
	 * The list of all open projects within the current Paper.js context.
	 * @name PaperScope#projects
	 * @type Project[]
	 */

	/**
	 * The active view of the active project.
	 * @name PaperScope#view
	 * @type View
	 */

	/**
	 * The list of view of the active project.
	 * @name PaperScope#views
	 * @type View[]
	 */

	/**
	 * The reference to the active tool.
	 * @name PaperScope#tool
	 * @type Tool
	 */

	/**
	 * The list of available tools.
	 * @name PaperScope#tools
	 * @type Tool[]
	 */

	evaluate: function(code) {
		var res = PaperScript.evaluate(code, this);
		View.updateFocus();
		return res;
	},

	/**
	 * Sets up the scope for a standard project, by creating an empty
	 * {@link Project} object for us, along with a {@link View} for the passed
	 * canvas, both linked to this scope.
	 */
	setup: function(canvas) {
		// We need to set the global paper reference to this scope,
		// since that will be used in the Project constructor to set
		// internal references.
		paper = this;
		new Project();
		if (canvas) {
			// Activate the newly created view straight away
			new View(canvas).activate();
		}
	},

	/**
	 * Injects the paper scope into any other given scope. Can be used for
	 * examle to inject the currently active PaperScope into the window's global
	 * scope, to emulate PaperScript-style globally accessible Paper classes and
	 * objects:
	 *
	 * @example
	 * paper.install(window);
	 */
	install: function(scope) {
		// Use scope as side-car (= 'this' inside iterator), and have it
		// returned at the end.
		return Base.each(this, function(value, key) {
			this[key] = value;
		}, scope);
	},

	clear: function() {
		// Remove all projects, views and tools.
		for (var i = this.projects.length - 1; i >= 0; i--)
			this.projects[i].remove();
		// This also removes the installed event handlers.
		for (var i = this.views.length - 1; i >= 0; i--)
			this.views[i].remove();
		for (var i = this.tools.length - 1; i >= 0; i--)
			this.tools[i].remove();
	},

	remove: function() {
		this.clear();
		delete PaperScope._scopes[this.id];
	},

	_needsRedraw: function() {
		// Make sure we're not looping through the view list each time...
		if (!this._redrawNotified) {
			for (var i = this.views.length - 1; i >= 0; i--)
				this.views[i]._redrawNeeded = true;
			this._redrawNotified = true;
		}
	},

	statics: /** @lends PaperScope */{
		_scopes: {},

		/**
		 * Retrieves a PaperScope object with the given id or associated with
		 * the passed canvas element.
		 *
		 * @param id
		 */
		get: function(id) {
			// If a script tag is passed, get the id from it.
			if (typeof id === 'object')
				id = id.getAttribute('id');
			return this._scopes[id] || null;
		},

		/**
		 * Iterates over all active scopes and calls the passed iterator
		 * function for each of them.
		 *
		 * @param iter the iterator function.
		 */
		each: function(iter) {
			Base.each(this._scopes, iter);
		}
	}
});
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import 'bulma/css/bulma.css';
import './index.css';
import App from './containers/App';
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
<commit_msg>Add hot reloading<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import 'bulma/css/bulma.css';
import './index.css';
import App from './containers/App';
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();

if (module.hot) {
  module.hot.accept('./containers/App', () => {
    const NextApp = require('./containers/App').default;
    ReactDOM.render(<NextApp />, document.getElementById('root'));
  });
}
<|endoftext|>


<commit_before>import weedux, { middleware } from 'weedux';
import { pageView, event, error, time } from './ga.js';

export const initialState = {
  servers: {
    gamesRefreshCount: 0,
    games: [],
    details: {},
    loading: true,
    error: ""
  },
  search: {
    terms: "",
    noPassOnly: false,
    userVerificationMode: "show"
  }
};

function initActions(dispatch){
  return {
    games: () => dispatch((d) => {
      d({ type: "GAMES_START" });

      fetch(`${process.env.REACT_APP_API_SERVER_HOST}/api/v1/games`)
        .then(r => r.json())
        .then((p) => d({ type: "GAMES_COMPLETE", payload: p}))
        .catch((e) => d({ type: "GAMES_FAIL", error: e }));
    }),
    details: (gameId, index) => dispatch((d) => {
      d({ type: "DETAILS_START" });

      fetch(`${process.env.REACT_APP_API_SERVER_HOST}/api/v1/details?gameId=${gameId}`)
        .then(r => r.json())
        .then((p) => d({ type: "DETAILS_COMPLETE", gameId, payload: p }))
        .catch((e) => d({ type: "DETAILS_FAIL", gameId, error: e }));
    })
  }
}

const reducers = [
  (s, a) => {
    const newState = { ...s };

    switch(a.type){
      case "GAMES_START":
      case "DETAILS_START":
        newState.servers.details[a.gameId] = { loading: true };
        break;

      case "GAMES_COMPLETE":
        event({
          category: "API Call",
          action: "Loaded Games",
          label: "API returned " + a.payload.length + " games.",
          value: newState.servers.gamesRefreshCount + 1
        });
        newState.servers.gamesRefreshCount++;
        newState.servers.games = a.payload;
        newState.servers.loading = false;
        break;

      case "DETAILS_COMPLETE":
        newState.servers.details[a.gameId] = { ...a.payload, loading: false };
        break;

      case "GAMES_FAIL":
        error("Could not load games: " + a.error, true);
        newState.servers.loading = false;
        newState.servers.error = "woops.jpg";
        break;

      case "DETAILS_FAIL":
        error("Could not load game details for game " + a.gameId + " :" + a.error, true);
        newState.servers.loading = false;
        newState.servers.error = "woops.jpg";
        break;

      default:
        return newState;
    }

    return newState;
  }
];

const store = new weedux( initialState, reducers, [middleware.thunk]);

export const actions = initActions(store.dispatcher().bind(store));
export default store;
<commit_msg>remove unused stuff<commit_after>import weedux, { middleware } from 'weedux';
import { event, error } from './ga.js';

export const initialState = {
  servers: {
    gamesRefreshCount: 0,
    games: [],
    details: {},
    loading: true,
    error: ""
  },
  search: {
    terms: "",
    noPassOnly: false,
    userVerificationMode: "show"
  }
};

function initActions(dispatch){
  return {
    games: () => dispatch((d) => {
      d({ type: "GAMES_START" });

      fetch(`${process.env.REACT_APP_API_SERVER_HOST}/api/v1/games`)
        .then(r => r.json())
        .then((p) => d({ type: "GAMES_COMPLETE", payload: p}))
        .catch((e) => d({ type: "GAMES_FAIL", error: e }));
    }),
    details: (gameId, index) => dispatch((d) => {
      d({ type: "DETAILS_START" });

      fetch(`${process.env.REACT_APP_API_SERVER_HOST}/api/v1/details?gameId=${gameId}`)
        .then(r => r.json())
        .then((p) => d({ type: "DETAILS_COMPLETE", gameId, payload: p }))
        .catch((e) => d({ type: "DETAILS_FAIL", gameId, error: e }));
    })
  }
}

const reducers = [
  (s, a) => {
    const newState = { ...s };

    switch(a.type){
      case "GAMES_START":
      case "DETAILS_START":
        newState.servers.details[a.gameId] = { loading: true };
        break;

      case "GAMES_COMPLETE":
        event({
          category: "API Call",
          action: "Loaded Games",
          label: "API returned " + a.payload.length + " games.",
          value: newState.servers.gamesRefreshCount + 1
        });
        newState.servers.gamesRefreshCount++;
        newState.servers.games = a.payload;
        newState.servers.loading = false;
        break;

      case "DETAILS_COMPLETE":
        newState.servers.details[a.gameId] = { ...a.payload, loading: false };
        break;

      case "GAMES_FAIL":
        error("Could not load games: " + a.error, true);
        newState.servers.loading = false;
        newState.servers.error = "woops.jpg";
        break;

      case "DETAILS_FAIL":
        error("Could not load game details for game " + a.gameId + " :" + a.error, true);
        newState.servers.loading = false;
        newState.servers.error = "woops.jpg";
        break;

      default:
        return newState;
    }

    return newState;
  }
];

const store = new weedux( initialState, reducers, [middleware.thunk]);

export const actions = initActions(store.dispatcher().bind(store));
export default store;
<|endoftext|>


<commit_before>/* Dispatch area - Should be eliminate after dispatching */

var markersGroup = new L.LayerGroup();
var isDispatching = false;
var placeIcon = L.icon({
	iconUrl: '/static/icons/place_marker.png',
	iconSize: [40, 40],
	iconAnchor: [20, 40],
	popupAnchor: [0,-40]
});

var dispatchingAmbulances = {};
var numberOfDispatchingAmbulances = 0;

var currentAddress;
var currentLocation;
var patients;
var paientsIndices;
var newPatientIndex;

var beginDispatching = function () {

    isDispatching = true;
    console.log('Begin dispatching.');

    $('#start_dispatch_button').hide();

    // Update current location
    updateCurrentLocation(mymap.getCenter());

    // Update current address
    updateCurrentAddress(currentLocation);

    // Clear current patients
    patients = [];
    patientsIndicies = [];
    newPatientIndex = 0;

    // Initialize patient form
    $('#patients').empty();

    // add new patient form entry
    $('#patients').html(newPatientForm(newPatientIndex, 'plus'));

    // associated button
    $('#patient-' + newPatientIndex + ' -button').click(function(e) {
        addPatient(newPatientIndex);
    });

}

var newPatientForm = function(index, symbol) {

    return '
' +
        '
' +
        '        <input id="patient-' + index + '-name" type="text"' +
        '               class="form-control"' +
        '               placeholder="Name">' +
        '
' +
        '
' +
        '        <input id="patient-' + index + '-age" type="text"' +
        '               class="form-control"' +
        '               placeholder="Age"/>' +
        '
' +
        '
' +
        '        <button class="btn btn-default new-patient"' +
        '                type="button"' +
        '                id="patient-' + index + '-button">' +
        '            ' +
        '        </button>' +
        '
' +
        '
';

}

var endDispatching = function () {

    isDispatching = false;
    dispatchingAmbulances = {};
    console.log('End dispatching.');

    markersGroup.clearLayers();

    $('#start_dispatch_button').show();

}

var removeFromDispatchingList = function(ambulance) {

    // delete from dispatching list
    delete dispatchingAmbulances[ambulance.id];
    numberOfDispatchingAmbulances--;

    // show message if last button
    if (numberOfDispatchingAmbulances == 0)
        $('#ambulance-selection-message').show();

}

var addToDispatchingList = function(ambulance) {

    // quick return if null or not dispatching
    if (ambulance == null || !isDispatching)
        return;

    // add ambulance to dispatching list
    console.log('Adding ambulance ' + ambulance.identifier + ' to dispatching list');

    // already in?
    if (ambulance.id in dispatchingAmbulances) {
        console.log('Already in dispatching list, skip');
        return;
    }

    // not available?
    if (ambulance.status != STATUS_AVAILABLE) {
        console.log('Ambulance is not available');
        alert('Can only dispatch available ambulances!');
        return;
    }

    // hide message if first button
    if (numberOfDispatchingAmbulances == 0)
        $('#ambulance-selection-message').hide();

    // add ambulance to list of dispatching ambulances
    dispatchingAmbulances[ambulance.id] = ambulance;
    numberOfDispatchingAmbulances++;

    // add button to ambulance dispatch grid
    $('#ambulance-selection').append(
        '<button id="dispatch-button-' + ambulance.id + '"'
        + ' value="' + ambulance.id + '"'
        + ' type="button" class="btn btn-sm btn-success"'
        + ' style="margin: 2px 2px;"'
        + ' draggable="true">'
        + ambulance.identifier
        + '</button>'
    );
    $('#dispatch-button-' + ambulance.id)
        .on('dragstart', function (e) {
            // on start of drag, copy information and fade button
            console.log('dragstart');
            this.style.opacity = '0.4';
            e.originalEvent.dataTransfer.setData("text/plain", ambulance.id);
        })
        .on('dragend', function (e) {
            console.log('dragend');
            if (e.originalEvent.dataTransfer.dropEffect == 'none') {
                // Remove button if not dropped back
                removeFromDispatchingList(ambulance);
                // Remove button
                $(this).remove();
            } else {
                // Restore opacity if dropped back in
                this.style.opacity = '1.0';
            }
        });
}

var updateCurrentLocation = function(location) {

    console.log('Setting current location to: ' + location.lat + ', ' + location.lng);

    // set currentLocation
    currentLocation = location;

    // update coordinates on form
    $('#curr-lat').html(currentLocation.lat);
    $('#curr-lng').html(currentLocation.lng);

    // remove existing marker
    markersGroup.clearLayers();

    // laydown marker
    var marker = L.marker(location,
        {
            icon: placeIcon,
            draggable: true
        })
        .addTo(markersGroup);
    markersGroup.addTo(mymap);

    // pan to location
    mymap.panTo(location);

    // events
    marker.on('dragend', function(e) {

        // update current location
        updateCurrentLocation(marker.getLatLng());

        // update address?
        if ($('#update-address').prop('checked'))
            updateCurrentAddress(currentLocation);

    })

}

var updateCurrentAddress = function(location) {

    var options = {
        types: 'address',
        limit: 1
    };
    geocoder.reverse(location, options,
        function (results, status) {

        if (status != "success") {
            alert("Could not geocode:\nError " + status + ", " + results['error']);
            return;
        }

        // quick return if found nothing
        if (results.length == 0) {
            console.log('Got nothing from geocode');
            return;
        }

        // parse features into current address
        currentAddress = geocoder.parse_feature(results[0]);

        console.log(
            'Setting currentAddress to:'
            + '\nnumber: ' + currentAddress['number']
            + '\nstreet: ' + currentAddress['street']
            + '\nunit: ' + currentAddress['unit']
            + '\nlocation: ' + currentAddress['location']['latitude']
            + ',' + currentAddress['location']['longitude']
            + '\nneighborhood: ' + currentAddress['neighborhood']
            + '\nzipcode: ' + currentAddress['zipcode']
            + '\ncity: ' + currentAddress['city']
            + '\nstate: ' + currentAddress['state']
            + '\ncountry: ' + currentAddress['country']
        );

        // set input text
        $('#street').val(currentAddress['street_address']);

    });

}

var updateCoordinates = function() {

    // when the user changes the street address
    var address =$('#street').val();

    // quick return if no address
    if (!address)
        return;

    // otherwise geocode and update
    var options = {
        types: 'address',
        limit: 1,
        autocomplete: 'true'
    };
    geocoder.geocode(address, options,
        function (results, status) {

            if (status != "success") {
                alert("Could not geocode:\nError " + status + ", " + results['error']);
                return;
            }

            // quick return if found nothing
            if (results.length == 0) {
                console.log('Got nothing from geocode');
                return;
            }

            // parse features into address
            var address = geocoder.parse_feature(results[0]);

            console.log(
                'Setting currentLocation to:'
                + '\nnumber: ' + address['number']
                + '\nstreet: ' + address['street']
                + '\nunit: ' + address['unit']
                + '\nlocation: ' + address['location']['latitude']
                + ',' + address['location']['longitude']
                + '\nneighborhood: ' + address['neighborhood']
                + '\nzipcode: ' + address['zipcode']
                + '\ncity: ' + address['city']
                + '\nstate: ' + address['state']
                + '\ncountry: ' + address['country']
            );

            // set current location
            updateCurrentLocation({
                lat: address['location']['latitude'],
                lng: address['location']['longitude']
            });

        });
}

var addPatient = function() {

}

// connect actions to inputs

$("#street").change(function () {

    // update coordinates?
    if ($('#update-coordinates').prop('checked'))
        updateCoordinates();

});

$('#update-coordinates').change(function() {

    // update coordinates?
    if ($('#update-coordinates').prop('checked'))
        updateCoordinates();

});

$('#update-address').change(function() {

    // update address?
    if ($('#update-address').prop('checked'))
        updateCurrentAddress(currentLocation);

});

$('#dispatch_form_collapse').submit(function (e) {

   // prevent normal form submission
    e.preventDefault();

    // dispatch call
    dispatchCall();

});

/*
 * dispatchCall makes an ajax post request to post dispatched ambulance.
 * @param void.
 * @return void.
 */
function dispatchCall() {

    var form = {};

    // call information
    form['details'] = $('#comment').val();
    form['priority'] = $('input:radio[name=priority]:checked').val();

    // checks
    if (form["priority"] === undefined) {
        alert("Please click one of priorities");
        return;
    }
    if (numberOfDispatchingAmbulances == 0) {
        alert("Please dispatch at least one ambulance");
        return;
    }

    // address information
    form['number'] = currentAddress['number'];
    form['street'] = currentAddress['street'];
    form['unit'] = currentAddress['unit'];
    form['neighborbood'] = currentAddress['neighborhood'];
    form['city'] = currentAddress['city'];
    form['state'] = currentAddress['state'];
    form['country'] = currentAddress['country'];
    form['zipcode'] = currentAddress['zipcode'];
    form['location'] = currentAddress['location'];

    // ambulances
    var ambulances = [];
    for (var id in dispatchingAmbulances)
        if (dispatchingAmbulances.hasOwnProperty(id))
            ambulances.push(id);
    form['ambulances'] = ambulances;

    // TODO: patients

    // make json call
    let postJsonUrl = 'api/call/';
    console.log("Will post '" + JSON.stringify(form) + "'");

    var CSRFToken = getCookie('csrftoken');

    // retrieve csrf token
    $.ajaxSetup({
        beforeSend: function (xhr, settings) {
            if (!CSRFSafeMethod(settings.type)) {
                xhr.setRequestHeader("X-CSRFToken", CSRFToken);
            }
        }
    })

    // make ajax call
    $.ajax({
        url: postJsonUrl,
        type: 'POST',
        dataType: 'json',
        data: form,
        success: function (data) {

            // alert(JSON.stringify(data));
            var successMsg = 'Success
' +
                +'Ambulance: ' + data['ambulance']
                + ' dispatched to
' + data['residential_unit']
                + ', ' + data['stmain_number'] + ', ' + data['latitude'] + ', ' + data['longitude'];

            // Show modal
            $('.modal-title').html('Success');
            $('.modal-body').html(successMsg).addClass('alert-success');
            $("#dispatchModal").modal('show');

            endDispatching();
        },
        error: function (jqXHR, textStatus, errorThrown) {

            // Show modal
            $('.modal-title').html('Failure');
            $('.modal-body').html(textStatus + ": " + errorThrown).addClass('alert-danger');
            $("#dispatchModal").modal('show');

            endDispatching();
        }
    });
}

function CSRFSafeMethod(method) {
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

/*
 * getCookie extracts the csrf token for form submit
 */
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = $.trim(cookies[i]);
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
<commit_msg>Upgrading to Bootstrap 4.0<commit_after>/* Dispatch area - Should be eliminate after dispatching */

var markersGroup = new L.LayerGroup();
var isDispatching = false;
var placeIcon = L.icon({
	iconUrl: '/static/icons/place_marker.png',
	iconSize: [40, 40],
	iconAnchor: [20, 40],
	popupAnchor: [0,-40]
});

var dispatchingAmbulances = {};
var numberOfDispatchingAmbulances = 0;

var currentAddress;
var currentLocation;
var patients;
var paientsIndices;
var newPatientIndex;

var beginDispatching = function () {

    isDispatching = true;
    console.log('Begin dispatching.');

    $('#start_dispatch_button').hide();

    // Update current location
    updateCurrentLocation(mymap.getCenter());

    // Update current address
    updateCurrentAddress(currentLocation);

    // Clear current patients
    patients = [];
    patientsIndicies = [];
    newPatientIndex = 0;

    // Initialize patient form
    $('#patients').empty();

    // add new patient form entry
    $('#patients').html(newPatientForm(newPatientIndex, 'plus'));

    // associated button
    $('#patient-' + newPatientIndex + ' -button').click(function(e) {
        addPatient(newPatientIndex);
    });

}

var newPatientForm = function(index, symbol) {

    return '
' +
        '
' +
        '        <input id="patient-' + index + '-name" type="text"' +
        '               class="form-control"' +
        '               placeholder="Name">' +
        '
' +
        '
' +
        '        <input id="patient-' + index + '-age" type="text"' +
        '               class="form-control"' +
        '               placeholder="Age"/>' +
        '
' +
        '
' +
        '        <button class="btn btn-default new-patient"' +
        '                type="button"' +
        '                id="patient-' + index + '-button">' +
        '            ' +
        '        </button>' +
        '
' +
        '
';

}

var endDispatching = function () {

    isDispatching = false;
    dispatchingAmbulances = {};
    console.log('End dispatching.');

    markersGroup.clearLayers();

    $('#start_dispatch_button').show();

}

var removeFromDispatchingList = function(ambulance) {

    // delete from dispatching list
    delete dispatchingAmbulances[ambulance.id];
    numberOfDispatchingAmbulances--;

    // show message if last button
    if (numberOfDispatchingAmbulances == 0)
        $('#ambulance-selection-message').show();

}

var addToDispatchingList = function(ambulance) {

    // quick return if null or not dispatching
    if (ambulance == null || !isDispatching)
        return;

    // add ambulance to dispatching list
    console.log('Adding ambulance ' + ambulance.identifier + ' to dispatching list');

    // already in?
    if (ambulance.id in dispatchingAmbulances) {
        console.log('Already in dispatching list, skip');
        return;
    }

    // not available?
    if (ambulance.status != STATUS_AVAILABLE) {
        console.log('Ambulance is not available');
        alert('Can only dispatch available ambulances!');
        return;
    }

    // hide message if first button
    if (numberOfDispatchingAmbulances == 0)
        $('#ambulance-selection-message').hide();

    // add ambulance to list of dispatching ambulances
    dispatchingAmbulances[ambulance.id] = ambulance;
    numberOfDispatchingAmbulances++;

    // add button to ambulance dispatch grid
    $('#ambulance-selection').append(
        '<button id="dispatch-button-' + ambulance.id + '"'
        + ' value="' + ambulance.id + '"'
        + ' type="button" class="btn btn-sm btn-success"'
        + ' style="margin: 2px 2px;"'
        + ' draggable="true">'
        + ambulance.identifier
        + '</button>'
    );
    $('#dispatch-button-' + ambulance.id)
        .on('dragstart', function (e) {
            // on start of drag, copy information and fade button
            console.log('dragstart');
            this.style.opacity = '0.4';
            e.originalEvent.dataTransfer.setData("text/plain", ambulance.id);
        })
        .on('dragend', function (e) {
            console.log('dragend');
            if (e.originalEvent.dataTransfer.dropEffect == 'none') {
                // Remove button if not dropped back
                removeFromDispatchingList(ambulance);
                // Remove button
                $(this).remove();
            } else {
                // Restore opacity if dropped back in
                this.style.opacity = '1.0';
            }
        });
}

var updateCurrentLocation = function(location) {

    console.log('Setting current location to: ' + location.lat + ', ' + location.lng);

    // set currentLocation
    currentLocation = location;

    // update coordinates on form
    $('#curr-lat').html(currentLocation.lat);
    $('#curr-lng').html(currentLocation.lng);

    // remove existing marker
    markersGroup.clearLayers();

    // laydown marker
    var marker = L.marker(location,
        {
            icon: placeIcon,
            draggable: true
        })
        .addTo(markersGroup);
    markersGroup.addTo(mymap);

    // pan to location
    mymap.panTo(location);

    // events
    marker.on('dragend', function(e) {

        // update current location
        updateCurrentLocation(marker.getLatLng());

        // update address?
        if ($('#update-address').prop('checked'))
            updateCurrentAddress(currentLocation);

    })

}

var updateCurrentAddress = function(location) {

    var options = {
        types: 'address',
        limit: 1
    };
    geocoder.reverse(location, options,
        function (results, status) {

        if (status != "success") {
            alert("Could not geocode:\nError " + status + ", " + results['error']);
            return;
        }

        // quick return if found nothing
        if (results.length == 0) {
            console.log('Got nothing from geocode');
            return;
        }

        // parse features into current address
        currentAddress = geocoder.parse_feature(results[0]);

        console.log(
            'Setting currentAddress to:'
            + '\nnumber: ' + currentAddress['number']
            + '\nstreet: ' + currentAddress['street']
            + '\nunit: ' + currentAddress['unit']
            + '\nlocation: ' + currentAddress['location']['latitude']
            + ',' + currentAddress['location']['longitude']
            + '\nneighborhood: ' + currentAddress['neighborhood']
            + '\nzipcode: ' + currentAddress['zipcode']
            + '\ncity: ' + currentAddress['city']
            + '\nstate: ' + currentAddress['state']
            + '\ncountry: ' + currentAddress['country']
        );

        // set input text
        $('#street').val(currentAddress['street_address']);

    });

}

var updateCoordinates = function() {

    // when the user changes the street address
    var address =$('#street').val();

    // quick return if no address
    if (!address)
        return;

    // otherwise geocode and update
    var options = {
        types: 'address',
        limit: 1,
        autocomplete: 'true'
    };
    geocoder.geocode(address, options,
        function (results, status) {

            if (status != "success") {
                alert("Could not geocode:\nError " + status + ", " + results['error']);
                return;
            }

            // quick return if found nothing
            if (results.length == 0) {
                console.log('Got nothing from geocode');
                return;
            }

            // parse features into address
            var address = geocoder.parse_feature(results[0]);

            console.log(
                'Setting currentLocation to:'
                + '\nnumber: ' + address['number']
                + '\nstreet: ' + address['street']
                + '\nunit: ' + address['unit']
                + '\nlocation: ' + address['location']['latitude']
                + ',' + address['location']['longitude']
                + '\nneighborhood: ' + address['neighborhood']
                + '\nzipcode: ' + address['zipcode']
                + '\ncity: ' + address['city']
                + '\nstate: ' + address['state']
                + '\ncountry: ' + address['country']
            );

            // set current location
            updateCurrentLocation({
                lat: address['location']['latitude'],
                lng: address['location']['longitude']
            });

        });
}

var addPatient = function(index) {

    console.log('Adding patient index ' + index);

}

// connect actions to inputs

$("#street").change(function () {

    // update coordinates?
    if ($('#update-coordinates').prop('checked'))
        updateCoordinates();

});

$('#update-coordinates').change(function() {

    // update coordinates?
    if ($('#update-coordinates').prop('checked'))
        updateCoordinates();

});

$('#update-address').change(function() {

    // update address?
    if ($('#update-address').prop('checked'))
        updateCurrentAddress(currentLocation);

});

$('#dispatch_form_collapse').submit(function (e) {

   // prevent normal form submission
    e.preventDefault();

    // dispatch call
    dispatchCall();

});

/*
 * dispatchCall makes an ajax post request to post dispatched ambulance.
 * @param void.
 * @return void.
 */
function dispatchCall() {

    var form = {};

    // call information
    form['details'] = $('#comment').val();
    form['priority'] = $('input:radio[name=priority]:checked').val();

    // checks
    if (form["priority"] === undefined) {
        alert("Please click one of priorities");
        return;
    }
    if (numberOfDispatchingAmbulances == 0) {
        alert("Please dispatch at least one ambulance");
        return;
    }

    // address information
    form['number'] = currentAddress['number'];
    form['street'] = currentAddress['street'];
    form['unit'] = currentAddress['unit'];
    form['neighborbood'] = currentAddress['neighborhood'];
    form['city'] = currentAddress['city'];
    form['state'] = currentAddress['state'];
    form['country'] = currentAddress['country'];
    form['zipcode'] = currentAddress['zipcode'];
    form['location'] = currentAddress['location'];

    // ambulances
    var ambulances = [];
    for (var id in dispatchingAmbulances)
        if (dispatchingAmbulances.hasOwnProperty(id))
            ambulances.push(id);
    form['ambulances'] = ambulances;

    // TODO: patients

    // make json call
    let postJsonUrl = 'api/call/';
    console.log("Will post '" + JSON.stringify(form) + "'");

    var CSRFToken = getCookie('csrftoken');

    // retrieve csrf token
    $.ajaxSetup({
        beforeSend: function (xhr, settings) {
            if (!CSRFSafeMethod(settings.type)) {
                xhr.setRequestHeader("X-CSRFToken", CSRFToken);
            }
        }
    })

    // make ajax call
    $.ajax({
        url: postJsonUrl,
        type: 'POST',
        dataType: 'json',
        data: form,
        success: function (data) {

            // alert(JSON.stringify(data));
            var successMsg = 'Success
' +
                +'Ambulance: ' + data['ambulance']
                + ' dispatched to
' + data['residential_unit']
                + ', ' + data['stmain_number'] + ', ' + data['latitude'] + ', ' + data['longitude'];

            // Show modal
            $('.modal-title').html('Success');
            $('.modal-body').html(successMsg).addClass('alert-success');
            $("#dispatchModal").modal('show');

            endDispatching();
        },
        error: function (jqXHR, textStatus, errorThrown) {

            // Show modal
            $('.modal-title').html('Failure');
            $('.modal-body').html(textStatus + ": " + errorThrown).addClass('alert-danger');
            $("#dispatchModal").modal('show');

            endDispatching();
        }
    });
}

function CSRFSafeMethod(method) {
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

/*
 * getCookie extracts the csrf token for form submit
 */
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = $.trim(cookies[i]);
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
<|endoftext|>