<commit_before>const {app, protocol, webContents, BrowserWindow} = require('electron')
const renderProcessPreferences = process.atomBinding('render_process_preferences').forAllBrowserWindow()

const fs = require('fs')
const path = require('path')
const url = require('url')

// TODO(zcbenz): Remove this when we have Object.values().
const objectValues = function (object) {
  return Object.keys(object).map(function (key) { return object[key] })
}

// Mapping between hostname and file path.
const hostPathMap = {}
let hostPathMapNextKey = 0

const generateHostForPath = function (path) {
  const key = `extension-${++hostPathMapNextKey}`
  hostPathMap[key] = path
  return key
}

const getPathForHost = function (host) {
  return hostPathMap[host]
}

// Cache manifests.
const manifestMap = {}

const getManifestFromPath = function (srcDirectory) {
  const manifest = JSON.parse(fs.readFileSync(path.join(srcDirectory, 'manifest.json')))
  if (!manifestMap[manifest.name]) {
    const hostname = generateHostForPath(srcDirectory)
    manifestMap[manifest.name] = manifest
    Object.assign(manifest, {
      srcDirectory: srcDirectory,
      hostname: hostname,
      // We can not use 'file://' directly because all resources in the extension
      // will be treated as relative to the root in Chrome.
      startPage: url.format({
        protocol: 'chrome-extension',
        slashes: true,
        hostname: hostname,
        pathname: manifest.devtools_page
      })
    })
    return manifest
  }
}

// Manage the background pages.
const backgroundPages = {}

const startBackgroundPages = function (manifest) {
  if (backgroundPages[manifest.hostname] || !manifest.background) return

  const scripts = manifest.background.scripts.map((name) => {
    return `<script src="${name}"></script>`
  }).join('')
  const html = new Buffer(`<html><body>${scripts}</body></html>`)

  const contents = webContents.create({})
  backgroundPages[manifest.hostname] = { html: html, contents: contents }
  contents.loadURL(url.format({
    protocol: 'chrome-extension',
    slashes: true,
    hostname: manifest.hostname,
    pathname: '_generated_background_page.html'
  }))
}

// Transfer the content scripts to renderer.
const contentScripts = {}

const injectContentScripts = function (manifest) {
  if (contentScripts[manifest.name] || !manifest.content_scripts) return

  const readArrayOfFiles = function (relativePath) {
    return fs.readFileSync(path.join(manifest.srcDirectory, relativePath))
  }

  const contentScriptToEntry = function (script) {
    return {
      matches: script.matches,
      js: script.js.map(readArrayOfFiles),
      run_at: script.run_at || 'document_idle'
    }
  }

  try {
    const entry = {
      contentScripts: manifest.content_scripts.map(contentScriptToEntry)
    }
    contentScripts[manifest.name] = renderProcessPreferences.addEntry(entry)
  } catch (e) {
    console.error('Failed to read content scripts', e)
  }
}

// Transfer the |manifest| to a format that can be recognized by the
// |DevToolsAPI.addExtensions|.
const manifestToExtensionInfo = function (manifest) {
  return {
    startPage: manifest.startPage,
    srcDirectory: manifest.srcDirectory,
    name: manifest.name,
    exposeExperimentalAPIs: true
  }
}

// Load the extensions for the window.
const loadDevToolsExtensions = function (win, manifests) {
  if (!win.devToolsWebContents) return

  for (const manifest of manifests) {
    startBackgroundPages(manifest)
    injectContentScripts(manifest)
  }
  const extensionInfoArray = manifests.map(manifestToExtensionInfo)
  win.devToolsWebContents.executeJavaScript(`DevToolsAPI.addExtensions(${JSON.stringify(extensionInfoArray)})`)
}

// The persistent path of "DevTools Extensions" preference file.
let loadedExtensionsPath = null

app.on('will-quit', function () {
  try {
    const loadedExtensions = objectValues(manifestMap).map(function (manifest) {
      return manifest.srcDirectory
    })
    if (loadedExtensions.length > 0) {
      try {
        fs.mkdirSync(path.dirname(loadedExtensionsPath))
      } catch (error) {
        // Ignore error
      }
      fs.writeFileSync(loadedExtensionsPath, JSON.stringify(loadedExtensions))
    } else {
      fs.unlinkSync(loadedExtensionsPath)
    }
  } catch (error) {
    // Ignore error
  }
})

// We can not use protocol or BrowserWindow until app is ready.
app.once('ready', function () {
  // Load persisted extensions.
  loadedExtensionsPath = path.join(app.getPath('userData'), 'DevTools Extensions')
  try {
    const loadedExtensions = JSON.parse(fs.readFileSync(loadedExtensionsPath))
    if (Array.isArray(loadedExtensions)) {
      // Preheat the manifest cache.
      for (const srcDirectory of loadedExtensions) {
        getManifestFromPath(srcDirectory)
      }
    }
  } catch (error) {
    // Ignore error
  }

  // The chrome-extension: can map a extension URL request to real file path.
  const chromeExtensionHandler = function (request, callback) {
    const parsed = url.parse(request.url)
    if (!parsed.hostname || !parsed.path) return callback()
    if (!/extension-\d+/.test(parsed.hostname)) return callback()

    const directory = getPathForHost(parsed.hostname)
    if (!directory) return callback()

    if (parsed.path === '/_generated_background_page.html' &&
        backgroundPages[parsed.hostname]) {
      return callback({
        mimeType: 'text/html',
        data: backgroundPages[parsed.hostname].html
      })
    }

    fs.readFile(path.join(directory, parsed.path), function (err, content) {
      if (err) {
        return callback(-6)  // FILE_NOT_FOUND
      } else {
        return callback({mimeType: 'text/html', data: content})
      }
    })
  }
  protocol.registerBufferProtocol('chrome-extension', chromeExtensionHandler, function (error) {
    if (error) {
      console.error(`Unable to register chrome-extension protocol: ${error}`)
    }
  })

  BrowserWindow.addDevToolsExtension = function (srcDirectory) {
    const manifest = getManifestFromPath(srcDirectory)
    if (manifest) {
      for (const win of BrowserWindow.getAllWindows()) {
        loadDevToolsExtensions(win, [manifest])
      }
      return manifest.name
    }
  }
  BrowserWindow.removeDevToolsExtension = function (name) {
    delete manifestMap[name]
  }

  // Load persisted extensions when devtools is opened.
  const init = BrowserWindow.prototype._init
  BrowserWindow.prototype._init = function () {
    init.call(this)
    this.webContents.on('devtools-opened', () => {
      loadDevToolsExtensions(this, objectValues(manifestMap))
    })
  }
})
<commit_msg>Handle unloading devtools correctly<commit_after>const {app, protocol, webContents, BrowserWindow} = require('electron')
const renderProcessPreferences = process.atomBinding('render_process_preferences').forAllBrowserWindow()

const fs = require('fs')
const path = require('path')
const url = require('url')

// TODO(zcbenz): Remove this when we have Object.values().
const objectValues = function (object) {
  return Object.keys(object).map(function (key) { return object[key] })
}

// Mapping between hostname and file path.
const hostPathMap = {}
let hostPathMapNextKey = 0

const generateHostForPath = function (path) {
  const key = `extension-${++hostPathMapNextKey}`
  hostPathMap[key] = path
  return key
}

const getPathForHost = function (host) {
  return hostPathMap[host]
}

// Cache manifests.
const manifestMap = {}

const getManifestFromPath = function (srcDirectory) {
  const manifest = JSON.parse(fs.readFileSync(path.join(srcDirectory, 'manifest.json')))
  if (!manifestMap[manifest.name]) {
    const hostname = generateHostForPath(srcDirectory)
    manifestMap[manifest.name] = manifest
    Object.assign(manifest, {
      srcDirectory: srcDirectory,
      hostname: hostname,
      // We can not use 'file://' directly because all resources in the extension
      // will be treated as relative to the root in Chrome.
      startPage: url.format({
        protocol: 'chrome-extension',
        slashes: true,
        hostname: hostname,
        pathname: manifest.devtools_page
      })
    })
    return manifest
  }
}

// Manage the background pages.
const backgroundPages = {}

const startBackgroundPages = function (manifest) {
  if (backgroundPages[manifest.hostname] || !manifest.background) return

  const scripts = manifest.background.scripts.map((name) => {
    return `<script src="${name}"></script>`
  }).join('')
  const html = new Buffer(`<html><body>${scripts}</body></html>`)

  const contents = webContents.create({})
  backgroundPages[manifest.hostname] = { html: html, webContents: contents }
  contents.loadURL(url.format({
    protocol: 'chrome-extension',
    slashes: true,
    hostname: manifest.hostname,
    pathname: '_generated_background_page.html'
  }))
}

const removeBackgroundPages = function (manifest) {
  if (!backgroundPages[manifest.hostname]) return

  backgroundPages[manifest.hostname].webContents.destroy()
  delete backgroundPages[manifest.hostname]
}

// Transfer the content scripts to renderer.
const contentScripts = {}

const injectContentScripts = function (manifest) {
  if (contentScripts[manifest.name] || !manifest.content_scripts) return

  const readArrayOfFiles = function (relativePath) {
    return fs.readFileSync(path.join(manifest.srcDirectory, relativePath))
  }

  const contentScriptToEntry = function (script) {
    return {
      matches: script.matches,
      js: script.js.map(readArrayOfFiles),
      run_at: script.run_at || 'document_idle'
    }
  }

  try {
    const entry = {
      contentScripts: manifest.content_scripts.map(contentScriptToEntry)
    }
    contentScripts[manifest.name] = renderProcessPreferences.addEntry(entry)
  } catch (e) {
    console.error('Failed to read content scripts', e)
  }
}

const removeContentScripts = function (manifest) {
  if (!contentScripts[manifest.name]) return

  renderProcessPreferences.removeEntry(contentScripts[manifest.name])
  delete contentScripts[manifest.name]
}

// Transfer the |manifest| to a format that can be recognized by the
// |DevToolsAPI.addExtensions|.
const manifestToExtensionInfo = function (manifest) {
  return {
    startPage: manifest.startPage,
    srcDirectory: manifest.srcDirectory,
    name: manifest.name,
    exposeExperimentalAPIs: true
  }
}

// Load the extensions for the window.
const loadDevToolsExtensions = function (win, manifests) {
  if (!win.devToolsWebContents) return

  for (const manifest of manifests) {
    startBackgroundPages(manifest)
    injectContentScripts(manifest)
  }
  const extensionInfoArray = manifests.map(manifestToExtensionInfo)
  win.devToolsWebContents.executeJavaScript(`DevToolsAPI.addExtensions(${JSON.stringify(extensionInfoArray)})`)
}

// The persistent path of "DevTools Extensions" preference file.
let loadedExtensionsPath = null

app.on('will-quit', function () {
  try {
    const loadedExtensions = objectValues(manifestMap).map(function (manifest) {
      return manifest.srcDirectory
    })
    if (loadedExtensions.length > 0) {
      try {
        fs.mkdirSync(path.dirname(loadedExtensionsPath))
      } catch (error) {
        // Ignore error
      }
      fs.writeFileSync(loadedExtensionsPath, JSON.stringify(loadedExtensions))
    } else {
      fs.unlinkSync(loadedExtensionsPath)
    }
  } catch (error) {
    // Ignore error
  }
})

// We can not use protocol or BrowserWindow until app is ready.
app.once('ready', function () {
  // Load persisted extensions.
  loadedExtensionsPath = path.join(app.getPath('userData'), 'DevTools Extensions')
  try {
    const loadedExtensions = JSON.parse(fs.readFileSync(loadedExtensionsPath))
    if (Array.isArray(loadedExtensions)) {
      // Preheat the manifest cache.
      for (const srcDirectory of loadedExtensions) {
        getManifestFromPath(srcDirectory)
      }
    }
  } catch (error) {
    // Ignore error
  }

  // The chrome-extension: can map a extension URL request to real file path.
  const chromeExtensionHandler = function (request, callback) {
    const parsed = url.parse(request.url)
    if (!parsed.hostname || !parsed.path) return callback()
    if (!/extension-\d+/.test(parsed.hostname)) return callback()

    const directory = getPathForHost(parsed.hostname)
    if (!directory) return callback()

    if (parsed.path === '/_generated_background_page.html' &&
        backgroundPages[parsed.hostname]) {
      return callback({
        mimeType: 'text/html',
        data: backgroundPages[parsed.hostname].html
      })
    }

    fs.readFile(path.join(directory, parsed.path), function (err, content) {
      if (err) {
        return callback(-6)  // FILE_NOT_FOUND
      } else {
        return callback({mimeType: 'text/html', data: content})
      }
    })
  }
  protocol.registerBufferProtocol('chrome-extension', chromeExtensionHandler, function (error) {
    if (error) {
      console.error(`Unable to register chrome-extension protocol: ${error}`)
    }
  })

  BrowserWindow.addDevToolsExtension = function (srcDirectory) {
    const manifest = getManifestFromPath(srcDirectory)
    if (manifest) {
      for (const win of BrowserWindow.getAllWindows()) {
        loadDevToolsExtensions(win, [manifest])
      }
      return manifest.name
    }
  }
  BrowserWindow.removeDevToolsExtension = function (name) {
    const manifest = manifestMap[name]
    if (!manifest) return

    removeBackgroundPages(manifest)
    removeContentScripts(manifest)
    delete manifestMap[name]
  }

  // Load persisted extensions when devtools is opened.
  const init = BrowserWindow.prototype._init
  BrowserWindow.prototype._init = function () {
    init.call(this)
    this.webContents.on('devtools-opened', () => {
      loadDevToolsExtensions(this, objectValues(manifestMap))
    })
  }
})
<|endoftext|>


<commit_before>/*
 #
 # Copyright (c) 2017 nexB Inc. and others. All rights reserved.
 # http://nexb.com and https://github.com/nexB/scancode-toolkit/
 # The ScanCode software is licensed under the Apache License version 2.0.
 # AboutCode is a trademark of nexB Inc.
 #
 # You may not use this software except in compliance with the License.
 # You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
 # Unless required by applicable law or agreed to in writing, software distributed
 # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 # CONDITIONS OF ANY KIND, either express or implied. See the License for the
 # specific language governing permissions and limitations under the License.
 #
 */

class ComponentDataTable {
    constructor(tableID, aboutCodeDB) {
        this.aboutCodeDB = aboutCodeDB;
        this.dataTable = this._createDataTable(tableID);
        this.dataTable.buttons().container().attr({
            "id": "show-components",
            "data-toggle": "modal",
            "data-placement": "right",
            "title": "Upload Components to DejaCode",
            "data-target": "#componentExportModal"
        });
    }

    database(aboutCodeDB) {
        this.aboutCodeDB = aboutCodeDB;
    }

    reload() {
        this.aboutCodeDB.findAllComponents({})
            .then((components) => {
                this.dataTable.clear();
                this.dataTable.rows.add(components);
                this.dataTable.draw();
            });
    }

    _createDataTable(tableID) {
        return $(tableID).DataTable({
            columns: ComponentDataTable.COLUMNS,
            dom: // Needed to keep datatables buttons and search inline
            "<'row'<'col-sm-9'B><'col-sm-3'f>>" +
            "<'row'<'col-sm-12'tr>>" +
            "<'row'<'col-sm-5'i><'col-sm-7'p>>",
            buttons: [{
                name: "uploadDeja",
                text: ' Upload Components'
            }],
            "language": {
                "emptyTable": "No Components created."
            }
        });
    }

    static get COLUMNS() {
        return [
            {
                data: "review_status",
                title: "Status",
                name: "status"
            },
            {
                data: "path",
                title: "Path",
                name: "path"
            },
            {
                data: "name",
                title: "Name",
                name: "name"
            },
            {
                data: "version",
                title: "Version",
                name: "version"
            },
            {
                data: "owner",
                title: "Owner",
                name: "owner",
                defaultContent: ""
            },
            {
                data: "licenses[
].short_name",
                title: "License",
                name: "license_expression",
                defaultContent: ""
            },
            {
                "data": "copyrights[
].statements[]",
                "title": "Copyright",
                "name": "copyright_statements"
            },
            {
                data: "programming_language",
                title: "Programming Language",
                name: "programming_language",
                defaultContent: ""
            },
            {
                "data": "homepage_url",
                "title": "Homepage URL",
                "name": "homepage_url",
                "defaultContent": "",
                "render": function(href) {
                    if (href) {
                        return `<a href='${href}' target="_blank"> ${href}</a>`
                    }
                    return ""
                }
            },
            {
                data: "notes",
                title: "Notes",
                name: "notes",
                defaultContent: ""
            }
        ];
    }
}

module.exports = ComponentDataTable;
<commit_msg>No-components alert based on DataTable, not DB #40<commit_after>/*
 #
 # Copyright (c) 2017 nexB Inc. and others. All rights reserved.
 # http://nexb.com and https://github.com/nexB/scancode-toolkit/
 # The ScanCode software is licensed under the Apache License version 2.0.
 # AboutCode is a trademark of nexB Inc.
 #
 # You may not use this software except in compliance with the License.
 # You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
 # Unless required by applicable law or agreed to in writing, software distributed
 # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 # CONDITIONS OF ANY KIND, either express or implied. See the License for the
 # specific language governing permissions and limitations under the License.
 #
 */

class ComponentDataTable {
    constructor(tableID, aboutCodeDB) {
        this.aboutCodeDB = aboutCodeDB;
        this.dataTable = this._createDataTable(tableID);
    }

    database(aboutCodeDB) {
        this.aboutCodeDB = aboutCodeDB;
    }

    reload() {
        this.aboutCodeDB.findAllComponents({})
            .then((components) => {
                this.dataTable.clear();
                this.dataTable.rows.add(components);
                this.dataTable.draw();
            });
    }

    _createDataTable(tableID) {
        return $(tableID).DataTable({
            columns: ComponentDataTable.COLUMNS,
            dom: // Needed to keep datatables buttons and search inline
            "<'row'<'col-sm-9'B><'col-sm-3'f>>" +
            "<'row'<'col-sm-12'tr>>" +
            "<'row'<'col-sm-5'i><'col-sm-7'p>>",
            buttons: [{
                name: "uploadDeja",
                text: ' Upload Components',
                action: function ( e, dt, node, config ) {
                    var entryCount = dt.data().count();
                    if (entryCount > 0) {
                        $('#componentExportModal').modal('show');
                    }
                    else {
                        alert("You have no Components to upload.  \n\nPlease create at least one Component and try again.");
                    }
                }
            }],
            "language": {
                "emptyTable": "No Components created."
            }
        });
    }

    static get COLUMNS() {
        return [
            {
                data: "review_status",
                title: "Status",
                name: "status"
            },
            {
                data: "path",
                title: "Path",
                name: "path"
            },
            {
                data: "name",
                title: "Name",
                name: "name"
            },
            {
                data: "version",
                title: "Version",
                name: "version"
            },
            {
                data: "owner",
                title: "Owner",
                name: "owner",
                defaultContent: ""
            },
            {
                data: "licenses[
].short_name",
                title: "License",
                name: "license_expression",
                defaultContent: ""
            },
            {
                "data": "copyrights[
].statements[]",
                "title": "Copyright",
                "name": "copyright_statements"
            },
            {
                data: "programming_language",
                title: "Programming Language",
                name: "programming_language",
                defaultContent: ""
            },
            {
                "data": "homepage_url",
                "title": "Homepage URL",
                "name": "homepage_url",
                "defaultContent": "",
                "render": function(href) {
                    if (href) {
                        return `<a href='${href}' target="_blank"> ${href}</a>`
                    }
                    return ""
                }
            },
            {
                data: "notes",
                title: "Notes",
                name: "notes",
                defaultContent: ""
            }
        ];
    }
}

module.exports = ComponentDataTable;
<|endoftext|>


<commit_before>import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';

import prerelease from 'semver/functions/prerelease';

export default Route.extend({
  flashMessages: service(),

  async model(params) {
    const requestedVersion = params.version_num;
    const crate = this.modelFor('crate');
    const maxVersion = crate.get('max_version');

    let versions = await crate.get('versions');

    const isUnstableVersion = version => !!prerelease(version);

    // Fallback to the crate's last stable version
    // If `max_version` is `0.0.0` then all versions have been yanked
    if (!params.version_num && maxVersion !== '0.0.0') {
      if (isUnstableVersion(maxVersion)) {
        const latestStableVersion = versions.find(version => {
          // Find the latest version that is stable AND not-yanked.
          if (!isUnstableVersion(version.get('num')) && !version.get('yanked')) {
            return version;
          }
        });

        if (latestStableVersion == null) {
          // Cannot find any version that is stable AND not-yanked.
          // The fact that "maxVersion" itself cannot be found means that
          // we have to fall back to the latest one that is unstable....
          const latestUnyankedVersion = versions.find(version => {
            // Find the latest version that is stable AND not-yanked.
            if (!version.get('yanked')) {
              return version;
            }
          });

          if (latestStableVersion == null) {
            // There's not even any unyanked version...
            params.version_num = maxVersion;
          } else {
            params.version_num = latestUnyankedVersion;
          }
        } else {
          params.version_num = latestStableVersion.get('num');
        }
      } else {
        params.version_num = maxVersion;
      }
    }

    const version = versions.find(version => version.get('num') === params.version_num);
    if (params.version_num && !version) {
      this.flashMessages.queue(`Version '${params.version_num}' of crate '${crate.get('name')}' does not exist`);
    }

    return {
      crate,
      requestedVersion,
      version: version || versions.find(version => version.get('num') === maxVersion) || versions.objectAt(0),
    };
  },

  setupController(controller, model) {
    this._super(...arguments);
    controller.loadReadmeTask.perform();

    let { crate } = model;
    if (!crate.documentation || crate.documentation.startsWith('https://docs.rs/')) {
      controller.loadDocsBuilds.perform();
    }
  },

  serialize(model) {
    let version_num = model.get('num');
    return { version_num };
  },
});
<commit_msg>crate.version: Convert `isUnstableVersion()` to top-level function<commit_after>import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';

import prerelease from 'semver/functions/prerelease';

function isUnstableVersion(version) {
  return !!prerelease(version);
}

export default Route.extend({
  flashMessages: service(),

  async model(params) {
    const requestedVersion = params.version_num;
    const crate = this.modelFor('crate');
    const maxVersion = crate.get('max_version');

    let versions = await crate.get('versions');

    // Fallback to the crate's last stable version
    // If `max_version` is `0.0.0` then all versions have been yanked
    if (!params.version_num && maxVersion !== '0.0.0') {
      if (isUnstableVersion(maxVersion)) {
        const latestStableVersion = versions.find(version => {
          // Find the latest version that is stable AND not-yanked.
          if (!isUnstableVersion(version.get('num')) && !version.get('yanked')) {
            return version;
          }
        });

        if (latestStableVersion == null) {
          // Cannot find any version that is stable AND not-yanked.
          // The fact that "maxVersion" itself cannot be found means that
          // we have to fall back to the latest one that is unstable....
          const latestUnyankedVersion = versions.find(version => {
            // Find the latest version that is stable AND not-yanked.
            if (!version.get('yanked')) {
              return version;
            }
          });

          if (latestStableVersion == null) {
            // There's not even any unyanked version...
            params.version_num = maxVersion;
          } else {
            params.version_num = latestUnyankedVersion;
          }
        } else {
          params.version_num = latestStableVersion.get('num');
        }
      } else {
        params.version_num = maxVersion;
      }
    }

    const version = versions.find(version => version.get('num') === params.version_num);
    if (params.version_num && !version) {
      this.flashMessages.queue(`Version '${params.version_num}' of crate '${crate.get('name')}' does not exist`);
    }

    return {
      crate,
      requestedVersion,
      version: version || versions.find(version => version.get('num') === maxVersion) || versions.objectAt(0),
    };
  },

  setupController(controller, model) {
    this._super(...arguments);
    controller.loadReadmeTask.perform();

    let { crate } = model;
    if (!crate.documentation || crate.documentation.startsWith('https://docs.rs/')) {
      controller.loadDocsBuilds.perform();
    }
  },

  serialize(model) {
    let version_num = model.get('num');
    return { version_num };
  },
});
<|endoftext|>


<commit_before>/**
 * BMotionWeb Session Module
 *
 */
define([
  'angular',
  'bms.func',
  'bms.ws',
  'bms.manifest',
  'bms.visualization'
], function(angular, bms) {

  return angular.module('bms.session', ['bms.ws', 'bms.manifest', 'bms.visualization'])
    .factory('bmsSession', ['$q', 'bmsWsService', 'bmsManifestService', 'bmsVisualization',
      function($q, bmsWsService, bmsManifestService, bmsVisualization) {

        var bmsSession = function(sessionId) {
          this.id = sessionId;
          this.manifestFilePath = undefined;
          this.manifestData = {};
          this.initialized = $q.defer();
          this.templateFolder = undefined;
          this.modelPath = undefined;
          this.toolData = {};
          this.views = {};
        };

        bmsSession.prototype.getId = function() {
          return this.id;
        };

        bmsSession.prototype.getModelPath = function() {
          return this.modelPath;
        };

        bmsSession.prototype.getTemplateFolder = function(manifestFilePath) {
          //TODO check if manifestFilePath is undefined
          //var filename = manifestFilePath.replace(/^.*[\\\/]/, '');
          return manifestFilePath.replace('/bmotion.json', '');
          //return folder;
        };

        bmsSession.prototype.getSvgData = function() {
          var self = this;
          var svgData = [];
          angular.forEach(this.views, function(view) {
            for (svg in view.svg) {
              svgData.push({
                file: svg,
                viewId: view.viewData.id,
                id: view.id
              });
            }
          });
          return svgData;
        };

        bmsSession.prototype.init = function(manifestFilePath) {

          var defer = $q.defer();

          var self = this;

          if (!manifestFilePath) {
            defer.reject("Manifest file path must not be undefined.");
          } else {
            bmsManifestService.getManifest(manifestFilePath)
              .then(function(manifestData) {

                var templateFolder = self.getTemplateFolder(manifestFilePath);
                var modelPath = templateFolder + '/' + manifestData.model;
                var groovyPath;

                if(manifestData.groovy) {
                   groovyPath = templateFolder + '/' + manifestData.groovy;
                }

                bmsWsService.initSession(self.id, manifestFilePath, modelPath, groovyPath, manifestData.modelOptions)
                  .then(function(sessionData) {

                    self.tool = sessionData[0].tool;
                    self.toolData = sessionData[1];
                    self.manifestFilePath = manifestFilePath;
                    self.manifestData = manifestData;
                    self.templateFolder = templateFolder;
                    self.modelPath = modelPath;
                    defer.resolve(self);
                    self.initialized.resolve(self);

                  }, function(err) {
                    defer.reject(err);
                  });
              }, function(err) {
                defer.reject(err);
              });
          }

          return defer.promise;

        };

        bmsSession.prototype.load = function() {

          var defer = $q.defer();
          var self = this;
          self.initialized = $q.defer();

          bmsWsService.loadSession(self.id)
            .then(function(sessionData) {

              self.tool = sessionData[0].tool;
              self.toolData = sessionData[1];
              self.manifestFilePath = sessionData[0].manifestFilePath;
              self.templateFolder = self.getTemplateFolder(self.manifestFilePath);

              bmsManifestService.getManifest(self.manifestFilePath)
                .then(function(manifestData) {
                  self.manifestData = manifestData;
                  self.modelPath = self.templateFolder + '/' + self.manifestData.model;
                  defer.resolve(self);
                  self.initialized.resolve(self);
                });

            }, function(err) {
              defer.reject(err);
            });

          return defer.promise;

        };

        bmsSession.prototype.destroy = function() {
          return bmsWsService.destroySession(self.id);
        };

        bmsSession.prototype.isInitialized = function() {
          return this.initialized.promise;
        };

        bmsSession.prototype.isClassicalBVisualization = function() {
          if (!this.tool) {
            return false;
          } else {
            return this.tool === 'ClassicalBVisualization';
          }
        };

        bmsSession.prototype.isEventBVisualization = function() {
          if (!this.tool) {
            return false;
          } else {
            return this.tool === 'EventBVisualization';
          }
        };

        bmsSession.prototype.isBVisualization = function() {
          if (!this.tool) {
            return false;
          } else {
            return this.tool === 'EventBVisualization' || this.tool === 'ClassicalBVisualization';
          }
        };

        bmsSession.prototype.isCSPVisualization = function() {
          if (!this.tool) {
            return false;
          } else {
            return this.tool === 'CSPVisualisation';
          }
        };

        bmsSession.prototype.getView = function(viewId) {
          // If id is undefined create a new one
          viewId = viewId === undefined ? bms.uuid() : viewId;
          if (this.views[viewId] === undefined) {
            this.views[viewId] = new bmsVisualization(viewId, this);
          }
          return this.views[viewId];
        };

        return bmsSession;

      }
    ])
    .factory('bmsSessionService', ['$q', 'bmsSession', 'bmsManifestService', 'bmsWsService',
      function($q, bmsSession, bmsManifestService, bmsWsService) {

        var sessions = {};

        return {
          getSession: function(_sessionId_) {
            sessionId = _sessionId_ ? _sessionId_ : bms.uuid();
            if (sessions[sessionId] === undefined) {
              sessions[sessionId] = new bmsSession(sessionId);
            }
            return sessions[sessionId];
          }
        };

      }
    ]);

});
<commit_msg>update<commit_after>/**
 * BMotionWeb Session Module
 *
 */
define([
  'angular',
  'bms.func',
  'bms.ws',
  'bms.manifest',
  'bms.visualization'
], function(angular, bms) {

  return angular.module('bms.session', ['bms.ws', 'bms.manifest', 'bms.visualization'])
    .factory('bmsSession', ['$q', 'bmsWsService', 'bmsManifestService', 'bmsVisualization',
      function($q, bmsWsService, bmsManifestService, bmsVisualization) {

        var bmsSession = function(sessionId) {
          this.id = sessionId;
          this.manifestFilePath = undefined;
          this.manifestData = {};
          this.initialized = $q.defer();
          this.templateFolder = undefined;
          this.modelPath = undefined;
          this.toolData = {};
          this.views = {};
        };

        bmsSession.prototype.getId = function() {
          return this.id;
        };

        bmsSession.prototype.getModelPath = function() {
          return this.modelPath;
        };

        bmsSession.prototype.getTemplateFolder = function(manifestFilePath) {
          //TODO check if manifestFilePath is undefined
          //var filename = manifestFilePath.replace(/^.*[\\\/]/, '');
          return manifestFilePath.replace('/bmotion.json', '');
          //return folder;
        };

        bmsSession.prototype.getSvgData = function() {
          var self = this;
          var svgData = [];
          angular.forEach(this.views, function(view) {
            for (svg in view.svg) {
              svgData.push({
                file: svg,
                viewId: view.viewData.id,
                id: view.id
              });
            }
          });
          return svgData;
        };

        bmsSession.prototype.init = function(manifestFilePath) {

          var defer = $q.defer();

          var self = this;

          if (!manifestFilePath) {
            defer.reject("Manifest file path must not be undefined.");
          } else {
            bmsManifestService.getManifest(manifestFilePath)
              .then(function(manifestData) {

                self.manifestFilePath = manifestFilePath;
                self.manifestData = manifestData;
                self.templateFolder = self.getTemplateFolder(manifestFilePath);
                self.modelPath = self.templateFolder + '/' + manifestData.model;

                if (manifestData.groovy) {
                  self.groovyPath = self.templateFolder + '/' + manifestData.groovy;
                }

                bmsWsService.initSession(self.id, self.manifestFilePath, self.modelPath, self.groovyPath, manifestData.modelOptions)
                  .then(function(sessionData) {
                    self.tool = sessionData[0].tool;
                    self.toolData = sessionData[1];
                    defer.resolve(self);
                    self.initialized.resolve(self);
                  }, function(err) {
                    defer.reject(err);
                  });
              }, function(err) {
                defer.reject(err);
              });
          }

          return defer.promise;

        };

        bmsSession.prototype.load = function() {

          var defer = $q.defer();
          var self = this;
          self.initialized = $q.defer();

          bmsWsService.loadSession(self.id)
            .then(function(sessionData) {

              self.tool = sessionData[0].tool;
              self.toolData = sessionData[1];
              self.manifestFilePath = sessionData[0].manifestFilePath;
              self.templateFolder = self.getTemplateFolder(self.manifestFilePath);

              bmsManifestService.getManifest(self.manifestFilePath)
                .then(function(manifestData) {
                  self.manifestData = manifestData;
                  self.modelPath = self.templateFolder + '/' + manifestData.model;
                  if (manifestData.groovy) {
                    self.groovyPath = self.templateFolder + '/' + manifestData.groovy;
                  }
                  defer.resolve(self);
                  self.initialized.resolve(self);
                });

            }, function(err) {
              defer.reject(err);
            });

          return defer.promise;

        };

        bmsSession.prototype.destroy = function() {
          return bmsWsService.destroySession(self.id);
        };

        bmsSession.prototype.isInitialized = function() {
          return this.initialized.promise;
        };

        bmsSession.prototype.isClassicalBVisualization = function() {
          if (!this.tool) {
            return false;
          } else {
            return this.tool === 'ClassicalBVisualization';
          }
        };

        bmsSession.prototype.isEventBVisualization = function() {
          if (!this.tool) {
            return false;
          } else {
            return this.tool === 'EventBVisualization';
          }
        };

        bmsSession.prototype.isBVisualization = function() {
          if (!this.tool) {
            return false;
          } else {
            return this.tool === 'EventBVisualization' || this.tool === 'ClassicalBVisualization';
          }
        };

        bmsSession.prototype.isCSPVisualization = function() {
          if (!this.tool) {
            return false;
          } else {
            return this.tool === 'CSPVisualisation';
          }
        };

        bmsSession.prototype.getView = function(viewId) {
          // If id is undefined create a new one
          viewId = viewId === undefined ? bms.uuid() : viewId;
          if (this.views[viewId] === undefined) {
            this.views[viewId] = new bmsVisualization(viewId, this);
          }
          return this.views[viewId];
        };

        return bmsSession;

      }
    ])
    .factory('bmsSessionService', ['$q', 'bmsSession', 'bmsManifestService', 'bmsWsService',
      function($q, bmsSession, bmsManifestService, bmsWsService) {

        var sessions = {};

        return {
          getSession: function(_sessionId_) {
            sessionId = _sessionId_ ? _sessionId_ : bms.uuid();
            if (sessions[sessionId] === undefined) {
              sessions[sessionId] = new bmsSession(sessionId);
            }
            return sessions[sessionId];
          }
        };

      }
    ]);

});
<|endoftext|>


<commit_before>import styled from 'styled-components';
import { Text } from '@buffetjs/core';

const Wrapper = styled.div`
  display: flex;
  align-items: center;
  justify-content: center;
  width: fit-content;
  padding: 1rem;
  border-radius: 0.2rem;
  height: 2.5rem;
  ${({ theme, isGreen }) =>
    isGreen
      ? `
        border: 1px solid #aad67c;
        background-color: #e6f8d4;
        ${Text} {
            color: ${theme.main.colors.green};
        }
    `
      : `
        border: 1px solid #A5D5FF;
        background-color: ${({ theme }) => theme.main.colors.lightestBlue};
        ${Text} {
            color: ${theme.main.colors.mediumBlue};
        }
    `};
`;

export default Wrapper;
<commit_msg>fix background color<commit_after>import styled from 'styled-components';
import { Text } from '@buffetjs/core';

const Wrapper = styled.div`
  display: flex;
  align-items: center;
  justify-content: center;
  width: fit-content;
  padding: 1rem;
  border-radius: 0.2rem;
  height: 2.5rem;
  ${({ theme, isGreen }) =>
    isGreen
      ? `
        border: 1px solid #aad67c;
        background-color: #e6f8d4;
        ${Text} {
            color: ${theme.main.colors.green};
        }
    `
      : `
        border: 1px solid #A5D5FF;
        background-color: ${theme.main.colors.lightestBlue};
        ${Text} {
            color: ${theme.main.colors.mediumBlue};
        }
    `};
`;

export default Wrapper;
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';

// https://facebook.github.io/react/docs/lifting-state-up.html
// https://facebook.github.io/react/docs/lifting-state-up.html#lifting-state-up

class Book extends Component {
  static propTypes = {
    id: PropTypes.string.isRequired,
    title: PropTypes.string.isRequired,
    authors: PropTypes.array,
    image: PropTypes.string,
    shelf: PropTypes.string,
    setBookShelf: PropTypes.func.isRequired
  }

  state = {
    bookshelf: ""
  }

  setBookShelf = (event) => {
    this.props.setBookShelf(this.props.id, event.target.value);
  }

  render() {
    const { title, authors, image, shelf } = this.props;

    var bookShelf = shelf;

    if(bookShelf === undefined) {
      bookShelf = "none";
    }

    return (

            {shelf}
            <select value={bookShelf} onChange={this.setBookShelf}>
              <option value="none" disabled>Move to...</option>
              <option value="currentlyReading">Currently Reading</option>
              <option value="wantToRead">Want to Read</option>
              <option value="read">Read</option>
              <option value="none">None</option>
            </select>

{title}

{(Array.isArray(authors)) && authors.map((author, idx) =>
{author}
)}

    );
  }
}

export default Book<commit_msg>Book > old state bookshelf cleaned out. shelf print on render() clened out<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';

// https://facebook.github.io/react/docs/lifting-state-up.html
// https://facebook.github.io/react/docs/lifting-state-up.html#lifting-state-up

class Book extends Component {
  static propTypes = {
    id: PropTypes.string.isRequired,
    title: PropTypes.string.isRequired,
    authors: PropTypes.array,
    image: PropTypes.string,
    shelf: PropTypes.string,
    setBookShelf: PropTypes.func.isRequired
  }

  setBookShelf = (event) => {
    this.props.setBookShelf(this.props.id, event.target.value);
  }

  render() {
    const { title, authors, image, shelf } = this.props;

    var bookShelf = shelf;

    if(bookShelf === undefined) {
      bookShelf = "none";
    }

    return (

            <select value={bookShelf} onChange={this.setBookShelf}>
              <option value="none" disabled>Move to...</option>
              <option value="currentlyReading">Currently Reading</option>
              <option value="wantToRead">Want to Read</option>
              <option value="read">Read</option>
              <option value="none">None</option>
            </select>

{title}

{(Array.isArray(authors)) && authors.map((author, idx) =>
{author}
)}

    );
  }
}

export default Book<|endoftext|>


<commit_before><commit_msg>cleanup<commit_after><|endoftext|>


<commit_before>var cVocab = {
	connection: null,
	start_time: null,

	log: function (msg) {
        $('#log').append("
" + msg + "
");
	},

	send_ping: function (to) {
        var ping = $iq({
            to: to,
            type: "get",
            id: "ping1"}).c("ping", {xmlns: "urn:xmpp:ping"});

        cVocab.log("Sending ping to " + to + ".");

        cVocab.start_time = (new Date()).getTime();
        cVocab.connection.send(ping);
    },

    handle_pong: function (iq) {
        var elapsed = (new Date()).getTime() - cVocab.start_time;
        cVocab.log("Received pong from server in " + elapsed + "ms.");

        cVocab.connection.disconnect();

        return false;
    }
}; // class

$(document).bind('connected', function () {
	cVocab.log("Connection established.");
    cVocab.connection.addHandler(cVocab.handle_pong, null, "iq", null, "ping1");
    var domain = Strophe.getDomainFromJid(cVocab.connection.jid);
    cVocab.send_ping(domain);
});

$(document).bind('disconnected', function () {
	cVocab.log("Connection terminated.");
    cVocab.connection = null;
});

$(document).ready(function() {

	$('#loginform').submit(function(event) {
		var sJid = $('#lname').val() + "@vocab.guru";
		var sPwd = $('#pwd').val();

		event.preventDefault();
		var conn = new Strophe.Connection("https://xmpp.vocab.guru:5282/http-bind");
		conn.connect(sJid, sPwd, function (status) {
			if (status === Strophe.Status.CONNECTED) {
				$(document).trigger('connected');
			} else if (status === Strophe.Status.DISCONNECTED) {
				$(document).trigger('disconnected');
			} // if
		});

	    cVocab.connection = conn;
	});

	$('#name').on('keyup', function(e){
		var sTmp = $(this).val();
		if(sTmp.length < 3) {
			$('#nameStatus').html('');
			return;
		} // if

		$('#nameStatus').html('');
		$.ajax({
				method: "GET",
				url: '/u/unique',
				data: { search: sTmp },
				timeout: 500,
				cache: false,
				success: function(data) {
					if("OK" == data) {
						$('#nameStatus').html('');
					} else {
						$('#nameStatus').html('');
					}
				}, // function success
				error: function(jqXHR, textStatus, errorThrown) {
					$('#nameStatus').html('?');
					if('timeout' != textStatus) {
						alert('error '+textStatus+errorThrown);
					} // if
				} // function error
		}); // ajax
	}); // function keyout

});<commit_msg>rid sid params<commit_after>var cVocab = {
	connection: null,
	start_time: null,
	rid: null,
	sid: null,

	log: function (msg) {
        $('#log').append("
" + msg + "
");
	},

	send_ping: function (to) {
        var ping = $iq({
            to: to,
            type: "get",
            id: "ping1"}).c("ping", {xmlns: "urn:xmpp:ping"});

        cVocab.log("Sending ping to " + to + ".");

        cVocab.start_time = (new Date()).getTime();
        cVocab.connection.send(ping);
    },

    handle_pong: function (iq) {
        var elapsed = (new Date()).getTime() - cVocab.start_time;
        cVocab.log("Received pong from server in " + elapsed + "ms.");

        cVocab.connection.disconnect();

        return false;
    }
}; // class

$(document).bind('connected', function () {
	cVocab.log("Connection established.");
    cVocab.connection.addHandler(cVocab.handle_pong, null, "iq", null, "ping1");
    var domain = Strophe.getDomainFromJid(cVocab.connection.jid);
    cVocab.send_ping(domain);
});

$(document).bind('disconnected', function () {
	cVocab.log("Connection terminated.");
    cVocab.connection = null;
});

$(document).ready(function() {

	$('#loginform').submit(function(event) {
		var sJid = $('#lname').val() + "@vocab.guru";
		var sPwd = $('#pwd').val();

		event.preventDefault();
		var conn = new Strophe.Connection("https://xmpp.vocab.guru:5282/http-bind");
		conn.xmlOutput = function(e) {
//			if(IS_CONNECTED) {
				cVocab.rid = $(e).attr('rid');
				cVocab.sid = $(e).attr('sid');
				cVocab.log("rid=" + cVocab.rid + ", sid=" + cVocab.sid);
//			} // if
		};
		conn.connect(sJid, sPwd, function (status) {
			if (status === Strophe.Status.CONNECTED) {
				$(document).trigger('connected');
			} else if (status === Strophe.Status.DISCONNECTED) {
				$(document).trigger('disconnected');
			} // if
		});

	    cVocab.connection = conn;
	});

	$('#name').on('keyup', function(e){
		var sTmp = $(this).val();
		if(sTmp.length < 3) {
			$('#nameStatus').html('');
			return;
		} // if

		$('#nameStatus').html('');
		$.ajax({
				method: "GET",
				url: '/u/unique',
				data: { search: sTmp },
				timeout: 500,
				cache: false,
				success: function(data) {
					if("OK" == data) {
						$('#nameStatus').html('');
					} else {
						$('#nameStatus').html('');
					}
				}, // function success
				error: function(jqXHR, textStatus, errorThrown) {
					$('#nameStatus').html('?');
					if('timeout' != textStatus) {
						alert('error '+textStatus+errorThrown);
					} // if
				} // function error
		}); // ajax
	}); // function keyout

});<|endoftext|>


<commit_before>/**
* @fileoverview 获取公共模块map.json文件
* @author  liweitao
*/

'use strict';

// 获取管理平台上存储的公共模块的map.json并保存到本地
module.exports = function($, appConf, moduleConf, args) {
  return function(mod, modulePath, appPath) {
    return new Promise(function (resolve, reject) {
      var path = require('path');
      var fs = require('fs');
      var request = require('request');
      var mkdirp = require('mkdirp');
      var _ = require('lodash');

      var Util = require('../../util');
      var reportUrl = Util.getSetting().report_url;
      var getCommonVersionUrl = reportUrl + '/api/gb/version';
      var getCommonJsonUrl = reportUrl + '/api/gb';

      var isDebug = args.debug ? true : false;
      var cacheFolder = path.join(Util.getAthenaPath(), 'cache');
      var commonCacheFolder = path.join(cacheFolder, 'common');
      var commonVersionJsonFile = path.join(commonCacheFolder, 'common.json');
      var app = appConf.app;
      var appId = appConf.appId;
      var commonModule = appConf.common;
      var catchMapJsonGbFile = path.join(commonCacheFolder, app + '_gb.json');

      if (!Util.existsSync(commonCacheFolder)) {
        mkdirp.sync(commonCacheFolder);
      }

      function getCommonJson (cb) {
        request.get(getCommonJsonUrl, {
          qs: {
            app: appId
          }
        }, function (err, res, body) {
          if (err) {
            if (isDebug) {
              console.log(err);
            }
            cb(false);
            return;
          }
          if (res.statusCode === 200 || res.statusCode === 201) {
            try {
              body = JSON.parse(body);
              if (body.no === 0) {
                var data = body.data;
                if (_.isEmpty(body.data)) {
                  cb(false);
                  return;
                }
                fs.writeFileSync(path.join(commonCacheFolder, app + '_' + commonModule + '.json'), JSON.stringify(data, null, 2));
                cb(true);
              } else {
                if (isDebug) {
                  console.log(body);
                }
                cb(false);
              }
            } catch (e) {
              if (isDebug) {
                console.log(e);
              }
              cb(false);
            }
          } else {
            if (isDebug) {
              console.log(res.statusCode);
              console.log(res);
            }
            cb(false);
          }
        });
      }

      function getCommonVersion (cb) {
        request.get(getCommonVersionUrl, {
          qs: {
            app: appId
          }
        }, function (err, res, body) {
          if (err) {
            if (isDebug) {
              console.log(err);
            }
            cb(false);
            return;
          }
          if (res.statusCode === 200 || res.statusCode === 201) {
            try {
              body = JSON.parse(body);
              if (body.no === 0) {
                var version = body.data.v;
                if (version === null) { // 未提交过common
                  cb('first');
                  return;
                }
                var commonVersionJson = {};
                if (Util.existsSync(commonVersionJsonFile)) {
                  try {
                    commonVersionJson = JSON.parse(fs.readFileSync(commonVersionJsonFile).toString());
                  } catch (e) {
                    commonVersionJson = {};
                  }
                }
                // 若没有保存版本的md5或者md5和服务端不一致，则重新请求一下新的map.json
                if (commonVersionJson[app + '_' + commonModule] === undefined
                  || commonVersionJson[app + '_' + commonModule] !== version
                  || !Util.existsSync(path.join(commonCacheFolder, app + '_' + commonModule + '.json'))) {
                  getCommonJson(function (success) {
                    if (success) {
                      $.util.log($.util.colors.yellow('注意: 本地' + commonModule + '的map.json文件与线上不一致, 将使用线上版本'));
                      commonVersionJson[app + '_' + commonModule] = version;
                      fs.writeFileSync(commonVersionJsonFile, JSON.stringify(commonVersionJson, null, 2));
                    } else {
                      $.util.log($.util.colors.red('请求' + commonModule + '的map.json出错，请反馈给liweitao'));
                    }
                    cb(true);
                  });
                } else {
                  try{
                    //版本一致，再进行项目内map.json与(线上/catch)的map.json 文件内容对比
                    var catchMapMd5Hash = Util.checksum(JSON.stringify(JSON.parse(fs.readFileSync(catchMapJsonGbFile)).rev), 16);
                    var localMapMd5Hash = Util.checksum(JSON.stringify(JSON.parse(fs.readFileSync(path.join(modulePath, 'dist', 'map.json'))).rev), 16);
                    if(catchMapMd5Hash !== localMapMd5Hash){
                      $.util.log($.util.colors.yellow('注意: 本地' + commonModule + '的map.json文件与线上不一致, 将使用线上版本'));
                    }
                  }catch(e){
                    if (isDebug) {
                      console.log(e);
                    }
                  }
                  cb(true);
                }
              } else {
                if (isDebug) {
                  console.log(body);
                }
                cb(false);
              }
            } catch (e) {
              if (isDebug) {
                console.log(e);
              }
              cb(false);
            }
          } else {
            if (isDebug) {
              console.log(res.statusCode);
              console.log(res);
            }
            cb(false);
          }
        });
      }
      // 首先请求一下服务器端版本号
      getCommonVersion(function (success) {
        if (!success) {
          $.util.log($.util.colors.red('请求' + commonModule + '的版本号出错，请反馈给liweitao'));
        }
        resolve();
      });
    });
  }
}
<commit_msg>update: 将对比方法抽离<commit_after>/**
* @fileoverview 获取公共模块map.json文件
* @author  liweitao
*/

'use strict';

// 获取管理平台上存储的公共模块的map.json并保存到本地
module.exports = function($, appConf, moduleConf, args) {
  return function(mod, modulePath, appPath) {
    return new Promise(function (resolve, reject) {
      var path = require('path');
      var fs = require('fs');
      var request = require('request');
      var mkdirp = require('mkdirp');
      var _ = require('lodash');

      var Util = require('../../util');
      var reportUrl = Util.getSetting().report_url;
      var getCommonVersionUrl = reportUrl + '/api/gb/version';
      var getCommonJsonUrl = reportUrl + '/api/gb';

      var isDebug = args.debug ? true : false;
      var cacheFolder = path.join(Util.getAthenaPath(), 'cache');
      var commonCacheFolder = path.join(cacheFolder, 'common');
      var commonVersionJsonFile = path.join(commonCacheFolder, 'common.json');
      var app = appConf.app;
      var appId = appConf.appId;
      var commonModule = appConf.common;
      var catchMapJsonGbFile = path.join(commonCacheFolder, app + '_gb.json');

      if (!Util.existsSync(commonCacheFolder)) {
        mkdirp.sync(commonCacheFolder);
      }

      function getCommonJson (cb) {
        request.get(getCommonJsonUrl, {
          qs: {
            app: appId
          }
        }, function (err, res, body) {
          if (err) {
            if (isDebug) {
              console.log(err);
            }
            cb(false);
            return;
          }
          if (res.statusCode === 200 || res.statusCode === 201) {
            try {
              body = JSON.parse(body);
              if (body.no === 0) {
                var data = body.data;
                if (_.isEmpty(body.data)) {
                  cb(false);
                  return;
                }
                fs.writeFileSync(path.join(commonCacheFolder, app + '_' + commonModule + '.json'), JSON.stringify(data, null, 2));
                cb(true);
              } else {
                if (isDebug) {
                  console.log(body);
                }
                cb(false);
              }
            } catch (e) {
              if (isDebug) {
                console.log(e);
              }
              cb(false);
            }
          } else {
            if (isDebug) {
              console.log(res.statusCode);
              console.log(res);
            }
            cb(false);
          }
        });
      }

      function getCommonVersion (cb) {
        request.get(getCommonVersionUrl, {
          qs: {
            app: appId
          }
        }, function (err, res, body) {
          if (err) {
            if (isDebug) {
              console.log(err);
            }
            cb(false);
            return;
          }
          if (res.statusCode === 200 || res.statusCode === 201) {
            try {
              body = JSON.parse(body);
              if (body.no === 0) {
                var version = body.data.v;
                if (version === null) { // 未提交过common
                  cb('first');
                  return;
                }
                var commonVersionJson = {};
                if (Util.existsSync(commonVersionJsonFile)) {
                  try {
                    commonVersionJson = JSON.parse(fs.readFileSync(commonVersionJsonFile).toString());
                  } catch (e) {
                    commonVersionJson = {};
                  }
                }
                // 若没有保存版本的md5或者md5和服务端不一致，则重新请求一下新的map.json
                if (commonVersionJson[app + '_' + commonModule] === undefined
                  || commonVersionJson[app + '_' + commonModule] !== version
                  || !Util.existsSync(path.join(commonCacheFolder, app + '_' + commonModule + '.json'))) {
                  getCommonJson(function (success) {
                    if (success) {
                      compareFileContent();
                      commonVersionJson[app + '_' + commonModule] = version;
                      fs.writeFileSync(commonVersionJsonFile, JSON.stringify(commonVersionJson, null, 2));
                    } else {
                      $.util.log($.util.colors.red('请求' + commonModule + '的map.json出错，请反馈给liweitao'));
                    }
                    cb(true);
                  });
                } else {
                  compareFileContent();
                  cb(true);
                }
              } else {
                if (isDebug) {
                  console.log(body);
                }
                cb(false);
              }
            } catch (e) {
              if (isDebug) {
                console.log(e);
              }
              cb(false);
            }
          } else {
            if (isDebug) {
              console.log(res.statusCode);
              console.log(res);
            }
            cb(false);
          }
        });
      }
      var compareFileContent = function(){
        //版本一致，再进行项目内map.json与(线上/catch)的map.json 文件内容对比
        var catchMapMd5Hash = Util.checksum(JSON.stringify(Util.readJsonFile(catchMapJsonGbFile).rev), 16);
        var localMapMd5Hash = Util.checksum(JSON.stringify(Util.readJsonFile(path.join(modulePath, 'dist', 'map.json')).rev), 16);
        if(catchMapMd5Hash !== localMapMd5Hash){
          $.util.log($.util.colors.yellow('注意: 本地' + commonModule + '的map.json文件与线上不一致, 将使用线上版本'));
        }
      }
      // 首先请求一下服务器端版本号
      getCommonVersion(function (success) {
        if (!success) {
          $.util.log($.util.colors.red('请求' + commonModule + '的版本号出错，请反馈给liweitao'));
        }
        resolve();
      });
    });
  }
}
<|endoftext|>


<commit_before>import React from 'react'

import Select from 'react-select-plus';
import 'react-select-plus/dist/react-select-plus.css';

import ProjectRadioGroups from './ProjectRadioGroups'

class ProjectSelector extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
         options: this.createOptionsList()
    }
  }

  createOptionsList() {
    // Group project after client id
    var groupedProjects = [];
    var that = this;
    this.props.projects.forEach(function(project){
        if(project.cid != undefined)
        {
          if(groupedProjects[project.cid] == null)
            groupedProjects[project.cid] = [];

          groupedProjects[project.cid].push({label: project.name, value: project.id, color: project.hex_color, client: that.getClient(project.cid).name});
        }
    });

    // Create array with client names and its projects
    var options = [];
    Object.keys(groupedProjects).forEach(function(key) {
      var values = groupedProjects[key];
      options.push({label: that.getClient(key).name, options: values})
    });

    return options;
  }

  getClient(id) {
        let retVal = null;
        this.props.clients.forEach(function(client) {
            if(client.id == id)
            {
                retVal = client;
                return;
            }
        });
        return retVal;
  }

  render() {
    return (

          <Select
            style={{zIndex: 999}}
            autofocus={true}
            name="form-field-name"
            value={this.state.value}
            options={this.state.options}
            clearable={false}
            onChange={(project) => this.projectRadioGroups.addToProjectList(project)}
          />
          <ProjectRadioGroups
            selectedProject={this.props.selectedProject}
            onChange={(project) => this.props.onChange(project)}
          />

      )
  }
}

ProjectSelector.propTypes = {
  clients: React.PropTypes.array.isRequired,
  projects: React.PropTypes.array.isRequired,
  onChange: React.PropTypes.func.isRequired,
  selectedProject: React.PropTypes.number
};

export default ProjectSelector<commit_msg>:ambulance: Fix ref to projectRadioGroups<commit_after>import React from 'react'

import Select from 'react-select-plus';
import 'react-select-plus/dist/react-select-plus.css';

import ProjectRadioGroups from './ProjectRadioGroups'

class ProjectSelector extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
         options: this.createOptionsList()
    }
  }

  createOptionsList() {
    // Group project after client id
    var groupedProjects = [];
    var that = this;
    this.props.projects.forEach(function(project){
        if(project.cid != undefined)
        {
          if(groupedProjects[project.cid] == null)
            groupedProjects[project.cid] = [];

          groupedProjects[project.cid].push({label: project.name, value: project.id, color: project.hex_color, client: that.getClient(project.cid).name});
        }
    });

    // Create array with client names and its projects
    var options = [];
    Object.keys(groupedProjects).forEach(function(key) {
      var values = groupedProjects[key];
      options.push({label: that.getClient(key).name, options: values})
    });

    return options;
  }

  getClient(id) {
        let retVal = null;
        this.props.clients.forEach(function(client) {
            if(client.id == id)
            {
                retVal = client;
                return;
            }
        });
        return retVal;
  }

  render() {
    return (

          <Select
            style={{zIndex: 999}}
            autofocus={true}
            name="form-field-name"
            value={this.state.value}
            options={this.state.options}
            clearable={false}
            onChange={(project) => this.projectRadioGroups.addToProjectList(project)}
          />
          <ProjectRadioGroups
            ref={(ref) => this.projectRadioGroups = ref}
            selectedProject={this.props.selectedProject}
            onChange={(project) => this.props.onChange(project)}
          />

      )
  }
}

ProjectSelector.propTypes = {
  clients: React.PropTypes.array.isRequired,
  projects: React.PropTypes.array.isRequired,
  onChange: React.PropTypes.func.isRequired,
  selectedProject: React.PropTypes.number
};

export default ProjectSelector<|endoftext|>


<commit_before>const async = require('async'),
  log = require('../../helpers/logger'),
  Game = require('../../models/game'),
  User = require('../../models/user');

/**
 * Abstraction to handle the page errors
 * @param  {String|Array} errors Single or collection of errors
 */
function handleError(req, res, errors)
{
	log.error(errors);
	if (Array.isArray(errors))
	{
		req.flash('errors', errors);
	}
	else
	{
		req.flash('error', 'Unable to update the game: ' + errors);
	}
	res.redirect(req.originalUrl);
}

function validateRequest(req){
  req.checkBody('title', 'Title is required').notEmpty();
	req.checkBody('bundleId', 'Bundle ID is required').isBundleId();
	req.checkBody('slug', 'Slug is required').isSlug();
	req.checkBody('repository', 'Repository needs to be a URL').isURL();
	req.checkBody('location', 'Location needs to be a URL').isURL();
	req.checkBody('description').optional();
  req.checkBody('thumbnail').optional();
  var errors = req.validationErrors();
	return errors ? errors : false;
}

/**
 * Abstraction to render a page, takes care of all
 * of the access control and populate the page with
 * standard parameters
 * @param  {Object} req The express request object
 * @param {Object} res The express response object
 * @param {string} template The template to use
 * @param {String} [populate='groups.group'] The game fields to populate
 * @param {function} [success] Callback when completed
 */
function renderPage(req, res, template, populate=null)
{
	async.waterfall(
		[
			function(done)
			{
        var game = Game.getBySlug(req.params.slug, done);
        if (populate){
          game.populate(populate);
				};
      },
			function(game, done)
			{
				if (!game){
					return res.status(404).render('404');
				}

				game.getAccess(req.user, done);
			}
		],
		function(err, game, access)
		{
			if (err)
			{
				return res.status(401).render('401');
			}
			res.render(template, {
			game: game,
			capabilities: game.capabilities,
			host: req.headers.host,
			isEditor: access.permission > 0,
			isAdmin: access.permission > 1,
			token: access.token,
			errors: req.flash('errors'),
			success: req.flash('success'),
			error: req.flash('error')
			});
		}
	);
}

/**
 * Abstraction to post a page, takes care of all
 * of the access control and populate the page with
 * standard parameters.
 * @param  {Object} req The express request object
 * @param {Object} res The express response object
 * @param {string} minPrivilege The minimum privilege needed to run all form
 * @param {Object} actions Run custom page actions
 */
function postPage(req, res, minPrivilege, actions)
{
	async.waterfall(
		[
			function(done)
			{
				Game.getBySlug(req.params.slug, done).populate('groups.group');
			},
			function(game, done)
			{
				if (!game) {
					return res.status(404).render('404');
				}

				game.getAccess(req.user, done);
			},
			function(game, access, done)
			{
				var response = function(err)
				{
					if (err) {
						return done(err);
					}
					done(null, game);
				};

				if (access.permission < minPrivilege)
				{
					return done('Invalid form permissions');
				}

				if (!req.body.action || !actions[req.body.action])
				{
					done('Invalid form action');
				}
				actions[req.body.action](response, game, access);
			}
		],
		function(err, game)
		{
			if (err) {
				return handleError(req, res, err);
			}

			req.flash('success', game.title + " updated successfully");
			res.redirect(req.body.slug ? req.baseUrl + `/${req.body.slug}` : req.originalUrl);
		}
	);
}

function defaultCapabilities(capabilities)
{
	capabilities.ui = Object.assign({
		mouse: false,
		touch: false
	}, capabilities.ui);

	capabilities.sizes = Object.assign({
			xsmall: false,
			small: false,
			medium: false,
			large: false,
			xlarge: false
		}, capabilities.sizes);
}

module.exports = {renderPage, postPage, defaultCapabilities, validateRequest, handleError};<commit_msg>add return for Chip<commit_after>const async = require('async'),
  log = require('../../helpers/logger'),
  Game = require('../../models/game'),
  User = require('../../models/user');

/**
 * Abstraction to handle the page errors
 * @param  {String|Array} errors Single or collection of errors
 */
function handleError(req, res, errors)
{
	log.error(errors);
	if (Array.isArray(errors))
	{
		req.flash('errors', errors);
	}
	else
	{
		req.flash('error', 'Unable to update the game: ' + errors);
	}
	res.redirect(req.originalUrl);
}

function validateRequest(req){
  req.checkBody('title', 'Title is required').notEmpty();
	req.checkBody('bundleId', 'Bundle ID is required').isBundleId();
	req.checkBody('slug', 'Slug is required').isSlug();
	req.checkBody('repository', 'Repository needs to be a URL').isURL();
	req.checkBody('location', 'Location needs to be a URL').isURL();
	req.checkBody('description').optional();
  req.checkBody('thumbnail').optional();
  var errors = req.validationErrors();
	return errors ? errors : false;
}

/**
 * Abstraction to render a page, takes care of all
 * of the access control and populate the page with
 * standard parameters
 * @param  {Object} req The express request object
 * @param {Object} res The express response object
 * @param {string} template The template to use
 * @param {String} [populate='groups.group'] The game fields to populate
 * @param {function} [success] Callback when completed
 */
function renderPage(req, res, template, populate=null)
{
	async.waterfall(
		[
			function(done)
			{
        var game = Game.getBySlug(req.params.slug, done);
        if (populate){
          game.populate(populate);
				};
      },
			function(game, done)
			{
				if (!game){
					return res.status(404).render('404');
				}

				game.getAccess(req.user, done);
			}
		],
		function(err, game, access)
		{
			if (err)
			{
				return res.status(401).render('401');
			}
			res.render(template, {
			game: game,
			capabilities: game.capabilities,
			host: req.headers.host,
			isEditor: access.permission > 0,
			isAdmin: access.permission > 1,
			token: access.token,
			errors: req.flash('errors'),
			success: req.flash('success'),
			error: req.flash('error')
			});
		}
	);
}

/**
 * Abstraction to post a page, takes care of all
 * of the access control and populate the page with
 * standard parameters.
 * @param  {Object} req The express request object
 * @param {Object} res The express response object
 * @param {string} minPrivilege The minimum privilege needed to run all form
 * @param {Object} actions Run custom page actions
 */
function postPage(req, res, minPrivilege, actions)
{
	async.waterfall(
		[
			function(done)
			{
				Game.getBySlug(req.params.slug, done).populate('groups.group');
			},
			function(game, done)
			{
				if (!game) {
					return res.status(404).render('404');
				}

				game.getAccess(req.user, done);
			},
			function(game, access, done)
			{
				var response = function(err)
				{
					if (err) {
						return done(err);
					}
					done(null, game);
					return;
				};

				if (access.permission < minPrivilege)
				{
					return done('Invalid form permissions');
				}

				if (!req.body.action || !actions[req.body.action])
				{
					done('Invalid form action');
				}
				actions[req.body.action](response, game, access);
			}
		],
		function(err, game)
		{
			if (err) {
				return handleError(req, res, err);
			}

			req.flash('success', game.title + " updated successfully");
			res.redirect(req.body.slug ? req.baseUrl + `/${req.body.slug}` : req.originalUrl);
		}
	);
}

function defaultCapabilities(capabilities)
{
	capabilities.ui = Object.assign({
		mouse: false,
		touch: false
	}, capabilities.ui);

	capabilities.sizes = Object.assign({
			xsmall: false,
			small: false,
			medium: false,
			large: false,
			xlarge: false
		}, capabilities.sizes);
}

module.exports = {renderPage, postPage, defaultCapabilities, validateRequest, handleError};<|endoftext|>


<commit_before>(function() {
    klp.utils = {
        compile_templates: function() {
            var $raw_tpls = $(".tpl-raw");
            var _tpl = {};
            if(!$raw_tpls.length){
                return _tpl;
            }
            $raw_tpls.each(function( index ) {
                var name = $(this).data("tpl");
                var content = $(this).html();

                _tpl[name] = swig.compile(content);
            });
            return _tpl;
        },

        mapIcon: function (type) {

            // FIXME: May be fix this in the icon name.
            // This is Sanjay's fault.
            type = type.replace(' ', '').toLowerCase();
            if (type === 'primaryschool') {
                type = 'school';
            }
            if (type === 'primaryschool_district') {
                type = 'school_district';
            }
            if (type === 'primaryschool_block') {
                type = 'school_block';
            }
            if (type === 'primaryschool_cluster') {
                type = 'school_cluster';
            }
            return L.icon({
                iconUrl: '/static/images/map/icon_'+type+'.png',
                iconSize: [20, 30],
                iconAnchor: [10, 26],
                popupAnchor: [0, -25]
            });
        },

        alertMessage: function(message, status) {
            // Status - error, success, warning.
            var $alert = $('<div />')
                            .addClass('alert')
                            .hide()
                            .text(message)
                            .appendTo('body')
                            .slideDown(250);

            if (status) {
                $alert.addClass(status);
            }
            setTimeout(function() {
                $alert.slideUp(500, function() {
                    $alert.remove();
                });
            }, 3000);
            //alert(message);
        },

        getRelativeHeight: function (width, height, min_height, container_width){
            var ht = (height/width)*container_width;
            ht = parseInt(ht,10);
            if(ht<min_height){
                return min_height;
            }
            // If number is odd, convert to even
            if(Math.abs(ht) % 2 == 1){
                ht++;
            }
            return ht;
        },

        getMTProfilePercents: function(mt_profile) {
            if (!mt_profile || _.isEmpty(mt_profile)) {
                return {
                    total: 0,
                    percents: {}
                };
            }
            var total_mts = _(_(mt_profile).values()).reduce(function(a, b) {
                return a + b;
            });
            mt_profile_percents = {};
            _(_(mt_profile).keys()).each(function(mt) {
                mt_profile_percents[mt] = ((mt_profile[mt] / total_mts) * 100).toFixed(2);
            });
            return {
                total: total_mts,
                percents: mt_profile_percents
            };
        },

        getStudentTeacherRatio: function(data) {
            var numBoys = data.num_boys_dise || 0;
            var numGirls = data.num_girls_dise || 0;
            var totalStudents = numBoys + numGirls;
            var numTeachers = data.teacher_count || null;
            if (numTeachers) {
                return parseInt(totalStudents / numTeachers);
            } else {
                return false;
            }
        },

        getBoyGirlPercents: function(num_boys, num_girls) {
            var total_students = num_boys + num_girls;
            var percent_boys = Math.round((num_boys / total_students) * 100);
            var percent_girls = Math.round((num_girls / total_students) * 100);
            return {
                total_students: total_students,
                percent_boys: percent_boys,
                percent_girls: percent_girls
            };
        },

        getFinancePercents: function(financeData) {
            var sgAmount = financeData.sg_amount ? financeData.sg_amount : 0;
            var smgAmount = financeData.smg_amount ? financeData.smg_amount : 0;
            var tlmAmount = financeData.tlm_amount ? financeData.tlm_amount : 0;
            var total = sgAmount + smgAmount + tlmAmount;
            return {
                'sg': ((sgAmount / total) * 100).toFixed(2),
                'smg': ((smgAmount / total) * 100).toFixed(2),
                'tlm': ((tlmAmount / total) * 100).toFixed(2)
            }
        },

        addSchoolContext: function(data) {
            data.has_num_students = data.num_boys && data.num_girls;
            data = $.extend(data, klp.utils.getBoyGirlPercents(data.num_boys, data.num_girls));
            if (data.hasOwnProperty('mt_profile')) {
                data.mt_profile_percents = klp.utils.getMTProfilePercents(data.mt_profile).percents;
            }
            return data;
        },

        populateForm: function(fields, data) {
            _(_(fields).keys()).each(function(key) {
                var $field = fields[key];
                if ($field.is('[data-type=image]')) {
                    if (data[key]) {
                        var $imagePreview = $field.parent().find('.js-image-preview');

                        //FIXME: avoid hard-coding "/media/", get from settings or so
                        var imageSrc = "/media/" + data[key];
                        $imagePreview.attr("src", imageSrc);
                    }
                } else {
                    $field.val(data[key]);
                }
            });
        },

        getFormData: function(fields) {
            var data = {};
            _(_(fields).keys()).each(function(key) {
                var $field = fields[key];
                if ($field.attr('type') === 'checkbox') {
                    data[key] = $field.is(":checked");
                } else if ($field.is('[data-type=image]')) {
                    var imageData = $field.parent().find('.js-image-preview').attr('src');
                    if (imageData) {
                        //remove first part of b64data
                        var fileData = imageData.split(",")[1];
                        data[key] = fileData;
                    } else {
                        data[key] = ''; //FIXME: UGLY!!
                    }
                } else {
                    data[key] = fields[key].val();
                }
            });
            return data;
        },

        invalidateField: function($field, message) {
            $field.addClass('error');
            var $error = $('<div />').addClass('js-error-message error-message');
            $error.text(message);
            $field.after($error);
        },

        invalidateErrors: function(fields, errors) {
            _(_(errors).keys()).each(function(errorKey) {
                var errorMsg = errors[errorKey];
                var $field = fields[errorKey];
                klp.utils.invalidateField($field, errorMsg);
            });
        },

        validateRequired: function(formID) {
            var $form = $('#' + formID);
            var isValid = true;
            $form.find('[data-required=true]').each(function() {
                var $this = $(this);
                if ($this.val() === '') {
                    isValid = false;
                    klp.utils.invalidateField($this, "This field is required.");
                }
            });
            return isValid;
        },

        clearValidationErrors: function(formID) {
            var $form = $('#' + formID);
            $form.find('.error').removeClass('error');
            $form.find('.js-error-message .error-message').remove();
        },

        clearForm: function(formID) {
            $('#' + formID).find('input, select').not('[type=submit]').each(function() {
                $(this).val('');
            });
            klp.utils.clearValidationErrors(formID);
        },

        startSubmit: function(formID) {
            var $form = $('#' + formID);
            $form.find('.js-submit-btn').hide();
            $form.find('input, textarea, select').attr('disabled', 'disabled');
            $form.find('.js-submit-loading').show();
        },

        stopSubmit: function(formID) {
            var $form = $('#' + formID);
            $form.find('.js-submit-btn').show();
            $form.find('input, textarea, select').removeAttr('disabled');
            $form.find('.js-submit-loading').hide();
        },

        schoolSelect2: function($elem, options) {
            $elem.select2({
                placeholder: 'Search for schools...',
                minimumInputLength: 3,
                quietMillis: 300,
                allowClear: true,
                initSelection: function(element, callback) {
                    var id = $(element).val();
                    if (id !== '') {
                        var url = "schools/school/" + id;
                        var $xhr = klp.api.do(url);
                        $xhr.done(function(response) {
                            callback({
                                'id': response.id,
                                'name': response.name
                            })
                        });
                    }
                },
                ajax: {
                    url: "/api/v1/schools/info",
                    quietMillis: 300,
                    allowClear: true,
                    data: function (term, page) {
                        return {
                            search: term
                        };
                    },
                    results: function (data, page) {
                        //console.log("data", data);
                        return {results: data.features};
                    }
                },
                formatResult: function(item) {
                    return item.name;
                },
                formatSelection: function(item) {
                    return item.name;
                }
            });
        },

        getSchoolType: function(id) {
            return id === 1 ? 'school' : 'preschool';
        }
    };

})();
<commit_msg>fix validation errors getting repeated multiple times<commit_after>(function() {
    klp.utils = {
        compile_templates: function() {
            var $raw_tpls = $(".tpl-raw");
            var _tpl = {};
            if(!$raw_tpls.length){
                return _tpl;
            }
            $raw_tpls.each(function( index ) {
                var name = $(this).data("tpl");
                var content = $(this).html();

                _tpl[name] = swig.compile(content);
            });
            return _tpl;
        },

        mapIcon: function (type) {

            // FIXME: May be fix this in the icon name.
            // This is Sanjay's fault.
            type = type.replace(' ', '').toLowerCase();
            if (type === 'primaryschool') {
                type = 'school';
            }
            if (type === 'primaryschool_district') {
                type = 'school_district';
            }
            if (type === 'primaryschool_block') {
                type = 'school_block';
            }
            if (type === 'primaryschool_cluster') {
                type = 'school_cluster';
            }
            return L.icon({
                iconUrl: '/static/images/map/icon_'+type+'.png',
                iconSize: [20, 30],
                iconAnchor: [10, 26],
                popupAnchor: [0, -25]
            });
        },

        alertMessage: function(message, status) {
            // Status - error, success, warning.
            var $alert = $('<div />')
                            .addClass('alert')
                            .hide()
                            .text(message)
                            .appendTo('body')
                            .slideDown(250);

            if (status) {
                $alert.addClass(status);
            }
            setTimeout(function() {
                $alert.slideUp(500, function() {
                    $alert.remove();
                });
            }, 3000);
            //alert(message);
        },

        getRelativeHeight: function (width, height, min_height, container_width){
            var ht = (height/width)*container_width;
            ht = parseInt(ht,10);
            if(ht<min_height){
                return min_height;
            }
            // If number is odd, convert to even
            if(Math.abs(ht) % 2 == 1){
                ht++;
            }
            return ht;
        },

        getMTProfilePercents: function(mt_profile) {
            if (!mt_profile || _.isEmpty(mt_profile)) {
                return {
                    total: 0,
                    percents: {}
                };
            }
            var total_mts = _(_(mt_profile).values()).reduce(function(a, b) {
                return a + b;
            });
            mt_profile_percents = {};
            _(_(mt_profile).keys()).each(function(mt) {
                mt_profile_percents[mt] = ((mt_profile[mt] / total_mts) * 100).toFixed(2);
            });
            return {
                total: total_mts,
                percents: mt_profile_percents
            };
        },

        getStudentTeacherRatio: function(data) {
            var numBoys = data.num_boys_dise || 0;
            var numGirls = data.num_girls_dise || 0;
            var totalStudents = numBoys + numGirls;
            var numTeachers = data.teacher_count || null;
            if (numTeachers) {
                return parseInt(totalStudents / numTeachers);
            } else {
                return false;
            }
        },

        getBoyGirlPercents: function(num_boys, num_girls) {
            var total_students = num_boys + num_girls;
            var percent_boys = Math.round((num_boys / total_students) * 100);
            var percent_girls = Math.round((num_girls / total_students) * 100);
            return {
                total_students: total_students,
                percent_boys: percent_boys,
                percent_girls: percent_girls
            };
        },

        getFinancePercents: function(financeData) {
            var sgAmount = financeData.sg_amount ? financeData.sg_amount : 0;
            var smgAmount = financeData.smg_amount ? financeData.smg_amount : 0;
            var tlmAmount = financeData.tlm_amount ? financeData.tlm_amount : 0;
            var total = sgAmount + smgAmount + tlmAmount;
            return {
                'sg': ((sgAmount / total) * 100).toFixed(2),
                'smg': ((smgAmount / total) * 100).toFixed(2),
                'tlm': ((tlmAmount / total) * 100).toFixed(2)
            }
        },

        addSchoolContext: function(data) {
            data.has_num_students = data.num_boys && data.num_girls;
            data = $.extend(data, klp.utils.getBoyGirlPercents(data.num_boys, data.num_girls));
            if (data.hasOwnProperty('mt_profile')) {
                data.mt_profile_percents = klp.utils.getMTProfilePercents(data.mt_profile).percents;
            }
            return data;
        },

        populateForm: function(fields, data) {
            _(_(fields).keys()).each(function(key) {
                var $field = fields[key];
                if ($field.is('[data-type=image]')) {
                    if (data[key]) {
                        var $imagePreview = $field.parent().find('.js-image-preview');

                        //FIXME: avoid hard-coding "/media/", get from settings or so
                        var imageSrc = "/media/" + data[key];
                        $imagePreview.attr("src", imageSrc);
                    }
                } else {
                    $field.val(data[key]);
                }
            });
        },

        getFormData: function(fields) {
            var data = {};
            _(_(fields).keys()).each(function(key) {
                var $field = fields[key];
                if ($field.attr('type') === 'checkbox') {
                    data[key] = $field.is(":checked");
                } else if ($field.is('[data-type=image]')) {
                    var imageData = $field.parent().find('.js-image-preview').attr('src');
                    if (imageData) {
                        //remove first part of b64data
                        var fileData = imageData.split(",")[1];
                        data[key] = fileData;
                    } else {
                        data[key] = ''; //FIXME: UGLY!!
                    }
                } else {
                    data[key] = fields[key].val();
                }
            });
            return data;
        },

        invalidateField: function($field, message) {
            //remove existing errors
            $field.parent().find('.error-message').remove();

            $field.addClass('error');
            var $error = $('<div />').addClass('js-error-message error-message');
            $error.text(message);
            $field.after($error);
        },

        invalidateErrors: function(fields, errors) {
            _(_(errors).keys()).each(function(errorKey) {
                var errorMsg = errors[errorKey];
                var $field = fields[errorKey];
                klp.utils.invalidateField($field, errorMsg);
            });
        },

        validateRequired: function(formID) {
            var $form = $('#' + formID);
            var isValid = true;
            $form.find('[data-required=true]').each(function() {
                var $this = $(this);
                if ($this.val() === '') {
                    isValid = false;
                    klp.utils.invalidateField($this, "This field is required.");
                }
            });
            return isValid;
        },

        clearValidationErrors: function(formID) {
            var $form = $('#' + formID);
            $form.find('.error').removeClass('error');
            $form.find('.js-error-message .error-message').remove();
        },

        clearForm: function(formID) {
            $('#' + formID).find('input, select').not('[type=submit]').each(function() {
                $(this).val('');
            });
            klp.utils.clearValidationErrors(formID);
        },

        startSubmit: function(formID) {
            var $form = $('#' + formID);
            $form.find('.js-submit-btn').hide();
            $form.find('input, textarea, select').attr('disabled', 'disabled');
            $form.find('.js-submit-loading').show();
        },

        stopSubmit: function(formID) {
            var $form = $('#' + formID);
            $form.find('.js-submit-btn').show();
            $form.find('input, textarea, select').removeAttr('disabled');
            $form.find('.js-submit-loading').hide();
        },

        schoolSelect2: function($elem, options) {
            $elem.select2({
                placeholder: 'Search for schools...',
                minimumInputLength: 3,
                quietMillis: 300,
                allowClear: true,
                initSelection: function(element, callback) {
                    var id = $(element).val();
                    if (id !== '') {
                        var url = "schools/school/" + id;
                        var $xhr = klp.api.do(url);
                        $xhr.done(function(response) {
                            callback({
                                'id': response.id,
                                'name': response.name
                            })
                        });
                    }
                },
                ajax: {
                    url: "/api/v1/schools/info",
                    quietMillis: 300,
                    allowClear: true,
                    data: function (term, page) {
                        return {
                            search: term
                        };
                    },
                    results: function (data, page) {
                        //console.log("data", data);
                        return {results: data.features};
                    }
                },
                formatResult: function(item) {
                    return item.name;
                },
                formatSelection: function(item) {
                    return item.name;
                }
            });
        },

        getSchoolType: function(id) {
            return id === 1 ? 'school' : 'preschool';
        }
    };

})();
<|endoftext|>