<commit_before>/**
 *
 * App Entry Point
 *
 * Copyright 2019, Author Name
 * Some information on the license.
 *
**/

import Navigo from 'navigo'

import RouteGlobal from './routes/global'
import RouteHome from './routes/home'

;(function (App, window)
{

  /**
   * App
   * Constructor for App.
   *
   * @since 1.0.0
   * @version 1.0.0
  **/
  App = function()
  {
    // Create object to store strings.
    window.config.contentStrings = window.config.contentStrings || {}
  }

  /**
   * Settings for this module.
   *
   * @since 1.0.0
   * @version 1.0.0
  **/
  App.prototype._settings = {
    usePjax: false
  }

  /**
   * Module init method.
   *
   * @since 1.0.0
   * @version 1.0.0
  **/
  App.prototype.init = function()
  {
    if (this._settings.usePjax) {
      // Get plugin.
      require('jquery-pjax')
      // Start Pjax.
      $(document).pjax('a', '.page-main')
      // Run routes on update.
      $('.page-main').on('pjax:end', this.routes.bind(this))
    }
    // Run bootstrap.
    this.bootstrap()
    // Run routes.
    this.routes()
  }

  /**
   * Module plugins method.
   *
   * @since 1.0.0
   * @version 1.0.0
  **/
  App.prototype.plugins = {
    sliders: (el, options) => {
      // DOM check.
      if (!el.length) return

      // Get plugin.
      require('script-loader!slick-carousel')
      // Init plugin.
      return el.slick(options)
    }
  }

  /**
   * Preloader methods.
   *
   * @since 1.0.0
   * @version 1.0.0
  **/
  App.prototype.preloaders = {
    svgs: {
      spinner: (width, height, color) => {
        width = (width) ? width : 25
        height = (height) ? height : 25
        color = (color) ? color : '#000'
        return '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="' + width + '" height="' + height + '" fill="' + color + '" viewBox="0 0 50 50" style="display:block;enable-background:new 0 0 50 50;" xml:space="preserve"><path d="M25.251,6.461c-10.318,0-18.683,8.365-18.683,18.683h4.068c0-8.071,6.543-14.615,14.615-14.615V6.461z"><animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 25 25" to="360 25 25" dur="0.6s" repeatCount="indefinite"/></path></svg>'
      },
      circle: (width, height, color) => {
        width = (width) ? width : 25
        height = (height) ? height : 25
        color = (color) ? color : '#000'
        return '<svg width="' + width + '" height="' + height + '" stroke="' + color + '" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><g transform="translate(1 1)" stroke-width="2"><circle stroke-opacity=".5" cx="18" cy="18" r="18"/><path d="M36 18c0-9.94-8.06-18-18-18"><animateTransform attributeName="transform" type="rotate" from="0 18 18" to="360 18 18" dur="1s" repeatCount="indefinite"/></path></g></g></svg>'
      },
      tick: (width, height, color) => {
        width = (width) ? width : 25
        height = (height) ? height : 25
        color = (color) ? color : '#8ac38b'
        return '<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="' + width + '" height="' + height + '" viewBox="0 0 100 100" enable-background="new 0 0 ' + width + ' ' + height + '" xml:space="preserve"><polyline class="check" fill="none" stroke="' + color + '" stroke-width="10" stroke-miterlimit="20" points="15,60 40,80 85,20" /></svg>'
      }
    },
    button: function($el, destroy)
    {
      $el.each((index, btn) => {
        // Set button.
        let $btn = $(btn)
        // Are we destroying?
        if (destroy) {
          // Guard :: Check element has 'js-preloading' class.
          if (!$btn.length || !$btn.hasClass('js-preloading')) return

          // Get storage ID.
          let uid = $btn.attr('data-content-id')
          // Get content from storage.
          let content = JSON.parse(window.config.contentStrings[uid])
          // Renable the button.
          $btn.removeClass('btn--disabled')
          // Remove preloader and content ID.
          $btn.html(content).removeAttr('data-content-id')
          // Remove class.
          $btn.removeClass('js-preloading')
          // Reset styles.
          $btn.css({'width': '', 'height': '', 'position': ''})
        }

        // Are we creating?
        if (!destroy) {
          // Guard :: Check element has 'js-preloading' class.
          if (!$btn.length || $btn.hasClass('js-preloading')) return

          // Get button content.
          let content = JSON.stringify($btn.html())
          // Create a storage ID.
          let uid = window.Helpers.guid()
          // Store content.
          window.config.contentStrings[uid] = content
          // Create preloader.
          let $preloader = $(this.svgs.spinner()).css({'fill': '#FFFFFF'}).hide()
          // Disable the button.
          $btn.addClass('btn--disabled')
          // Add button styles.
          $btn.css({'width': $btn.outerWidth(), 'height': $btn.outerHeight(), 'position': 'relative'})
          // Add preloader and content ID.
          $btn.html($preloader).attr('data-content-id', uid)
          // Add class.
          $btn.addClass('js-preloading')
          // Add preloader styles.
          $preloader.css({'position': 'absolute', 'top': '50%', 'left': '50%', 'margin-left': -$preloader.outerWidth() / 2, 'margin-top': -$preloader.outerHeight() / 2}).show()
        }
      })
    }
  }

  /**
   * Module bootstrap method.
   *
   * @since 1.0.0
   * @version 1.0.0
  **/
  App.prototype.bootstrap = function()
  {
    // Remove 'no-js' class from html.
    $('html').removeClass('no-js').addClass('js')
  }

  /**
   * Module routes method.
   *
   * @since 1.0.0
   * @version 1.0.0
  **/
  App.prototype.routes = function()
  {
    // Init Routing.
    window.Router = new Navigo(location.protocol + '//' + location.host, false)
    // Start global route controller init method.
    RouteGlobal.init()
    // Start global route controller listeners method.
    RouteGlobal.listeners()
    // Router.
    window.Router.on({
      '/': () => {
        // Log it.
        window.Helpers.log('Route Loaded: home', '#E19F12')
        // Get route controller.
        let c = RouteHome
        // Check for an init method.
        if (typeof c.init === 'function') c.init()
        // Check for an listeners method.
        if (typeof c.listeners === 'function') c.events()
      }
    }).resolve()
  }

  // Export
  window.App = new App()

}(window.App = window.App || function () {}, window))

// Start.
window.App.init()
<commit_msg>Fixes<commit_after>/**
 *
 * App Entry Point
 *
 * Copyright 2019, Author Name
 * Some information on the license.
 *
**/

import Navigo from 'navigo'

import RouteGlobal from './routes/global'
import RouteHome from './routes/home'

;(function (App, window)
{

  /**
   * App
   * Constructor for App.
   *
   * @since 1.0.0
   * @version 1.0.0
  **/
  App = function()
  {
    // Create object to store strings.
    window.config.contentStrings = window.config.contentStrings || {}
  }

  /**
   * Settings for this module.
   *
   * @since 1.0.0
   * @version 1.0.0
  **/
  App.prototype._settings = {
    usePjax: false
  }

  /**
   * Module init method.
   *
   * @since 1.0.0
   * @version 1.0.0
  **/
  App.prototype.init = function()
  {
    if (this._settings.usePjax) {
      // Get plugin.
      require('jquery-pjax')
      // Start Pjax.
      $(document).pjax('a', '.page-main')
      // Run routes on update.
      $('.page-main').on('pjax:end', this.routes.bind(this))
    }
    // Run bootstrap.
    this.bootstrap()
    // Run routes.
    this.routes()
  }

  /**
   * Module plugins method.
   *
   * @since 1.0.0
   * @version 1.0.0
  **/
  App.prototype.plugins = {
    modal: (title, body, btn, destroy) => {
      // Check for an existing modal.
      if ($('.obj-modal').length) $('.obj-modal').remove()
      // Check for destroy.
      if (destroy) return $('.obj-modal').remove()

      // Define wrapper.
      const wrapper = `<div class="obj-modal"></div>`
      // Define modal
      const modal = `

` + body + `

`
      // Get 10% of document height.
      let docHeight = ($(window).height() / 100) * 10
      // Add to body.
      if (!$('.obj-modal').length) {
        $('body').append(wrapper)
      }
      // Add to wrapper.
      $('.obj-modal').empty().append(modal)
      // Set maxium height.
      $('.obj-modal__window').css({'maxHeight': ($(window).height() - docHeight)})
      // Add title.
      if (title) {
        $('.obj-modal__window').prepend(`

` + title + `

        `)
      }
      // Add btn.
      if (btn) {
        $('.obj-modal__window').append(`

            <button class="btn btn--common btn--small" data-js-event="closeModal">` + btn + `</button>

        `)
      }
      // Wait and show modal.
      setTimeout(() => {
        $('.obj-modal').addClass('active')
      }, 50)
      // Click events.
      $('[data-js-event="closeModal"]').on('click', () => {
        $('.obj-modal').remove()
      })
    },
    sliders: (el, options) => {
      // DOM check.
      if (!el.length) return

      // Get plugin.
      require('script-loader!slick-carousel')
      // Init plugin.
      return el.slick(options)
    }
  }

  /**
   * Preloader methods.
   *
   * @since 1.0.0
   * @version 1.0.0
  **/
  App.prototype.preloaders = {
    svgs: {
      spinner: (width, height, color) => {
        width = (width) ? width : 25
        height = (height) ? height : 25
        color = (color) ? color : '#000'
        return '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="' + width + '" height="' + height + '" fill="' + color + '" viewBox="0 0 50 50" style="display:block;enable-background:new 0 0 50 50;" xml:space="preserve"><path d="M25.251,6.461c-10.318,0-18.683,8.365-18.683,18.683h4.068c0-8.071,6.543-14.615,14.615-14.615V6.461z"><animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 25 25" to="360 25 25" dur="0.6s" repeatCount="indefinite"/></path></svg>'
      },
      circle: (width, height, color) => {
        width = (width) ? width : 25
        height = (height) ? height : 25
        color = (color) ? color : '#000'
        return '<svg width="' + width + '" height="' + height + '" stroke="' + color + '" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><g transform="translate(1 1)" stroke-width="2"><circle stroke-opacity=".5" cx="18" cy="18" r="18"/><path d="M36 18c0-9.94-8.06-18-18-18"><animateTransform attributeName="transform" type="rotate" from="0 18 18" to="360 18 18" dur="1s" repeatCount="indefinite"/></path></g></g></svg>'
      },
      tick: (width, height, color) => {
        width = (width) ? width : 25
        height = (height) ? height : 25
        color = (color) ? color : '#8ac38b'
        return '<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="' + width + '" height="' + height + '" viewBox="0 0 100 100" enable-background="new 0 0 ' + width + ' ' + height + '" xml:space="preserve"><polyline class="check" fill="none" stroke="' + color + '" stroke-width="10" stroke-miterlimit="20" points="15,60 40,80 85,20" /></svg>'
      }
    },
    button: function($el, destroy)
    {
      $el.each((index, btn) => {
        // Set button.
        let $btn = $(btn)
        // Are we destroying?
        if (destroy) {
          // Guard :: Check element has 'js-preloading' class.
          if (!$btn.length || !$btn.hasClass('js-preloading')) return

          // Get storage ID.
          let uid = $btn.attr('data-content-id')
          // Get content from storage.
          let content = JSON.parse(window.config.contentStrings[uid])
          // Renable the button.
          $btn.removeClass('btn--disabled')
          // Remove preloader and content ID.
          $btn.html(content).removeAttr('data-content-id')
          // Remove class.
          $btn.removeClass('js-preloading')
          // Reset styles.
          $btn.css({'width': '', 'height': '', 'position': ''})
        }

        // Are we creating?
        if (!destroy) {
          // Guard :: Check element has 'js-preloading' class.
          if (!$btn.length || $btn.hasClass('js-preloading')) return

          // Get button content.
          let content = JSON.stringify($btn.html())
          // Create a storage ID.
          let uid = window.Helpers.guid()
          // Store content.
          window.config.contentStrings[uid] = content
          // Create preloader.
          let $preloader = $(this.svgs.spinner()).css({'fill': '#FFFFFF'}).hide()
          // Disable the button.
          $btn.addClass('btn--disabled')
          // Add button styles.
          $btn.css({'width': $btn.outerWidth(), 'height': $btn.outerHeight(), 'position': 'relative'})
          // Add preloader and content ID.
          $btn.html($preloader).attr('data-content-id', uid)
          // Add class.
          $btn.addClass('js-preloading')
          // Add preloader styles.
          $preloader.css({'position': 'absolute', 'top': '50%', 'left': '50%', 'margin-left': -$preloader.outerWidth() / 2, 'margin-top': -$preloader.outerHeight() / 2}).show()
        }
      })
    }
  }

  /**
   * Module bootstrap method.
   *
   * @since 1.0.0
   * @version 1.0.0
  **/
  App.prototype.bootstrap = function()
  {
    // Remove 'no-js' class from html.
    $('html').removeClass('no-js').addClass('js')
  }

  /**
   * Module routes method.
   *
   * @since 1.0.0
   * @version 1.0.0
  **/
  App.prototype.routes = function()
  {
    // Init Routing.
    window.Router = new Navigo(location.protocol + '//' + location.host, false)
    // Start global route controller init method.
    RouteGlobal.init()
    // Start global route controller listeners method.
    RouteGlobal.listeners()
    // Router.
    window.Router.on({
      '/': () => {
        // Log it.
        window.Helpers.log('Route Loaded: home', '#E19F12')
        // Get route controller.
        let c = RouteHome
        // Check for an init method.
        if (typeof c.init === 'function') c.init()
        // Check for an listeners method.
        if (typeof c.listeners === 'function') c.events()
      }
    }).resolve()
  }

  // Export
  window.App = new App()

}(window.App = window.App || function () {}, window))

// Start.
window.App.init()
<|endoftext|>


<commit_before>console.log('module1!);
<commit_msg>Update module1.js<commit_after>console.log('module1!');
<|endoftext|>


<commit_before>const helper = require('think-helper');
const assert = require('assert');
const Cookies = require('cookies');
const url = require('url');

const PARAM = Symbol('context-param');
const POST = Symbol('context-post');
const FILE = Symbol('context-file');
const COOKIE_STORE = Symbol('cookie-store');
const path = require('path');
const fs = require('fs');
const onFinished = require('on-finished');
const destroy = require('destroy');

/**
 * extend context
 */
module.exports = {
  /**
   * get userAgent header
   */
  get userAgent() {
    return this.header['user-agent'];
  },
  /**
   * is get request
   */
  get isGet() {
    return this.method === 'GET';
  },
  /**
   * is post request
   */
  get isPost() {
    return this.method === 'POST';
  },
  /**
   * is command line invoke
   */
  get isCli() {
    return this.method === 'CLI';
  },
  /**
   * get referer header
   */
  referer(onlyHost) {
    return this.referrer(onlyHost);
  },
  /**
   * get referer header
   */
  referrer(onlyHost) {
    const referrer = this.header['referer'];
    if (!referrer || !onlyHost) return referrer;
    return url.parse(referrer).hostname;
  },
  /**
   * is method
   */
  isMethod(method) {
    return this.method === method.toUpperCase();
  },
  /**
   * is ajax request
   */
  isAjax(method) {
    if (method && !this.isMethod(method)) return false;
    return this.header['x-requested-with'] === 'XMLHttpRequest';
  },
  /**
   * is jsonp request
   */
  isJsonp(callbackField = this.config('jsonpCallbackField')) {
    return !!this.param(callbackField);
  },
  /**
   * send jsonp data
   */
  jsonp(data, callbackField = this.config('jsonpCallbackField')) {
    let field = this.param(callbackField);
    // remove unsafe chars
    field = (field || '').replace(/[^\w.]/g, '');
    if (field) {
      data = `${field}(${JSON.stringify(data)})`;
    }
    this.type = this.config('jsonpContentType');
    this.body = data;
    return false;
  },
  /**
   * send json data
   */
  json(data) {
    this.type = this.config('jsonContentType');
    this.body = data;
    return false;
  },
  /**
   * send success data
   */
  success(data = '', message = '') {
    const obj = {
      [this.config('errnoField')]: 0,
      [this.config('errmsgField')]: message,
      data
    };
    this.type = this.config('jsonContentType');
    this.body = obj;
    return false;
  },
  /**
   * send fail data
   */
  fail(errno, errmsg = '', data = '') {
    let obj;
    if (helper.isObject(errno)) {
      obj = errno;
    } else {
      if (/^[A-Z_]+$/.test(errno)) {
        const messages = think.app.validators.messages || {};
        const msg = messages[errno];
        if (think.isArray(msg)) {
          [errno, errmsg] = msg;
        }
      }
      if (!think.isNumber(errno)) {
        [data, errmsg, errno] = [errmsg, errno, this.config('defaultErrno')];
      }
      obj = {
        [this.config('errnoField')]: errno,
        [this.config('errmsgField')]: errmsg
      };
      if (data) {
        obj.data = data;
      }
    }
    this.type = this.config('jsonContentType');
    this.body = obj;
    return false;
  },
  /**
   * set expires header
   */
  expires(time) {
    time = helper.ms(time);
    const date = new Date(Date.now() + time);
    this.set('Cache-Control', `max-age=${time}`);
    this.set('Expires', date.toUTCString());
  },
  /**
   * get or set configs
   * @param {String} name
   * @param {Mixed} value
   * @param {String} m
   */
  config(name, value, m = this.module) {
    return think.config(name, value, m);
  },
  /**
   * get or set query data
   * `query` or `get` is already used in koa
   * @param {String} name
   * @param {Mixed} value
   */
  param(name, value) {
    if (!this[PARAM]) {
      this[PARAM] = Object.assign({}, this.request._query || this.request.query);
      this.app.emit('filterParam', this[PARAM]);
    }
    if (!name) return this[PARAM];
    if (helper.isObject(name)) {
      this[PARAM] = Object.assign(this[PARAM], name);
      return this;
    }
    assert(name && helper.isString(name), 'param.name must be a string');
    if (value === undefined) {
      // this.param('a,b')
      if (name.indexOf(',') > -1) {
        const value = {};
        name.split(',').forEach(item => {
          value[item] = this[PARAM][item];
        });
        return value;
      }
      return this[PARAM][name];
    }
    this[PARAM][name] = value;
    return this;
  },
  /**
   * get or set post data
   * @param {String} name
   * @param {Mixed} value
   */
  post(name, value) {
    if (!this[POST]) {
      const json = this.request.body && this.request.body.post;
      this[POST] = think.isArray(json) ? Array.from(json) : Object.assign({}, json);
      this.app.emit('filterParam', this[POST]);
    }
    if (!name) return this[POST];
    if (helper.isObject(name)) {
      this[POST] = Object.assign(this[POST], name);
      return this;
    }
    if (value === undefined) {
      // this.param('a,b')
      if (name.indexOf(',') > -1) {
        const value = {};
        name.split(',').forEach(item => {
          value[item] = this[POST][item];
        });
        return value;
      }
      return this[POST][name];
    }
    this[POST][name] = value;
    return this;
  },
  /**
   * get or set file data
   * @param {String} name
   * @param {Mixed} value
   */
  file(name, value) {
    if (!this[FILE]) {
      this[FILE] = Object.assign({}, this.request.body && this.request.body.file);
    }
    if (!name) return this[FILE];
    if (helper.isObject(name)) {
      this[FILE] = Object.assign(this[FILE], name);
      return this;
    }
    if (value === undefined) {
      return this[FILE][name];
    }
    this[FILE][name] = value;
    return this;
  },
  /**
   * get or set cookie
   * @param {String} name
   * @param {String} value
   * @param {Object} options
   */
  cookie(name, value, options = {}) {
    assert(name && helper.isString(name), 'cookie.name must be a string');
    options = Object.assign({}, this.config('cookie'), options);
    const instance = new Cookies(this.req, this.res, {
      keys: options.keys,
      secure: this.req.secure
    });

    if (!this[COOKIE_STORE]) this[COOKIE_STORE] = {};

    // get cookie
    if (value === undefined) {
      if (this[COOKIE_STORE][name] !== undefined) return this[COOKIE_STORE][name];
      return instance.get(name, options);
    }
    // remove cookie
    if (value === null) {
      delete this[COOKIE_STORE][name];
      // If the value is omitted, an outbound header with an expired date is used to delete the cookie.
      // https://github.com/pillarjs/cookies#cookiesset-name--value---options--
      return instance.set(name, undefined, options);
    }
    assert(helper.isString(value), 'cookie value must be a string');
    // http://browsercookielimits.squawky.net/
    if (value.length >= 4094) {
      this.app.emit('cookieLimit', {name, value, ctx: this});
    }
    this[COOKIE_STORE][name] = value;
    // set cookie
    return instance.set(name, value, options);
  },
  /**
   * get service
   * @param {String} name
   * @param {String} m
   */
  service(...args) {
    return think.service(...args);
  },
  /**
   * download
   * @param {String} filepath
   * @param {String} filename
   */
  download(filepath, filename = path.basename(filepath)) {
    assert(filepath, 'filepath can not be empty');
    const contentType = this.response.get('Content-Type');
    if (!contentType) {
      this.type = path.extname(filename);
    }
    const contentDisposition = this.response.get('Content-Disposition');
    if (!contentDisposition) {
      this.attachment(filename);
    }
    const stream = fs.createReadStream(filepath);
    this.body = stream;
    onFinished(this.res, () => {
      destroy(stream);
    });
    return false;
  }
};
<commit_msg>fix #974<commit_after>const helper = require('think-helper');
const assert = require('assert');
const Cookies = require('cookies');
const url = require('url');

const PARAM = Symbol('context-param');
const POST = Symbol('context-post');
const FILE = Symbol('context-file');
const COOKIE_STORE = Symbol('cookie-store');
const path = require('path');
const fs = require('fs');
const onFinished = require('on-finished');
const destroy = require('destroy');

/**
 * extend context
 */
module.exports = {
  /**
   * get userAgent header
   */
  get userAgent() {
    return this.header['user-agent'];
  },
  /**
   * is get request
   */
  get isGet() {
    return this.method === 'GET';
  },
  /**
   * is post request
   */
  get isPost() {
    return this.method === 'POST';
  },
  /**
   * is command line invoke
   */
  get isCli() {
    return this.method === 'CLI';
  },
  /**
   * get referer header
   */
  referer(onlyHost) {
    return this.referrer(onlyHost);
  },
  /**
   * get referer header
   */
  referrer(onlyHost) {
    const referrer = this.header['referer'];
    if (!referrer || !onlyHost) return referrer;
    return url.parse(referrer).hostname;
  },
  /**
   * is method
   */
  isMethod(method) {
    return this.method === method.toUpperCase();
  },
  /**
   * is ajax request
   */
  isAjax(method) {
    if (method && !this.isMethod(method)) return false;
    return this.header['x-requested-with'] === 'XMLHttpRequest';
  },
  /**
   * is jsonp request
   */
  isJsonp(callbackField = this.config('jsonpCallbackField')) {
    return !!this.param(callbackField);
  },
  /**
   * send jsonp data
   */
  jsonp(data, callbackField = this.config('jsonpCallbackField')) {
    let field = this.param(callbackField);
    // remove unsafe chars
    field = (field || '').replace(/[^\w.]/g, '');
    if (field) {
      data = `${field}(${JSON.stringify(data)})`;
    }
    this.type = this.config('jsonpContentType');
    this.body = data;
    return false;
  },
  /**
   * send json data
   */
  json(data) {
    this.type = this.config('jsonContentType');
    this.body = data;
    return false;
  },
  /**
   * send success data
   */
  success(data = '', message = '') {
    const obj = {
      [this.config('errnoField')]: 0,
      [this.config('errmsgField')]: message,
      data
    };
    this.type = this.config('jsonContentType');
    this.body = obj;
    return false;
  },
  /**
   * send fail data
   */
  fail(errno, errmsg = '', data = '') {
    let obj;
    if (helper.isObject(errno)) {
      obj = errno;
    } else {
      if (/^[A-Z_]+$/.test(errno)) {
        const messages = think.app.validators.messages || {};
        const msg = messages[errno];
        if (think.isArray(msg)) {
          [errno, errmsg] = msg;
        }
      }
      if (!think.isNumber(errno)) {
        [data, errmsg, errno] = [errmsg, errno, this.config('defaultErrno')];
      }
      obj = {
        [this.config('errnoField')]: errno,
        [this.config('errmsgField')]: errmsg
      };
      if (data) {
        obj.data = data;
      }
    }
    this.type = this.config('jsonContentType');
    this.body = obj;
    return false;
  },
  /**
   * set expires header
   */
  expires(time) {
    time = helper.ms(time);
    const date = new Date(Date.now() + time);
    this.set('Cache-Control', `max-age=${time}`);
    this.set('Expires', date.toUTCString());
  },
  /**
   * get or set configs
   * @param {String} name
   * @param {Mixed} value
   * @param {String} m
   */
  config(name, value, m = this.module) {
    return think.config(name, value, m);
  },
  /**
   * get or set query data
   * `query` or `get` is already used in koa
   * @param {String} name
   * @param {Mixed} value
   */
  param(name, value) {
    if (!this[PARAM]) {
      this[PARAM] = Object.assign({}, this.request._query || this.request.query);
      this.app.emit('filterParam', this[PARAM]);
    }
    if (!name) return this[PARAM];
    if (helper.isObject(name)) {
      this[PARAM] = Object.assign(this[PARAM], name);
      return this;
    }
    assert(name && helper.isString(name), 'param.name must be a string');
    if (value === undefined) {
      // this.param('a,b')
      if (name.indexOf(',') > -1) {
        const value = {};
        name.split(',').forEach(item => {
          value[item] = this[PARAM][item];
        });
        return value;
      }
      return this[PARAM][name];
    }
    this[PARAM][name] = value;
    return this;
  },
  /**
   * get or set post data
   * @param {String} name
   * @param {Mixed} value
   */
  post(name, value) {
    if (!this[POST]) {
      const json = this.request.body && this.request.body.post;
      this[POST] = think.isArray(json) ? Array.from(json) : Object.assign({}, json);
      this.app.emit('filterParam', this[POST]);
    }
    if (!name) return this[POST];
    if (helper.isObject(name)) {
      this[POST] = Object.assign(this[POST], name);
      return this;
    }
    if (value === undefined) {
      // this.param('a,b')
      if (name.indexOf(',') > -1) {
        const value = {};
        name.split(',').forEach(item => {
          value[item] = this[POST][item];
        });
        return value;
      }
      return this[POST][name];
    }
    this[POST][name] = value;
    return this;
  },
  /**
   * get or set file data
   * @param {String} name
   * @param {Mixed} value
   */
  file(name, value) {
    if (!this[FILE]) {
      this[FILE] = Object.assign({}, this.request.body && this.request.body.file);
    }
    if (!name) return this[FILE];
    if (helper.isObject(name)) {
      this[FILE] = Object.assign(this[FILE], name);
      return this;
    }
    if (value === undefined) {
      return this[FILE][name];
    }
    this[FILE][name] = value;
    return this;
  },
  /**
   * get or set cookie
   * @param {String} name
   * @param {String} value
   * @param {Object} options
   */
  cookie(name, value, options = {}) {
    assert(name && helper.isString(name), 'cookie.name must be a string');
    options = Object.assign({}, this.config('cookie'), options);
    const instance = new Cookies(this.req, this.res, {
      keys: options.keys,
      secure: this.request.secure
    });

    if (!this[COOKIE_STORE]) this[COOKIE_STORE] = {};

    // get cookie
    if (value === undefined) {
      if (this[COOKIE_STORE][name] !== undefined) return this[COOKIE_STORE][name];
      return instance.get(name, options);
    }
    // remove cookie
    if (value === null) {
      delete this[COOKIE_STORE][name];
      // If the value is omitted, an outbound header with an expired date is used to delete the cookie.
      // https://github.com/pillarjs/cookies#cookiesset-name--value---options--
      return instance.set(name, undefined, options);
    }
    assert(helper.isString(value), 'cookie value must be a string');
    // http://browsercookielimits.squawky.net/
    if (value.length >= 4094) {
      this.app.emit('cookieLimit', {name, value, ctx: this});
    }
    this[COOKIE_STORE][name] = value;
    // set cookie
    return instance.set(name, value, options);
  },
  /**
   * get service
   * @param {String} name
   * @param {String} m
   */
  service(...args) {
    return think.service(...args);
  },
  /**
   * download
   * @param {String} filepath
   * @param {String} filename
   */
  download(filepath, filename = path.basename(filepath)) {
    assert(filepath, 'filepath can not be empty');
    const contentType = this.response.get('Content-Type');
    if (!contentType) {
      this.type = path.extname(filename);
    }
    const contentDisposition = this.response.get('Content-Disposition');
    if (!contentDisposition) {
      this.attachment(filename);
    }
    const stream = fs.createReadStream(filepath);
    this.body = stream;
    onFinished(this.res, () => {
      destroy(stream);
    });
    return false;
  }
};
<|endoftext|>


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

var Document = this.Document = Base.extend({
	beans: true,

	initialize: function(canvas) {
		if (canvas && canvas instanceof HTMLCanvasElement) {
			this.canvas = canvas;
			this.size = new Size(canvas.offsetWidth, canvas.offsetHeight);
		} else {
			this.size = Size.read(arguments) || new Size(1024, 768);
			this.canvas = document.createElement('canvas');
			this.canvas.width = this.size.width;
			this.canvas.height = this.size.height;
		}
		this.bounds = new Rectangle(new Point(0, 0), this.size);
		this.context = this.canvas.getContext('2d');
		paper.documents.push(this);
		this.activate();
		this.layers = [];
		this.activeLayer = new Layer();
		this.setCurrentStyle(null);
		this.symbols = [];
		this.views = [new DocumentView(this)];
		this.activeView = this.views[0];
		this._selectedItems = {};
		this._selectedItemCount = 0;
	},

	getCurrentStyle: function() {
		return this._currentStyle;
	},

	setCurrentStyle: function(style) {
		this._currentStyle = new PathStyle(this, style);
	},

	activate: function() {
		var index = paper.documents.indexOf(this);
		if (index != -1) {
			paper.document = this;
			return true;
		}
		return false;
	},

	getSelectedItems: function() {
		// TODO: return groups if their children are all selected,
		// and filter out their children from the list.
		// TODO: the order of these items should be that of their
		// drawing order.
		var items = [];
		Base.each(this._selectedItems, function(item) {
			items.push(item);
		});
		return items;
	},

	// TODO: implement setSelectedItems?

	_selectItem: function(item, select) {
		if (select) {
			this._selectedItemCount++;
			this._selectedItems[item.getId()] = item;
		} else {
			this._selectedItemCount--;
			delete this._selectedItems[item.getId()];
		}
	},

	draw: function() {
		if (this.canvas) {
			var context = this.context;
			// Initial tests conclude that clearing the canvas using clearRect
			// is always faster than setting canvas.width = canvas.width
			// http://jsperf.com/clearrect-vs-setting-width/7
			context.clearRect(0, 0,
					this.size.width + 1, this.size.height + 1);
			context.save();
			var param = { offset: new Point(0, 0) };
			for (var i = 0, l = this.layers.length; i < l; i++)
				Item.draw(this.layers[i], context, param);
			context.restore();

			// Draw the selection of the selected items in the document:
			if (this._selectedItemCount > 0) {
				context.save();
				context.strokeWidth = 1;
				// Todo: use Layer#color
				context.strokeStyle = context.fillStyle = '#4f7aff';
				param = { selection: true };
				Base.each(this._selectedItems, function(item) {
					item.draw(context, param);
				});
				context.restore();
			}
		}
	},

	redraw: function() {
		this.draw();
	}
});
<commit_msg>Add test code for dirty rectangle performance, deactivated by a boolean switch.<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

var Document = this.Document = Base.extend({
	beans: true,

	initialize: function(canvas) {
		if (canvas && canvas instanceof HTMLCanvasElement) {
			this.canvas = canvas;
			this.size = new Size(canvas.offsetWidth, canvas.offsetHeight);
		} else {
			this.size = Size.read(arguments) || new Size(1024, 768);
			this.canvas = document.createElement('canvas');
			this.canvas.width = this.size.width;
			this.canvas.height = this.size.height;
		}
		this.bounds = new Rectangle(new Point(0, 0), this.size);
		this.context = this.canvas.getContext('2d');
		paper.documents.push(this);
		this.activate();
		this.layers = [];
		this.activeLayer = new Layer();
		this.setCurrentStyle(null);
		this.symbols = [];
		this.views = [new DocumentView(this)];
		this.activeView = this.views[0];
		this._selectedItems = {};
		this._selectedItemCount = 0;
	},

	getCurrentStyle: function() {
		return this._currentStyle;
	},

	setCurrentStyle: function(style) {
		this._currentStyle = new PathStyle(this, style);
	},

	activate: function() {
		var index = paper.documents.indexOf(this);
		if (index != -1) {
			paper.document = this;
			return true;
		}
		return false;
	},

	getSelectedItems: function() {
		// TODO: return groups if their children are all selected,
		// and filter out their children from the list.
		// TODO: the order of these items should be that of their
		// drawing order.
		var items = [];
		Base.each(this._selectedItems, function(item) {
			items.push(item);
		});
		return items;
	},

	// TODO: implement setSelectedItems?

	_selectItem: function(item, select) {
		if (select) {
			this._selectedItemCount++;
			this._selectedItems[item.getId()] = item;
		} else {
			this._selectedItemCount--;
			delete this._selectedItems[item.getId()];
		}
	},

	draw: function() {
		if (this.canvas) {
			var context = this.context;
			context.save();

			var testDirtyRects = false;
			if (testDirtyRects) {
				var left = this.size.width / 8,
					top = this.size.height / 8;

				function clear(rect) {
					context.clearRect(rect.x, rect.y, rect.width, rect.height);

					if (true) {
						context.moveTo(rect.x, rect.y);
						context.lineTo(rect.x + rect.width, rect.y);
						context.lineTo(rect.x + rect.width, rect.y + rect.height);
						context.lineTo(rect.x, rect.y + rect.height);
					}
				}

				context.beginPath();

				clear(Rectangle.create(left, top, 2 * left, 2 * top));
				clear(Rectangle.create(3 * left, 3 * top, 2 * left, 2 * top));

//				clear(Rectangle.create(left, top, 4 * left, 4 * top));

				context.closePath();
				context.clip();
			} else {
				// Initial tests conclude that clearing the canvas using clearRect
				// is always faster than setting canvas.width = canvas.width
				// http://jsperf.com/clearrect-vs-setting-width/7
				context.clearRect(0, 0,
						this.size.width + 1, this.size.height + 1);
			}

			var param = { offset: new Point(0, 0) };
			for (var i = 0, l = this.layers.length; i < l; i++)
				Item.draw(this.layers[i], context, param);
			context.restore();

			// Draw the selection of the selected items in the document:
			if (this._selectedItemCount > 0) {
				context.save();
				context.strokeWidth = 1;
				// Todo: use Layer#color
				context.strokeStyle = context.fillStyle = '#4f7aff';
				param = { selection: true };
				Base.each(this._selectedItems, function(item) {
					item.draw(context, param);
				});
				context.restore();
			}
		}
	},

	redraw: function() {
		this.draw();
	}
});
<|endoftext|>


<commit_before>/** section: scripty2 fx
 *  class s2.fx.Heartbeat
 *
 *  The heartbeat class provides for effects timing. An instance of this class
 *  is automatically created when the first effect on a page is instantiated.
 *
 *  This class can be extended and replaced by your own implementation:
 *
 *      // call before effects are created
 *      var myHeartbeat = Class.create(s2.fx.Heartbeat, { ... });
 *      s2.fx.initialize(new myHeartbeat());
 *
 *  This can be used to implement customized debugging and more.
**/
s2.fx.Heartbeat = Class.create({
  /**
   *  new s2.fx.Heartbeat([options])
   *  - options (Object): options hash
   *
   *  The following options are available:
   *  * [[framerate]]: set (maximum) framerate for calls to [[s2.fx.beat]]/
  **/
  initialize: function(options) {
    this.options = Object.extend({
      framerate: Prototype.Browser.MobileSafari ? 20 : 60
    }, options);
    this.beat = this.beat.bind(this);
  },

  /**
   *  s2.fx.Heartbeat.start() -> undefined
   *
   *  This function is called by [[s2.fx]] whenever there's a new active effect queued
   *  and there are no other effects running. This mechanism can be used to prevent
   *  unnecessary timeouts/intervals from being active, as [[s2.fx.Hearbeat.beat]] is only
   *  called when there are active effects that need to be rendered.
  **/
  start: function() {
    if (this.heartbeatInterval) return;
    this.heartbeatInterval =
      setInterval(this.beat, 1000/this.options.framerate);
    this.updateTimestamp();
  },

  /**
   *  s2.fx.Heartbeat.stop() -> undefined
   *
   *  Called when the last active effect is dequeued.
  **/
  stop: function() {
    if (!this.heartbeatInterval) return;
    clearInterval(this.heartbeatInterval);
    this.heartbeatInterval = null;
    this.timestamp = null;
  },

  /**
   *  s2.fx.Heartbeat.beat() -> undefined
   *
   *  This method fires an `effect:heartbeat` event which is in turn used by
   *  [[s2.fx]] to render all active effect queues.
   *
   *  Fires: effect:heartbeat
  **/
  beat: function() {
    this.updateTimestamp();
    document.fire('effect:heartbeat');
  },

  /**
   *  s2.fx.Heartbeat.getTimestamp() -> Date
   *
   *  Returns the current timestamp.
  **/
  getTimestamp: function() {
    return this.timestamp || this.generateTimestamp();
  },

  /**
   *  s2.fx.Heartbeat.generateTimestamp() -> Date
   *
   *  Returns the current date and time.
  **/
  generateTimestamp: function() {
    return new Date().getTime();
  },

  /**
   *  s2.fx.Heartbeat.updateTimestamp() -> undefined
   *
   *  Updates the current timestamp (sets it to the current date and time).
   *
   *  If subclassed, this can be used to achieve special effects, for example all effects
   *  could be sped up or slowed down.
  **/
  updateTimestamp: function() {
    this.timestamp = this.generateTimestamp();
  }
});<commit_msg>Fix docs: heartbeat methods are instance methods<commit_after>/** section: scripty2 fx
 *  class s2.fx.Heartbeat
 *
 *  The heartbeat class provides for effects timing. An instance of this class
 *  is automatically created when the first effect on a page is instantiated.
 *
 *  This class can be extended and replaced by your own implementation:
 *
 *      // call before effects are created
 *      var myHeartbeat = Class.create(s2.fx.Heartbeat, { ... });
 *      s2.fx.initialize(new myHeartbeat());
 *
 *  This can be used to implement customized debugging and more.
**/
s2.fx.Heartbeat = Class.create({
  /**
   *  new s2.fx.Heartbeat([options])
   *  - options (Object): options hash
   *
   *  The following options are available:
   *  * [[framerate]]: set (maximum) framerate for calls to [[s2.fx.beat]]/
  **/
  initialize: function(options) {
    this.options = Object.extend({
      framerate: Prototype.Browser.MobileSafari ? 20 : 60
    }, options);
    this.beat = this.beat.bind(this);
  },

  /**
   *  s2.fx.Heartbeat#start() -> undefined
   *
   *  This function is called by [[s2.fx]] whenever there's a new active effect queued
   *  and there are no other effects running. This mechanism can be used to prevent
   *  unnecessary timeouts/intervals from being active, as [[s2.fx.Hearbeat.beat]] is only
   *  called when there are active effects that need to be rendered.
  **/
  start: function() {
    if (this.heartbeatInterval) return;
    this.heartbeatInterval =
      setInterval(this.beat, 1000/this.options.framerate);
    this.updateTimestamp();
  },

  /**
   *  s2.fx.Heartbeat#stop() -> undefined
   *
   *  Called when the last active effect is dequeued.
  **/
  stop: function() {
    if (!this.heartbeatInterval) return;
    clearInterval(this.heartbeatInterval);
    this.heartbeatInterval = null;
    this.timestamp = null;
  },

  /**
   *  s2.fx.Heartbeat#beat() -> undefined
   *
   *  This method fires an `effect:heartbeat` event which is in turn used by
   *  [[s2.fx]] to render all active effect queues.
   *
   *  Fires: effect:heartbeat
  **/
  beat: function() {
    this.updateTimestamp();
    document.fire('effect:heartbeat');
  },

  /**
   *  s2.fx.Heartbeat#getTimestamp() -> Date
   *
   *  Returns the current timestamp.
  **/
  getTimestamp: function() {
    return this.timestamp || this.generateTimestamp();
  },

  /**
   *  s2.fx.Heartbeat#generateTimestamp() -> Date
   *
   *  Returns the current date and time.
  **/
  generateTimestamp: function() {
    return new Date().getTime();
  },

  /**
   *  s2.fx.Heartbeat#updateTimestamp() -> undefined
   *
   *  Updates the current timestamp (sets it to the current date and time).
   *
   *  If subclassed, this can be used to achieve special effects, for example all effects
   *  could be sped up or slowed down.
  **/
  updateTimestamp: function() {
    this.timestamp = this.generateTimestamp();
  }
});<|endoftext|>


<commit_before>import elrUtlities from 'elr-utilities';
const $ = require('jquery');

let elr = elrUtlities();

const elrSimpleSlider = function({
    sliderClass = 'elr-simple-slider',
    slideClass = 'elr-simple-slide',
    slideHolderClass = 'elr-simple-slide-holder',
    effect = 'fade',
    navClass = 'elr-simple-slider-nav',
    slideListClass = 'elr-simple-slider-list',
    speed = 500,
    interval = 10000,
    auto = true
} = {}) {
    const $slider = $(`.${sliderClass}`);
    let isAnimating = false;
    const self = {
        createSlideList($slides) {
            let li = '';

            $.each($slides, function(index) {
                if (index === 0) {
                    li += `<li><button class="active" data-item-num="${index}"></button></li>`;
                } else {
                    li += `<li><button data-item-num="${index}"></button></li>`;
                }
            });

            return elr.createElement('ul', {
                'class': slideListClass,
                'html': li
            });
        },
        getCurrent($slideHolder) {
            const $slides = $slideHolder.find(`.${slideClass}`);

            if (effect === 'fade') {
                return $slides.not(':hidden').index();
            } else if (effect === 'slide-left') {
                return (Math.abs($slideHolder.position().left) / parseInt($slides.first().width(), 10));
            }
        },
        goToSlide(current, slideNum, $slideHolder) {
            const $slides = $slideHolder.find(`.${slideClass}`);

            if (effect === 'fade') {
                $slides.eq(current).fadeOut(speed);
                $slides.eq(slideNum).fadeIn(speed);
            } else if (effect === 'slide-left') {
                const slideWidth = parseInt($slides.first().width(), 10);
                const pos = $slideHolder.position().left;
                let newPos;

                if (current < slideNum) {
                    const slideDiff = current - slideNum;
                    newPos = pos + (slideWidth * slideDiff);
                } else if (current > slideNum) {
                    const slideDiff = -(current - slideNum);
                    newPos = pos - (slideWidth * slideDiff);
                }

                $slideHolder.stop().animate({
                    left: newPos
                }, speed);
            }
        },
        fadeSlide(current, dir, $slides) {
            const lastSlide = $slides.length - 1;

            $slides.eq(current).fadeOut(speed);

            if (dir === 'next' && current === lastSlide) {
                $slides.first().fadeIn(speed);

                return 0;
            } else if (dir === 'next') {
                $slides.eq(current + 1).fadeIn(speed);

                return current + 1;
            } else if (dir === 'prev' && current === 0) {
                $slides.eq(lastSlide).fadeIn(speed);

                return lastSlide;
            } else {
                $slides.eq(current - 1).fadeIn(speed);

                return current - 1;
            }
        },
        slideLeft(current, dir, $slides, $slideHolder) {
            // TODO: fix bug where paging doesn't work properly when paging from first to last slide

            const lastSlide = $slides.length - 1;
            const slideWidth = parseInt($slides.first().width(), 10);
            const pos = $slideHolder.position().left;

            isAnimating = true;

            if (dir === 'next' && current === lastSlide) {
                let $oldSlides = $slides;
                let $newSlides = $slides.clone();
                let numSlides = $slides.length;

                $slideHolder.css('width', slideWidth * (numSlides * 2));
                $slideHolder.append($newSlides);
                let newPos = pos - slideWidth;

                $slideHolder.stop().animate({
                    left: newPos
                }, speed, 'linear', function() {
                    $slideHolder.css({
                        'width': slideWidth * numSlides,
                        'left': 0
                    });
                    $oldSlides.remove();
                    isAnimating = false;
                });

                return 0;
            } else if (dir === 'next') {
                let newPos = pos - slideWidth;

                $slideHolder.stop().animate({
                    left: newPos
                }, speed, 'linear', function() {
                    isAnimating = false;
                });

                return (Math.abs(newPos) / slideWidth);
            } else if (dir === 'prev' && current === 0) {
                let $oldSlides = $slides;
                let $newSlides = $slides.clone();
                let numSlides = $slides.length;
                let width = slideWidth * numSlides;

                $slideHolder.css('width', width * 2);
                $slideHolder.prepend($newSlides);
                $slideHolder.css('left', -width);
                let newPos = -width + slideWidth;

                $slideHolder.stop().animate({
                    left: newPos
                }, speed, 'linear', function() {
                    $slideHolder.css({
                        'width': width,
                        'left': -(width - slideWidth)
                    });
                    $oldSlides.remove();
                    isAnimating = false;
                });

                return numSlides - 1;
            } else {
                let newPos = pos + slideWidth;

                $slideHolder.stop().animate({
                    left: newPos
                }, speed, 'linear', function() {
                    isAnimating = false;
                });

                return (Math.abs(newPos) / slideWidth);
            }
        },
        advanceSlide(current, dir, $slideHolder) {
            const $slides = $slideHolder.find(`.${slideClass}`);

            if (effect === 'fade') {
                return self.fadeSlide(current, dir, $slides);
            } else if (effect === 'slide-left') {
                return self.slideLeft(current, dir, $slides, $slideHolder);
            }
        },
        pageSlide(e, $slideHolder) {
            const current = self.getCurrent($slideHolder);
            let dir;

            if (e.which === 37) {
                dir = 'prev';
            } else if (e.which === 39) {
                dir = 'next';
            } else {
                return;
            }

            return self.advanceSlide(current, dir, $slideHolder);
        },
        startShow(interval, $slideHolder, $slideList) {
            return setInterval(function() {
                // $nextControl.trigger('click');
                const current = self.getCurrent($slideHolder);
                const nextSlide = self.advanceSlide(current, 'next', $slideHolder);

                $slideList.find('button').removeClass('active');
                $slideList.find('li').eq(nextSlide).find('button').addClass('active');
            }, interval);
        },
        pauseShow(start) {
            clearInterval(start);
            console.log('slider paused');
        }
    };

    if ($slider.length) {

        $.each($slider, function() {
            const $currentSlider = $(this);
            const $slideHolder = $currentSlider.find(`.${slideHolderClass}`);
            const $slides = $slideHolder.find(`.${slideClass}`);
            const $currentSliderControls = $currentSlider.find(`.${navClass}`).find('button');
            const $nextControl = $currentSlider.find(`.${navClass}`).find("button[data-dir='next']");
            const $body = $('body');
            let $slideList;
            let begin;

            // add overflow hidden to make sure only the current slide is visible
            $slideHolder.css({overflow: 'hidden'});

            if (effect === 'slide-left') {
                const slideWidth = $slides.first().width();
                const numSlides = $slides.length;

                $currentSlider.addClass('slide-left');
                $slideHolder.css('width', slideWidth * numSlides);
            } else if (effect === 'fade') {
                $slides.hide().first().show();
            }

            $slideList = self.createSlideList($slides).appendTo($currentSlider);

            if (auto) {
                begin = self.startShow(interval, $slideHolder, $slideList);

                $slides.on('mouseover', function() {
                    self.pauseShow(begin);
                });

                $slides.on('mouseout', function() {
                    begin = self.startShow(interval, $slideHolder, $slideList);
                });
            }

            $currentSliderControls.on('click', function(e) {
                e.preventDefault();
                e.stopPropagation();

                const dir = $(this).data('dir');
                const current = self.getCurrent($slideHolder);
                const nextSlide = self.advanceSlide(current, dir, $slideHolder);

                $slideList.find('button').removeClass('active');
                $slideList.find('li').eq(nextSlide).find('button').addClass('active');
                self.pauseShow(begin);
            });

            $currentSlider.on({
                mouseenter: function () {
                    const $holder = $(this).find(`.${slideHolderClass}`);

                    $body.keydown(function(e) {
                        if(isAnimating) {
                            e.preventDefault();
                            return false;
                        }

                        const nextSlide = self.pageSlide(e, $holder);

                        $slideList.find('button').removeClass('active');
                        $slideList.find('li').eq(nextSlide).find('button').addClass('active');
                    });
                },
                mouseleave: function () {
                    $body.off('keydown');
                }
            });

            $currentSlider.on('click', `.${slideListClass} button`, function(e) {
                e.preventDefault();
                e.stopPropagation();

                const $that = $(this);
                const current = self.getCurrent($slideHolder);
                const slideNum = $that.data('item-num');

                $slideList.find('button').removeClass('active');
                $that.addClass('active');

                self.goToSlide(current, slideNum, $slideHolder);
                self.pauseShow(begin);
            });
        });
    }

    return self;
};

export default elrSimpleSlider;<commit_msg>fix elr-utility-lib include<commit_after>import elrUtlities from 'elr-utility-lib';
const $ = require('jquery');

let elr = elrUtlities();

const elrSimpleSlider = function({
    sliderClass = 'elr-simple-slider',
    slideClass = 'elr-simple-slide',
    slideHolderClass = 'elr-simple-slide-holder',
    effect = 'fade',
    navClass = 'elr-simple-slider-nav',
    slideListClass = 'elr-simple-slider-list',
    speed = 500,
    interval = 10000,
    auto = true
} = {}) {
    const $slider = $(`.${sliderClass}`);
    let isAnimating = false;
    const self = {
        createSlideList($slides) {
            let li = '';

            $.each($slides, function(index) {
                if (index === 0) {
                    li += `<li><button class="active" data-item-num="${index}"></button></li>`;
                } else {
                    li += `<li><button data-item-num="${index}"></button></li>`;
                }
            });

            return elr.createElement('ul', {
                'class': slideListClass,
                'html': li
            });
        },
        getCurrent($slideHolder) {
            const $slides = $slideHolder.find(`.${slideClass}`);

            if (effect === 'fade') {
                return $slides.not(':hidden').index();
            } else if (effect === 'slide-left') {
                return (Math.abs($slideHolder.position().left) / parseInt($slides.first().width(), 10));
            }
        },
        goToSlide(current, slideNum, $slideHolder) {
            const $slides = $slideHolder.find(`.${slideClass}`);

            if (effect === 'fade') {
                $slides.eq(current).fadeOut(speed);
                $slides.eq(slideNum).fadeIn(speed);
            } else if (effect === 'slide-left') {
                const slideWidth = parseInt($slides.first().width(), 10);
                const pos = $slideHolder.position().left;
                let newPos;

                if (current < slideNum) {
                    const slideDiff = current - slideNum;
                    newPos = pos + (slideWidth * slideDiff);
                } else if (current > slideNum) {
                    const slideDiff = -(current - slideNum);
                    newPos = pos - (slideWidth * slideDiff);
                }

                $slideHolder.stop().animate({
                    left: newPos
                }, speed);
            }
        },
        fadeSlide(current, dir, $slides) {
            const lastSlide = $slides.length - 1;

            $slides.eq(current).fadeOut(speed);

            if (dir === 'next' && current === lastSlide) {
                $slides.first().fadeIn(speed);

                return 0;
            } else if (dir === 'next') {
                $slides.eq(current + 1).fadeIn(speed);

                return current + 1;
            } else if (dir === 'prev' && current === 0) {
                $slides.eq(lastSlide).fadeIn(speed);

                return lastSlide;
            } else {
                $slides.eq(current - 1).fadeIn(speed);

                return current - 1;
            }
        },
        slideLeft(current, dir, $slides, $slideHolder) {
            // TODO: fix bug where paging doesn't work properly when paging from first to last slide

            const lastSlide = $slides.length - 1;
            const slideWidth = parseInt($slides.first().width(), 10);
            const pos = $slideHolder.position().left;

            isAnimating = true;

            if (dir === 'next' && current === lastSlide) {
                let $oldSlides = $slides;
                let $newSlides = $slides.clone();
                let numSlides = $slides.length;

                $slideHolder.css('width', slideWidth * (numSlides * 2));
                $slideHolder.append($newSlides);
                let newPos = pos - slideWidth;

                $slideHolder.stop().animate({
                    left: newPos
                }, speed, 'linear', function() {
                    $slideHolder.css({
                        'width': slideWidth * numSlides,
                        'left': 0
                    });
                    $oldSlides.remove();
                    isAnimating = false;
                });

                return 0;
            } else if (dir === 'next') {
                let newPos = pos - slideWidth;

                $slideHolder.stop().animate({
                    left: newPos
                }, speed, 'linear', function() {
                    isAnimating = false;
                });

                return (Math.abs(newPos) / slideWidth);
            } else if (dir === 'prev' && current === 0) {
                let $oldSlides = $slides;
                let $newSlides = $slides.clone();
                let numSlides = $slides.length;
                let width = slideWidth * numSlides;

                $slideHolder.css('width', width * 2);
                $slideHolder.prepend($newSlides);
                $slideHolder.css('left', -width);
                let newPos = -width + slideWidth;

                $slideHolder.stop().animate({
                    left: newPos
                }, speed, 'linear', function() {
                    $slideHolder.css({
                        'width': width,
                        'left': -(width - slideWidth)
                    });
                    $oldSlides.remove();
                    isAnimating = false;
                });

                return numSlides - 1;
            } else {
                let newPos = pos + slideWidth;

                $slideHolder.stop().animate({
                    left: newPos
                }, speed, 'linear', function() {
                    isAnimating = false;
                });

                return (Math.abs(newPos) / slideWidth);
            }
        },
        advanceSlide(current, dir, $slideHolder) {
            const $slides = $slideHolder.find(`.${slideClass}`);

            if (effect === 'fade') {
                return self.fadeSlide(current, dir, $slides);
            } else if (effect === 'slide-left') {
                return self.slideLeft(current, dir, $slides, $slideHolder);
            }
        },
        pageSlide(e, $slideHolder) {
            const current = self.getCurrent($slideHolder);
            let dir;

            if (e.which === 37) {
                dir = 'prev';
            } else if (e.which === 39) {
                dir = 'next';
            } else {
                return;
            }

            return self.advanceSlide(current, dir, $slideHolder);
        },
        startShow(interval, $slideHolder, $slideList) {
            return setInterval(function() {
                // $nextControl.trigger('click');
                const current = self.getCurrent($slideHolder);
                const nextSlide = self.advanceSlide(current, 'next', $slideHolder);

                $slideList.find('button').removeClass('active');
                $slideList.find('li').eq(nextSlide).find('button').addClass('active');
            }, interval);
        },
        pauseShow(start) {
            clearInterval(start);
            console.log('slider paused');
        }
    };

    if ($slider.length) {

        $.each($slider, function() {
            const $currentSlider = $(this);
            const $slideHolder = $currentSlider.find(`.${slideHolderClass}`);
            const $slides = $slideHolder.find(`.${slideClass}`);
            const $currentSliderControls = $currentSlider.find(`.${navClass}`).find('button');
            const $nextControl = $currentSlider.find(`.${navClass}`).find("button[data-dir='next']");
            const $body = $('body');
            let $slideList;
            let begin;

            // add overflow hidden to make sure only the current slide is visible
            $slideHolder.css({overflow: 'hidden'});

            if (effect === 'slide-left') {
                const slideWidth = $slides.first().width();
                const numSlides = $slides.length;

                $currentSlider.addClass('slide-left');
                $slideHolder.css('width', slideWidth * numSlides);
            } else if (effect === 'fade') {
                $slides.hide().first().show();
            }

            $slideList = self.createSlideList($slides).appendTo($currentSlider);

            if (auto) {
                begin = self.startShow(interval, $slideHolder, $slideList);

                $slides.on('mouseover', function() {
                    self.pauseShow(begin);
                });

                $slides.on('mouseout', function() {
                    begin = self.startShow(interval, $slideHolder, $slideList);
                });
            }

            $currentSliderControls.on('click', function(e) {
                e.preventDefault();
                e.stopPropagation();

                const dir = $(this).data('dir');
                const current = self.getCurrent($slideHolder);
                const nextSlide = self.advanceSlide(current, dir, $slideHolder);

                $slideList.find('button').removeClass('active');
                $slideList.find('li').eq(nextSlide).find('button').addClass('active');
                self.pauseShow(begin);
            });

            $currentSlider.on({
                mouseenter: function () {
                    const $holder = $(this).find(`.${slideHolderClass}`);

                    $body.keydown(function(e) {
                        if(isAnimating) {
                            e.preventDefault();
                            return false;
                        }

                        const nextSlide = self.pageSlide(e, $holder);

                        $slideList.find('button').removeClass('active');
                        $slideList.find('li').eq(nextSlide).find('button').addClass('active');
                    });
                },
                mouseleave: function () {
                    $body.off('keydown');
                }
            });

            $currentSlider.on('click', `.${slideListClass} button`, function(e) {
                e.preventDefault();
                e.stopPropagation();

                const $that = $(this);
                const current = self.getCurrent($slideHolder);
                const slideNum = $that.data('item-num');

                $slideList.find('button').removeClass('active');
                $that.addClass('active');

                self.goToSlide(current, slideNum, $slideHolder);
                self.pauseShow(begin);
            });
        });
    }

    return self;
};

export default elrSimpleSlider;<|endoftext|>


<commit_before>/*
 * Copyright 2009-2011 Mozilla Foundation and contributors
 * Licensed under the New BSD license. See LICENSE.txt or:
 * http://opensource.org/licenses/BSD-3-Clause
 */

define(function(require, exports, module) {

  // We need to make sure GCLI is initialized before we begin testing it
  require('gcli/index');

  var examiner = require('test/examiner');

  // It's tempting to want to unify these strings and make addSuite() do the
  // call to require(), however that breaks the build system which looks for
  // the strings passed to require
  examiner.addSuite('gclitest/testTokenize', require('gclitest/testTokenize'));
  examiner.addSuite('gclitest/testSplit', require('gclitest/testSplit'));
  examiner.addSuite('gclitest/testCli', require('gclitest/testCli'));
  examiner.addSuite('gclitest/testExec', require('gclitest/testExec'));
  examiner.addSuite('gclitest/testKeyboard', require('gclitest/testKeyboard'));
  examiner.addSuite('gclitest/testScratchpad', require('gclitest/testScratchpad'));
  examiner.addSuite('gclitest/testHistory', require('gclitest/testHistory'));
  examiner.addSuite('gclitest/testRequire', require('gclitest/testRequire'));
  examiner.addSuite('gclitest/testJs', require('gclitest/testJs'));
  examiner.addSuite('gclitest/testTypes', require('gclitest/testTypes'));

  exports.examiner = examiner;
});
<commit_msg>Bug 720644 (fuzzy): Alpha-sort the tests in the suite Should reduce the time to see if something is there<commit_after>/*
 * Copyright 2009-2011 Mozilla Foundation and contributors
 * Licensed under the New BSD license. See LICENSE.txt or:
 * http://opensource.org/licenses/BSD-3-Clause
 */

define(function(require, exports, module) {

  // We need to make sure GCLI is initialized before we begin testing it
  require('gcli/index');

  var examiner = require('test/examiner');

  // It's tempting to want to unify these strings and make addSuite() do the
  // call to require(), however that breaks the build system which looks for
  // the strings passed to require
  examiner.addSuite('gclitest/testCli', require('gclitest/testCli'));
  examiner.addSuite('gclitest/testExec', require('gclitest/testExec'));
  examiner.addSuite('gclitest/testHistory', require('gclitest/testHistory'));
  examiner.addSuite('gclitest/testJs', require('gclitest/testJs'));
  examiner.addSuite('gclitest/testKeyboard', require('gclitest/testKeyboard'));
  examiner.addSuite('gclitest/testRequire', require('gclitest/testRequire'));
  examiner.addSuite('gclitest/testScratchpad', require('gclitest/testScratchpad'));
  examiner.addSuite('gclitest/testSplit', require('gclitest/testSplit'));
  examiner.addSuite('gclitest/testTokenize', require('gclitest/testTokenize'));
  examiner.addSuite('gclitest/testTypes', require('gclitest/testTypes'));

  exports.examiner = examiner;
});
<|endoftext|>


<commit_before>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2014, Joyent, Inc.
 */

/*
 * Backfill sapi_services bucket after adding index type field
 */

var path = require('path');
var fs = require('fs');
var util = require('util');
var moray = require('moray');
var async = require('async');

var config_file = path.resolve(__dirname, '..', 'etc/config.json');
var bunyan = require('bunyan');

var SERVICES_BUCKET = 'sapi_services';

var config;
try {
    config = JSON.parse(fs.readFileSync(config_file, 'utf8'));
} catch (e) {
    console.error('Error parsing config file JSON:');
    console.dir(e);
    process.exit(1);
}

var log = new bunyan({
    name: 'sapi-backfill',
    streams: [ {
        level: config.logLevel || 'info',
        stream: process.stdout
    }]
});

var morayClient = moray.createClient({
    log: log,
    host: config.moray.host,
    port: config.moray.port,
    retry: (config.retry === false ? false : {
        retries: Infinity,
        minTimeout: 1000,
        maxTimeout: 60000
    })
});

function onConnect() {
    morayClient.removeListener('error', onError);
    log.info('moray: connected %s', morayClient.toString());
    updateBucket(onBucket);
}

function onConnectAttempt(number, delay) {
    var level;
    if (number === 0) {
        level = 'info';
    } else if (number < 5) {
        level = 'warn';
    } else {
        level = 'error';
    }

    log[level]({
        attempt: number,
        delay: delay
    }, 'moray: connection attempted');
}

function onError(err) {
    log.error(err, 'moray: connection failed');
}

morayClient.once('connect', onConnect);
morayClient.once('error', onError);
morayClient.on('connectAttempt', onConnectAttempt);

/*
 * Work is done here
 */

function updateBucket(cb) {
    morayClient.getBucket(SERVICES_BUCKET, function (err, bucket) {
        if (err) {
            cb(err);
            return;
        }

        if (bucket.index.type !== undefined) {
            log.info('"type" index is already added');
            cb();
            return;
        }

        var cfg = {
            index: {
                uuid: { type: 'string', unique: true },
                name: { type: 'string' },
                application_uuid: { type: 'string' },
                type: { type: "string" }
            }
        };
        morayClient.updateBucket(SERVICES_BUCKET, cfg, cb);
    });
}

function listServices(cb) {
    var services = [];
    var req = morayClient.findObjects(SERVICES_BUCKET, '(uuid=*)');

    req.once('error', cb);

    req.on('record', function (object) {
        services.push(object.value);
    });

    return req.once('end', function () {
        cb(null, services);
    });
}

function updateServices(services, cb) {
    async.forEach(services, updateService, cb);
}

function updateService(service, cb) {
    var uuid = service.uuid;

    if (service.type === undefined) {
        service.type = 'vm';
        morayClient.putObject(SERVICES_BUCKET, uuid, service, function (err) {
            if (err) {
                log.error(err, 'Could not update service %s', uuid);
                cb(err);
                return;
            }

            log.info('Service %s has ben updated', uuid);
            cb();
        });
    } else {
        log.info('Service %s already has a type %s', uuid, service.type);
        process.nextTick(cb);
    }
}

function onBucket(bucketErr) {
    if (bucketErr) {
        log.error(bucketErr, 'Could not update bucket');
        process.exit(1);
    }

    listServices(function (err, services) {
        if (err) {
            log.error(err, 'Could not list services');
            process.exit(1);
        }

        updateServices(services, function (updateErr) {
            if (updateErr) {
                log.error(updateErr, 'Could not update services');
                process.exit(1);
            }
            log.info('Services have been updated');
            process.exit(0);
        });
    });
}<commit_msg>SAPI-247: Make sure we fill the correct service types<commit_after>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2014, Joyent, Inc.
 */

/*
 * Backfill sapi_services bucket after adding index type field
 */

var path = require('path');
var fs = require('fs');
var util = require('util');
var moray = require('moray');
var async = require('async');

var config_file = path.resolve(__dirname, '..', 'etc/config.json');
var bunyan = require('bunyan');

var SERVICES_BUCKET = 'sapi_services';

var config;
try {
    config = JSON.parse(fs.readFileSync(config_file, 'utf8'));
} catch (e) {
    console.error('Error parsing config file JSON:');
    console.dir(e);
    process.exit(1);
}

var log = new bunyan({
    name: 'sapi-backfill',
    streams: [ {
        level: config.logLevel || 'info',
        stream: process.stdout
    }]
});

var morayClient = moray.createClient({
    log: log,
    host: config.moray.host,
    port: config.moray.port,
    retry: (config.retry === false ? false : {
        retries: Infinity,
        minTimeout: 1000,
        maxTimeout: 60000
    })
});

function onConnect() {
    morayClient.removeListener('error', onError);
    log.info('moray: connected %s', morayClient.toString());
    updateBucket(onBucket);
}

function onConnectAttempt(number, delay) {
    var level;
    if (number === 0) {
        level = 'info';
    } else if (number < 5) {
        level = 'warn';
    } else {
        level = 'error';
    }

    log[level]({
        attempt: number,
        delay: delay
    }, 'moray: connection attempted');
}

function onError(err) {
    log.error(err, 'moray: connection failed');
}

morayClient.once('connect', onConnect);
morayClient.once('error', onError);
morayClient.on('connectAttempt', onConnectAttempt);

/*
 * Work is done here
 */

function updateBucket(cb) {
    morayClient.getBucket(SERVICES_BUCKET, function (err, bucket) {
        if (err) {
            cb(err);
            return;
        }

        if (bucket.index.type !== undefined) {
            log.info('"type" index is already added');
            cb();
            return;
        }

        var cfg = {
            index: {
                uuid: { type: 'string', unique: true },
                name: { type: 'string' },
                application_uuid: { type: 'string' },
                type: { type: "string" }
            }
        };
        morayClient.updateBucket(SERVICES_BUCKET, cfg, cb);
    });
}

function listServices(cb) {
    var services = [];
    var req = morayClient.findObjects(SERVICES_BUCKET, '(uuid=*)');

    req.once('error', cb);

    req.on('record', function (object) {
        services.push(object.value);
    });

    return req.once('end', function () {
        cb(null, services);
    });
}

function updateServices(services, cb) {
    async.forEach(services, updateService, cb);
}

function updateService(service, cb) {
    var uuid = service.uuid;

    if (service.type === undefined) {
        if (service.name === 'vm-agent' || service.name === 'net-agent') {
            service.type = 'agent';
        } else {
            service.type = 'vm';
        }

        morayClient.putObject(SERVICES_BUCKET, uuid, service,
            { noBucketCache: true }, function (err) {
            if (err) {
                log.error(err, 'Could not update service %s', uuid);
                cb(err);
                return;
            }

            log.info('Service %s has ben updated', uuid);
            cb();
        });
    } else {
        log.info('Service %s already has a type %s', uuid, service.type);
        process.nextTick(cb);
    }
}

function onBucket(bucketErr) {
    if (bucketErr) {
        log.error(bucketErr, 'Could not update bucket');
        process.exit(1);
    }

    listServices(function (err, services) {
        if (err) {
            log.error(err, 'Could not list services');
            process.exit(1);
        }

        updateServices(services, function (updateErr) {
            if (updateErr) {
                log.error(updateErr, 'Could not update services');
                process.exit(1);
            }
            log.info('Services have been updated');
            process.exit(0);
        });
    });
}<|endoftext|>


<commit_before>/*!
 * OS.js - JavaScript Operating System
 *
 * Copyright (c) 2011-2015, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */
(function(Service, Window, Utils, API, VFS, GUI) {
  'use strict';

  /////////////////////////////////////////////////////////////////////////////
  // SERVICE
  /////////////////////////////////////////////////////////////////////////////

  function ArduinoService(args, metadata) {
    Service.apply(this, ['ArduinoService', args, metadata]);

    this.pollingNetwork = false;
    this.pollingInterval = null;
    this.cache = {
      devices: {}
    };
  }

  ArduinoService.prototype = Object.create(Service.prototype);
  ArduinoService.constructor = Service;

  ArduinoService.prototype.destroy = function() {
    var wm = OSjs.Core.getWindowManager();
    if ( wm ) {
      wm.destroyNotificationIcon('_ArduinoNotification');
      wm.destroyNotificationIcon('_ArduinoNetworkNotification');
      wm.destroyNotificationIcon('_ArduinoWIFINotification');
    }

    this.cache = {};
    this.pollingInterval = clearInterval(this._pollingInteval);

    return Service.prototype.destroy.apply(this, arguments);
  };

  ArduinoService.prototype.init = function(settings, metadata, onInited) {
    Service.prototype.init.apply(this, arguments);

    var self = this;
    var wm = OSjs.Core.getWindowManager();

    function showNetworkContextMenu(ev) {
      var mnu = [];
      var devs = self.cache.devices;

      function createSubItem(d, idx) {
        if ( idx > 0 ) {
          mnu.push({title: '
', titleHTML: true});
        }

        mnu.push({
          title: '' + d + '',
          titleHTML: true
        });

        Object.keys(devs[d]).forEach(function(i) {
          mnu.push({
            title: i + ': ' + devs[d][i]
          });
        });
      }

      Object.keys(devs).forEach(function(d, idx) {
        createSubItem(d, idx);
      });

      OSjs.API.createMenu(mnu, ev);
    }

    function showWIFIContextMenu(ev) {
      self.externalCall('iwinfo', {}, function(err, result) {
        var sts = result ? 'connected' : 'disconnected';
        info = result ? result.split(' ') : [];

        var mnu = [
          {titleHTML: true, title: 'Status: ' + sts},
          {titleHTML: true, title: 'AP: ' + String(info[0] || null)},
          {titleHTML: true, title: 'SSID: ' + String(info[1] || null)},
          {titleHTML: true, title: 'Security: ' + String(info[2] || null)},
          {titleHTML: true, title: 'Security: ' + String(info[3] || 0) + ' ' + (info[4] || 'dBm')}
        ];

        OSjs.API.createMenu(mnu, ev);
      });

    }

    function showContextMenu(ev) {
      var mnu = [
        {title: 'Open Settings', onClick: function(ev) {
          API.launch('ApplicationArduinoSettings');
        }}
      ];
      OSjs.API.createMenu(mnu, ev);
    }

    wm.createNotificationIcon('_ArduinoNotification', {
      image: API.getIcon('devices/audio-card.png'),
      title: 'Arduino Device',
      onContextMenu: showContextMenu,
      onClick: showContextMenu
    });

    wm.createNotificationIcon('_ArduinoNetworkNotification', {
      image: API.getIcon('devices/network-wired.png'),
      title: 'Arduino Network Devices',
      onContextMenu: showNetworkContextMenu,
      onClick: showNetworkContextMenu
    });
    wm.createNotificationIcon('_ArduinoWIFINotification', {
      image: API.getIcon('devices/network-wireless.png'),
      title: 'Open Settings',
      onContextMenu: showWIFIContextMenu,
      onClick: showWIFIContextMenu
    });

    this.pollingInterval = setInterval(function() {
      self.pollNetwork();
    }, 15000);

    this.pollNetwork();

    onInited();
  };

  ArduinoService.prototype._onMessage = function(obj, msg, args) {
    if ( msg === 'attention' ) {
      // args.foo
    }
  };

  ArduinoService.prototype.pollNetwork = function() {
    var self = this;

    this.pollingNetwork = true;

    this.cache.devices = {};

    function getArpTable(table, dev) {
      var result = null;
      table.forEach(function(iter) {
        if ( iter.Device === dev ) {
          result = iter;
        }
        return !!result;
      });
      return result;
    };

    this.externalCall('netinfo', {}, function(err, result) {
      var devs = [];
      try {
        devs = Object.keys(result.deviceinfo);
      } catch ( e ) {
        console.warn('Error parsing devices', e);
      }

      devs.forEach(function(dev) {
        var arp =  getArpTable(result.arptable, dev) || {};
        var details = {
          'IP': arp['IP address'] || '',
          'Mask': arp['Mask'] || '',
          'MAC': arp['HW address'] || ''
        };
        self.cache.devices[dev] = details;
      });
    });
  };

  ArduinoService.prototype.externalCall = function(fn, args, cb) {
    this._call(fn, args, function(response) {
      response = response || {};
      if ( response.result ) {
        cb(false, response.result);
      } else {
        cb(response.error || 'No response from device');
      }
    }, function(err) {
      cb('Failed to get response from device: ' + err);
    }, false);
  };

  /////////////////////////////////////////////////////////////////////////////
  // EXPORTS
  /////////////////////////////////////////////////////////////////////////////

  OSjs.Applications = OSjs.Applications || {};
  OSjs.Applications.ArduinoService = OSjs.Applications.ArduinoService || {};
  OSjs.Applications.ArduinoService.Class = ArduinoService;

})(OSjs.Core.Service, OSjs.Core.Window, OSjs.Utils, OSjs.API, OSjs.VFS, OSjs.GUI);
<commit_msg>Updated wifi status icon (#169)<commit_after>/*!
 * OS.js - JavaScript Operating System
 *
 * Copyright (c) 2011-2015, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */
(function(Service, Window, Utils, API, VFS, GUI) {
  'use strict';

  /////////////////////////////////////////////////////////////////////////////
  // SERVICE
  /////////////////////////////////////////////////////////////////////////////

  function ArduinoService(args, metadata) {
    Service.apply(this, ['ArduinoService', args, metadata]);

    this.pollingNetwork = false;
    this.pollingInterval = null;
    this.cache = {
      devices: {}
    };
  }

  ArduinoService.prototype = Object.create(Service.prototype);
  ArduinoService.constructor = Service;

  ArduinoService.prototype.destroy = function() {
    var wm = OSjs.Core.getWindowManager();
    if ( wm ) {
      wm.destroyNotificationIcon('_ArduinoNotification');
      wm.destroyNotificationIcon('_ArduinoNetworkNotification');
      wm.destroyNotificationIcon('_ArduinoWIFINotification');
    }

    this.cache = {};
    this.pollingInterval = clearInterval(this._pollingInteval);

    return Service.prototype.destroy.apply(this, arguments);
  };

  ArduinoService.prototype.init = function(settings, metadata, onInited) {
    Service.prototype.init.apply(this, arguments);

    var self = this;
    var wm = OSjs.Core.getWindowManager();

    function showNetworkContextMenu(ev) {
      var mnu = [];
      var devs = self.cache.devices;

      function createSubItem(d, idx) {
        if ( idx > 0 ) {
          mnu.push({title: '
', titleHTML: true});
        }

        mnu.push({
          title: '' + d + '',
          titleHTML: true
        });

        Object.keys(devs[d]).forEach(function(i) {
          mnu.push({
            title: i + ': ' + devs[d][i]
          });
        });
      }

      Object.keys(devs).forEach(function(d, idx) {
        createSubItem(d, idx);
      });

      OSjs.API.createMenu(mnu, ev);
    }

    function showWIFIContextMenu(ev) {
      self.externalCall('iwinfo', {}, function(err, result) {
        var sts = result ? 'connected' : 'disconnected';
        var info = result ? result.split(' ') : [];

        var mnu = [
          {titleHTML: true, title: 'Status: ' + sts},
          {titleHTML: true, title: 'AP: ' + String(info[0] || null)},
          {titleHTML: true, title: 'SSID: ' + String(info[1] || null)},
          {titleHTML: true, title: 'Security: ' + String(info[2] || null)},
          {titleHTML: true, title: 'Security: ' + String(info[3] || 0) + ' ' + (info[4] || 'dBm')}
        ];

        OSjs.API.createMenu(mnu, ev);
      });

    }

    function showContextMenu(ev) {
      var mnu = [
        {title: 'Open Settings', onClick: function(ev) {
          API.launch('ApplicationArduinoSettings');
        }}
      ];
      OSjs.API.createMenu(mnu, ev);
    }

    wm.createNotificationIcon('_ArduinoNotification', {
      image: API.getIcon('devices/audio-card.png'),
      title: 'Arduino Device',
      onContextMenu: showContextMenu,
      onClick: showContextMenu
    });

    wm.createNotificationIcon('_ArduinoNetworkNotification', {
      image: API.getIcon('devices/network-wired.png'),
      title: 'Arduino Network Devices',
      onContextMenu: showNetworkContextMenu,
      onClick: showNetworkContextMenu
    });
    wm.createNotificationIcon('_ArduinoWIFINotification', {
      image: API.getIcon('devices/network-wireless.png'),
      title: 'Open Settings',
      onContextMenu: showWIFIContextMenu,
      onClick: showWIFIContextMenu
    });

    this.pollingInterval = setInterval(function() {
      self.pollNetwork();
    }, 15000);

    this.pollNetwork();

    onInited();
  };

  ArduinoService.prototype._onMessage = function(obj, msg, args) {
    if ( msg === 'attention' ) {
      // args.foo
    }
  };

  ArduinoService.prototype.pollNetwork = function() {
    var self = this;

    this.pollingNetwork = true;

    this.cache.devices = {};

    function getArpTable(table, dev) {
      var result = null;
      table.forEach(function(iter) {
        if ( iter.Device === dev ) {
          result = iter;
        }
        return !!result;
      });
      return result;
    };

    this.externalCall('netinfo', {}, function(err, result) {
      var devs = [];
      try {
        devs = Object.keys(result.deviceinfo);
      } catch ( e ) {
        console.warn('Error parsing devices', e);
      }

      devs.forEach(function(dev) {
        var arp =  getArpTable(result.arptable, dev) || {};
        var details = {
          'IP': arp['IP address'] || '',
          'Mask': arp['Mask'] || '',
          'MAC': arp['HW address'] || ''
        };
        self.cache.devices[dev] = details;
      });
    });
  };

  ArduinoService.prototype.externalCall = function(fn, args, cb) {
    this._call(fn, args, function(response) {
      response = response || {};
      if ( response.result ) {
        cb(false, response.result);
      } else {
        cb(response.error || 'No response from device');
      }
    }, function(err) {
      cb('Failed to get response from device: ' + err);
    }, false);
  };

  /////////////////////////////////////////////////////////////////////////////
  // EXPORTS
  /////////////////////////////////////////////////////////////////////////////

  OSjs.Applications = OSjs.Applications || {};
  OSjs.Applications.ArduinoService = OSjs.Applications.ArduinoService || {};
  OSjs.Applications.ArduinoService.Class = ArduinoService;

})(OSjs.Core.Service, OSjs.Core.Window, OSjs.Utils, OSjs.API, OSjs.VFS, OSjs.GUI);
<|endoftext|>


<commit_before>/**
 * formula.js
 * Generic JSON Schema form builder
 *
 * Norsk Polarinstutt 2014, http://npolar.no/
 */

angular.module('formula')
	.directive('formula',
	['formulaJsonLoader', 'formulaSchema', 'formulaForm', 'formulaI18n', '$http', '$compile', '$templateCache',
	function(jsonLoader, schema, form, i18n, $http, $compile, $templateCache) {
		return {
			restrict: 'A',
            scope: { data: '=formula' },
			controller: ['$scope', '$attrs', function($scope, $attrs) {
				var controller = this, formBuffer = { pending: false, data: null };

				controller.model    = $scope.data.model || {};
                controller.schema   = $scope.schema = new schema();
                controller.form     = $scope.form = new form($scope.model);

				$scope.template = $scope.data.template || 'default';
				$scope.language = { uri: $scope.data.language || null, code: null };

				function formBuild(formURI) {
					if(!formBuffer.pending || formURI) {
						$scope.schema.then(function(schemaData) {
							if(schemaData) {
								formBuffer.pending = false;
								//controller.model = $scope.data.model = {};
								controller.form = $scope.form = new form(controller.model, formURI);
								$scope.form.build(schemaData, formBuffer.data);
								$scope.form.translate($scope.language.code);
							}
						});
					}
				}

                $scope.$watch('data.form', function(uri) {
                    if(uri) {
                        formBuffer.pending = true;
                        jsonLoader(uri).then(function(data) {
                            formBuffer.data = data;
                            formBuild(uri);
                        });
                    } else {
                        formBuffer.data = null;
                        formBuild(null);
                    }
                });

				$scope.$watch('data.schema', function(uri) {
					if(($scope.schema.uri = uri)) {
						$scope.schema.deref(uri).then(function(schemaData) {
							formBuild();
						});
					}
				});

				$scope.$watch('data.language', function(uri) {
					var code = i18n.code(uri);

					if(uri && !code) {
						i18n.add(uri).then(function(code) {
							$scope.language.code = code;
							$scope.form.translate(code);
						});
					} else {
						$scope.language.code = code;
						$scope.form.translate(code);
					}
				});
			}],
			link: function(scope, element, attrs, controller) {
				var template = angular.element($templateCache.get('default.html'));

				// TODO: Template hot-swapping
				if(attrs.formulaTemplate) {
					var templStr = attrs.formulaTemplate, templElem;
					if(templStr.substr(0, -5) != '.html') {
						templStr += '.html';
					}
					if((templElem = $templateCache.get(templStr))) {
						template = templElem;
					}
				}

				if(element.prop('tagName') == 'FORM') {
					if(!element.children().length) {
						element.append(template.children());
						$compile(element.children())(scope);
					}
				} else {
					var formElem = element.find('form');
					if(!formElem.length) {
						element.prepend(template);
						$compile(element.children())(scope);
					}
				}

				// Watch model changes and inject into controller used by formula directives
				scope.$watch('data.model', function(model) {
					controller.model = model;
				}, true);

			}
		};
	}]);
<commit_msg>Fixed comments for data hot-swapping<commit_after>/**
 * formula.js
 * Generic JSON Schema form builder
 *
 * Norsk Polarinstutt 2014, http://npolar.no/
 */

angular.module('formula')
	.directive('formula',
	['formulaJsonLoader', 'formulaSchema', 'formulaForm', 'formulaI18n', '$http', '$compile', '$templateCache',
	function(jsonLoader, schema, form, i18n, $http, $compile, $templateCache) {
		return {
			restrict: 'A',
            scope: { data: '=formula' },
			controller: ['$scope', '$attrs', function($scope, $attrs) {
				var controller = this, formBuffer = { pending: false, data: null };

				controller.model    = $scope.data.model || {};
                controller.schema   = $scope.schema = new schema();
                controller.form     = $scope.form = new form($scope.model);

				$scope.template = $scope.data.template || 'default';
				$scope.language = { uri: $scope.data.language || null, code: null };

				function formBuild(formURI) {
					if(!formBuffer.pending || formURI) {
						$scope.schema.then(function(schemaData) {
							if(schemaData) {
								formBuffer.pending = false;
								controller.form = $scope.form = new form(controller.model, formURI);
								$scope.form.build(schemaData, formBuffer.data);
								$scope.form.translate($scope.language.code);
							}
						});
					}
				}

				// Enable form definition hot-swapping
                $scope.$watch('data.form', function(uri) {
                    if(uri) {
                        formBuffer.pending = true;
                        jsonLoader(uri).then(function(data) {
                            formBuffer.data = data;
                            formBuild(uri);
                        });
                    } else {
                        formBuffer.data = null;
                        formBuild(null);
                    }
                });

				// Enable schema hot-swapping
				$scope.$watch('data.schema', function(uri) {
					if(($scope.schema.uri = uri)) {
						$scope.schema.deref(uri).then(function(schemaData) {
							formBuild();
						});
					}
				});

				// Enable language hot-swapping
				$scope.$watch('data.language', function(uri) {
					var code = i18n.code(uri);

					if(uri && !code) {
						i18n.add(uri).then(function(code) {
							$scope.language.code = code;
							$scope.form.translate(code);
						});
					} else {
						$scope.language.code = code;
						$scope.form.translate(code);
					}
				});

				// Enable data hot-swapping
				$scope.$watch('data.model', function(model) {
					controller.model = model;
				}, true);
			}],
			link: function(scope, element, attrs, controller) {
				var template = angular.element($templateCache.get('default.html'));

				// TODO: Template hot-swapping
				if(attrs.formulaTemplate) {
					var templStr = attrs.formulaTemplate, templElem;
					if(templStr.substr(0, -5) != '.html') {
						templStr += '.html';
					}
					if((templElem = $templateCache.get(templStr))) {
						template = templElem;
					}
				}

				if(element.prop('tagName') == 'FORM') {
					if(!element.children().length) {
						element.append(template.children());
						$compile(element.children())(scope);
					}
				} else {
					var formElem = element.find('form');
					if(!formElem.length) {
						element.prepend(template);
						$compile(element.children())(scope);
					}
				}
			}
		};
	}]);
<|endoftext|>