<commit_before>/*globals $, PI2, LinearGradient, ColorStop, RGBColor, RAD_TO_DEG, DEG_TO_RAD*/
$(function() {
  'use strict';

  var HALF_PI = 0.5 * Math.PI;

  function normalizeAngle( angle ) {
    angle = angle % PI2;
    return angle >= 0 ? angle : angle + PI2;
  }

  function quadrantOf( angle ) {
    if ( angle < HALF_PI) { return 0; }
    if ( angle < Math.PI ) { return 1; }
    if ( angle < Math.PI + HALF_PI ) { return 2; }
    return 3;
  }

  /**
   * Percent or pixels.
   *
   * These regexps are very liberal in the values they accept. For example, the
   * following values are accepted:
   *
   *  abc10% -> 10%
   *  abc100px -> 100px
   */
  var percentRegex = /\d+\%/,
      pixelRegex   = /\d+px/;

  function unitsOf( string ) {
    if ( percentRegex.test( string ) ) {
      return '%';
    }

    if ( pixelRegex.test( string ) ) {
      return 'px';
    }

    return null;
  }

  var mouse = {
    x: 0,
    y: 0
  };

  var editors = [];

  function Editor( options ) {
    this.$gradient = $( options.id );

    this.$canvas = this.$gradient.find( '#canvas' );
    this.canvas  = this.$canvas[0];
    this.ctx     = this.canvas.getContext( '2d' );

    this.canvas.width  = this.$canvas.parent().width();
    this.canvas.height = this.$canvas.parent().height();

    this.$gradientOffset = this.$gradient.offset();

    this.x = this.$gradientOffset.left + 0.5 * this.$gradient.width();
    this.y = this.$gradientOffset.top  + 0.5 * this.$gradient.height();

    this.gradientAngle = 0;

    this.gradient = new LinearGradient();
    this.gradient.angle = this.gradientAngle + 'deg';
  }

  Editor.prototype.update = function() {
    var $gradient = this.$gradient,
        gradient  = this.gradient;

    var dx = mouse.x - this.x,
        dy = mouse.y - this.y;

    this.gradientAngle = ( normalizeAngle( Math.atan2( dy, dx ) ) * RAD_TO_DEG ).toFixed(0) % 360;
    gradient.angle = this.gradientAngle + 'deg';
    $gradient.css( 'background', gradient.css() );

    // Clean-up.
    $gradient.children( '.colorstop' ).remove();

    var quadrant = quadrantOf( this.gradientAngle * DEG_TO_RAD );

    var colorStopCount = gradient.colorStops.length - 1;
    gradient.colorStops.forEach(function( colorStop, index ) {
      var $colorStop = $( '

' );

      var top, left;
      // TODO: Clean this stuff up!
      // This only handles percentages right now.
      if ( quadrant === 0 || quadrant === 1 ) {
        left = ( index / colorStopCount ) * 100 + '%';

        if ( colorStop.position ) {
          left = colorStop.position;
        }
      }

      if ( quadrant === 1 || quadrant === 2 ) {
        top = ( index / colorStopCount ) * 100 + '%';

        if ( colorStop.position ) {
          top = colorStop.position;
        }
      }

      if ( quadrant === 0 || quadrant === 3 ) {
        top = ( ( colorStopCount - index ) / colorStopCount ) * 100 + '%';

        if ( colorStop.position ) {
          top = ( 100 - parseInt( colorStop.position, 10 ) ) + '%';
        }
      }

      if ( quadrant === 2 || quadrant === 3 ) {
        left = ( ( colorStopCount - index ) / colorStopCount ) * 100 + '%';

        if ( colorStop.position ) {
          left = ( 100 - parseInt( colorStop.position, 10 ) ) + '%';
        }
      }

      if ( gradient.angle === '0deg' || gradient.angle === '180deg' ) {
        left = '50%';
      }

      if ( gradient.angle === '90deg' || gradient.angle === '270deg' ) {
        top = '50%';
      }

      $colorStop.css({
        background: colorStop.css(),
        top:  top,
        left: left,
        transform: 'rotateZ(' + gradient.angle + ')'
      });

      $gradient.append( $colorStop );
    });

    this.drawCanvas();
  };

  Editor.prototype.drawCanvas = function() {
    var canvas = this.canvas,
        ctx    = this.ctx;

    ctx.clearRect( 0, 0, canvas.width, canvas.height );
    ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';
    ctx.shadowBlur = 5;
    ctx.font = '16pt Helvetica, Arial, sans-serif';
    ctx.fillStyle = 'white';
    ctx.fillText( this.gradientAngle, 20, canvas.height - 20 );
  };

  var editor0 = new Editor({
    id: '#gradient-canvas-0'
  });

  editors.push( editor0 );

  editor0.gradient.colorStops.push( new ColorStop( new RGBColor( 255,   0, 128 ) ) );
  editor0.gradient.colorStops.push( new ColorStop( new RGBColor(   0, 255, 255 ), '40%' ) );
  editor0.gradient.colorStops.push( new ColorStop( new RGBColor( 255, 128, 255 ), '80%' ) );
  editor0.gradient.colorStops.push( new ColorStop( new RGBColor(   0,   0, 255 ) ) );

  editor0.update();

  var editor1 = new Editor({
    id: '#gradient-canvas-1'
  });

  editors.push( editor1 );

  editor1.gradient.colorStops.push( new ColorStop( new RGBColor(   0,   0, 128 ) ) );
  editor1.gradient.colorStops.push( new ColorStop( new RGBColor( 255, 255, 255 ), '90px' ) );
  editor1.gradient.colorStops.push( new ColorStop( new RGBColor(   0,   0, 255 ) ) );

  editor1.update();

  function onMouseMove( event ) {
    mouse.x = event.pageX;
    mouse.y = event.pageY;

    editors.forEach(function( editor ) {
      editor.update();
    });
  }

  $( window ).on({
    mousemove: onMouseMove
  });
});
<commit_msg>Add pixel handling in the bg-gradient editor test.<commit_after>/*globals $, PI2, LinearGradient, ColorStop, RGBColor, RAD_TO_DEG, DEG_TO_RAD*/
$(function() {
  'use strict';

  var HALF_PI = 0.5 * Math.PI;

  function normalizeAngle( angle ) {
    angle = angle % PI2;
    return angle >= 0 ? angle : angle + PI2;
  }

  function quadrantOf( angle ) {
    if ( angle < HALF_PI) { return 0; }
    if ( angle < Math.PI ) { return 1; }
    if ( angle < Math.PI + HALF_PI ) { return 2; }
    return 3;
  }

  /**
   * Percent or pixels.
   *
   * These regexps are very liberal in the values they accept. For example, the
   * following values are accepted:
   *
   *  abc10% -> 10%
   *  abc100px -> 100px
   */
  var percentRegex = /(\d+)(\%)/,
      pixelRegex   = /(\d+)(px)/;

  function unitsOf( string ) {
    if ( percentRegex.test( string ) ) {
      return '%';
    }

    if ( pixelRegex.test( string ) ) {
      return 'px';
    }

    return null;
  }

  var mouse = {
    x: 0,
    y: 0
  };

  var editors = [];

  function Editor( options ) {
    this.$gradient = $( options.id );

    this.$canvas = this.$gradient.find( '#canvas' );
    this.canvas  = this.$canvas[0];
    this.ctx     = this.canvas.getContext( '2d' );

    this.canvas.width  = this.$canvas.parent().width();
    this.canvas.height = this.$canvas.parent().height();

    this.$gradientOffset = this.$gradient.offset();

    this.x = this.$gradientOffset.left + 0.5 * this.$gradient.width();
    this.y = this.$gradientOffset.top  + 0.5 * this.$gradient.height();

    this.gradientAngle = 0;

    this.gradient = new LinearGradient();
    this.gradient.angle = this.gradientAngle + 'deg';
  }

  Editor.prototype.update = function() {
    var $gradient = this.$gradient,
        gradient  = this.gradient;

    var dx = mouse.x - this.x,
        dy = mouse.y - this.y;

    this.gradientAngle = ( normalizeAngle( Math.atan2( dy, dx ) ) * RAD_TO_DEG ).toFixed(0) % 360;
    gradient.angle = this.gradientAngle + 'deg';
    $gradient.css( 'background', gradient.css() );

    // Clean-up.
    $gradient.children( '.colorstop' ).remove();

    var gradientAngle = this.gradientAngle,
        quadrant = quadrantOf( gradientAngle * DEG_TO_RAD ),
        colorStopCount = gradient.colorStops.length - 1;

    gradient.colorStops.forEach(function( colorStop, index ) {
      var $colorStop = $( '

' );

      var inPercent, inPixels = false;
      var pixels, xPixels, yPixels;
      if ( unitsOf( colorStop.position ) === 'px' ) {
        inPixels = true;

        pixels = parseInt( colorStop.position, 10 );
        xPixels = Math.abs( pixels * Math.sin( gradientAngle * DEG_TO_RAD ) ).toFixed(0);
        yPixels = Math.abs( pixels * Math.cos( gradientAngle * DEG_TO_RAD ) ).toFixed(0);
      } else {
        inPercent = true;
      }

      var top, left;
      // TODO: Clean this stuff up!
      // This only handles percentages right now.
      if ( quadrant === 0 || quadrant === 1 ) {
        left = ( index / colorStopCount ) * 100 + '%';

        if ( colorStop.position ) {
          left = colorStop.position;
          if ( inPixels ) {
            left = xPixels + 'px';
          }
        }
      }

      if ( quadrant === 1 || quadrant === 2 ) {
        top = ( index / colorStopCount ) * 100 + '%';

        if ( colorStop.position ) {
          top = colorStop.position;
          if ( inPixels ) {
            top = yPixels + 'px';
          }
        }
      }

      if ( quadrant === 0 || quadrant === 3 ) {
        top = ( ( colorStopCount - index ) / colorStopCount ) * 100 + '%';

        if ( colorStop.position ) {
          top = ( 100 - parseInt( colorStop.position, 10 ) ) + '%';
          if ( inPixels ) {
            top = 'calc(100% - ' + yPixels + 'px)';
          }
        }
      }

      if ( quadrant === 2 || quadrant === 3 ) {
        left = ( ( colorStopCount - index ) / colorStopCount ) * 100 + '%';

        if ( colorStop.position ) {
          left = ( 100 - parseInt( colorStop.position, 10 ) ) + '%';
          if ( inPixels ) {
            left = 'calc(100% - ' + xPixels + 'px)';
          }
        }
      }

      if ( gradient.angle === '0deg' || gradient.angle === '180deg' ) {
        left = '50%';
      }

      if ( gradient.angle === '90deg' || gradient.angle === '270deg' ) {
        top = '50%';
      }

      $colorStop.css({
        background: colorStop.css(),
        top:  top,
        left: left,
        transform: 'rotateZ(' + gradient.angle + ')'
      });

      $gradient.append( $colorStop );
    });

    this.drawCanvas();
  };

  Editor.prototype.drawCanvas = function() {
    var canvas = this.canvas,
        ctx    = this.ctx;

    ctx.clearRect( 0, 0, canvas.width, canvas.height );
    ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';
    ctx.shadowBlur = 5;
    ctx.font = '16pt Helvetica, Arial, sans-serif';
    ctx.fillStyle = 'white';
    ctx.fillText( this.gradientAngle, 20, canvas.height - 20 );
  };

  var editor0 = new Editor({
    id: '#gradient-canvas-0'
  });

  editors.push( editor0 );

  editor0.gradient.colorStops.push( new ColorStop( new RGBColor( 255,   0, 128 ) ) );
  editor0.gradient.colorStops.push( new ColorStop( new RGBColor(   0, 255, 255 ), '40%' ) );
  editor0.gradient.colorStops.push( new ColorStop( new RGBColor( 255, 128, 255 ), '80%' ) );
  editor0.gradient.colorStops.push( new ColorStop( new RGBColor(   0,   0, 255 ) ) );

  editor0.update();

  var editor1 = new Editor({
    id: '#gradient-canvas-1'
  });

  editors.push( editor1 );

  editor1.gradient.colorStops.push( new ColorStop( new RGBColor(   0,   0, 128 ) ) );
  editor1.gradient.colorStops.push( new ColorStop( new RGBColor( 255, 255, 255 ), '90px' ) );
  editor1.gradient.colorStops.push( new ColorStop( new RGBColor(   0,   0, 255 ) ) );

  editor1.update();

  function onMouseMove( event ) {
    mouse.x = event.pageX;
    mouse.y = event.pageY;

    editors.forEach(function( editor ) {
      editor.update();
    });
  }

  $( window ).on({
    mousemove: onMouseMove
  });
});
<|endoftext|>


<commit_before>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var AddBlendFS = require('../shaders/AddBlend-frag.js');
var Class = require('../../../utils/Class');
var ColorMatrix = require('../../../display/ColorMatrix');
var ColorMatrixFS = require('../shaders/ColorMatrix-frag.js');
var CopyFS = require('../shaders/Copy-frag.js');
var GetFastValue = require('../../../utils/object/GetFastValue');
var LinearBlendFS = require('../shaders/LinearBlend-frag.js');
var QuadVS = require('../shaders/Quad-vert.js');
var WEBGL_CONST = require('../const');
var WebGLPipeline = require('../WebGLPipeline');

/**
 * @classdesc
 * TODO
 *
 * The fragment shader it uses can be found in `shaders/src/PostFX.frag`.
 * The vertex shader it uses can be found in `shaders/src/PostFX.vert`.
 *
 * The default shader attributes for this pipeline are:
 *
 * `inPosition` (vec2, offset 0)
 * `inTexCoord` (vec2, offset 8)
 *
 * The default shader uniforms for this pipeline are:
 *
 * `uProjectionMatrix` (mat4)
 * `uMainSampler` (sampler2D)
 *
 * @class UtilityPipeline
 * @extends Phaser.Renderer.WebGL.WebGLPipeline
 * @memberof Phaser.Renderer.WebGL.Pipelines
 * @constructor
 * @since 3.50.0
 *
 * @param {Phaser.Types.Renderer.WebGL.WebGLPipelineConfig} config - The configuration options for this pipeline.
 */
var UtilityPipeline = new Class({

    Extends: WebGLPipeline,

    initialize:

    function UtilityPipeline (config)
    {
        config.renderTarget = [
            {
                scale: 1
            },
            {
                scale: 1
            },
            {
                scale: 0.5
            },
            {
                scale: 0.5
            }
        ];
        config.vertShader = QuadVS;
        config.shaders = [
            {
                name: 'Copy',
                fragShader: CopyFS,
                uniforms: [
                    'uMainSampler',
                    'uBrightness'
                ]
            },
            {
                name: 'AddBlend',
                fragShader: AddBlendFS,
                uniforms: [
                    'uMainSampler1',
                    'uMainSampler2',
                    'uStrength'
                ]
            },
            {
                name: 'LinearBlend',
                fragShader: LinearBlendFS,
                uniforms: [
                    'uMainSampler1',
                    'uMainSampler2',
                    'uStrength'
                ]
            },
            {
                name: 'ColorMatrix',
                fragShader: ColorMatrixFS,
                uniforms: [
                    'uMainSampler',
                    'uColorMatrix'
                ]
            }
        ];
        config.attributes = GetFastValue(config, 'attributes', [
            {
                name: 'inPosition',
                size: 2,
                type: WEBGL_CONST.FLOAT
            },
            {
                name: 'inTexCoord',
                size: 2,
                type: WEBGL_CONST.FLOAT
            }
        ]);

        //  x, y, u, v (x/y in NDC)

        config.vertices = new Float32Array([
            -1, -1, 0, 0,
            -1, 1, 0, 1,
            1, 1, 1, 1,
            -1, -1, 0, 0,
            1, 1, 1, 1,
            1, -1, 1, 0
        ]);

        config.batchSize = 1;

        WebGLPipeline.call(this, config);

        this.colorMatrix = new ColorMatrix();

        this.copyShader;
        this.addShader;
        this.linearShader;
        this.colorMatrixShader;

        this.fullFrame1;
        this.fullFrame2;
        this.halfFrame1;
        this.halfFrame2;
    },

    boot: function ()
    {
        WebGLPipeline.prototype.boot.call(this);

        var shaders = this.shaders;
        var targets = this.renderTargets;

        this.copyShader = shaders[0];
        this.addShader = shaders[1];
        this.linearShader = shaders[2];
        this.colorMatrixShader = shaders[3];

        this.fullFrame1 = targets[0];
        this.fullFrame2 = targets[1];
        this.halfFrame1 = targets[2];
        this.halfFrame2 = targets[3];

        console.log(this);
    },

    //  params = RenderTargets
    copyFrame: function (source, target, brightness, clearAlpha)
    {
        if (brightness === undefined) { brightness = 1; }
        if (clearAlpha === undefined) { clearAlpha = true; }

        var gl = this.gl;

        this.set1i('uMainSampler', 0, this.copyShader);
        this.set1f('uBrightness', brightness, this.copyShader);

        if (target)
        {
            gl.viewport(0, 0, target.width, target.height);
        }
        else
        {
            gl.viewport(0, 0, source.width, source.height);
        }

        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, source.texture);

        gl.bindFramebuffer(gl.FRAMEBUFFER, this.fullFrame1.framebuffer);

        if (target)
        {
            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture, 0);
        }

        if (clearAlpha)
        {
            gl.clearColor(0, 0, 0, 0);
        }
        else
        {
            gl.clearColor(0, 0, 0, 1);
        }

        gl.bufferData(gl.ARRAY_BUFFER, this.vertexData, gl.STATIC_DRAW);
        gl.drawArrays(gl.TRIANGLES, 0, 6);

        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
        gl.bindTexture(gl.TEXTURE_2D, null);
    },

    drawFrame: function (source, target)
    {
        var gl = this.gl;

        this.set1i('uMainSampler', 0, this.colorMatrixShader);
        this.set1fv('uColorMatrix', this.colorMatrix.getData(), this.colorMatrixShader);

        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, source.texture);

        // gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer);
        gl.bindFramebuffer(gl.FRAMEBUFFER, null);

        if (target)
        {
            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture, 0);
        }

        // if (clearAlpha)
        // {
            // gl.clearColor(0, 0, 0, 0);
        // }
        // else
        // {
            // gl.clearColor(0, 0, 0, 1);
        // }

        gl.bufferData(gl.ARRAY_BUFFER, this.vertexData, gl.STATIC_DRAW);
        gl.drawArrays(gl.TRIANGLES, 0, 6);

        // gl.bindFramebuffer(gl.FRAMEBUFFER, null);
        gl.bindTexture(gl.TEXTURE_2D, null);
    },

    bindAndDraw: function (source, target)
    {
        var gl = this.gl;

        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, source.texture);

        // gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer);
        gl.bindFramebuffer(gl.FRAMEBUFFER, null);

        if (target)
        {
            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture, 0);
        }

        // if (clearAlpha)
        // {
            // gl.clearColor(0, 0, 0, 0);
        // }
        // else
        // {
            // gl.clearColor(0, 0, 0, 1);
        // }

        gl.bufferData(gl.ARRAY_BUFFER, this.vertexData, gl.STATIC_DRAW);
        gl.drawArrays(gl.TRIANGLES, 0, 6);

        // gl.bindFramebuffer(gl.FRAMEBUFFER, null);
        gl.bindTexture(gl.TEXTURE_2D, null);
    }

});

module.exports = UtilityPipeline;
<commit_msg>Lots of tidying up, added blend methods<commit_after>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var AddBlendFS = require('../shaders/AddBlend-frag.js');
var Class = require('../../../utils/Class');
var ColorMatrix = require('../../../display/ColorMatrix');
var ColorMatrixFS = require('../shaders/ColorMatrix-frag.js');
var CopyFS = require('../shaders/Copy-frag.js');
var GetFastValue = require('../../../utils/object/GetFastValue');
var LinearBlendFS = require('../shaders/LinearBlend-frag.js');
var QuadVS = require('../shaders/Quad-vert.js');
var WEBGL_CONST = require('../const');
var WebGLPipeline = require('../WebGLPipeline');

/**
 * @classdesc
 * TODO
 *
 * The fragment shader it uses can be found in `shaders/src/PostFX.frag`.
 * The vertex shader it uses can be found in `shaders/src/PostFX.vert`.
 *
 * The default shader attributes for this pipeline are:
 *
 * `inPosition` (vec2, offset 0)
 * `inTexCoord` (vec2, offset 8)
 *
 * The default shader uniforms for this pipeline are:
 *
 * `uProjectionMatrix` (mat4)
 * `uMainSampler` (sampler2D)
 *
 * @class UtilityPipeline
 * @extends Phaser.Renderer.WebGL.WebGLPipeline
 * @memberof Phaser.Renderer.WebGL.Pipelines
 * @constructor
 * @since 3.50.0
 *
 * @param {Phaser.Types.Renderer.WebGL.WebGLPipelineConfig} config - The configuration options for this pipeline.
 */
var UtilityPipeline = new Class({

    Extends: WebGLPipeline,

    initialize:

    function UtilityPipeline (config)
    {
        config.renderTarget = [
            {
                scale: 1
            },
            {
                scale: 1
            },
            {
                scale: 0.5
            },
            {
                scale: 0.5
            }
        ];
        config.vertShader = QuadVS;
        config.shaders = [
            {
                name: 'Copy',
                fragShader: CopyFS,
                uniforms: [
                    'uMainSampler',
                    'uBrightness'
                ]
            },
            {
                name: 'AddBlend',
                fragShader: AddBlendFS,
                uniforms: [
                    'uMainSampler1',
                    'uMainSampler2',
                    'uStrength'
                ]
            },
            {
                name: 'LinearBlend',
                fragShader: LinearBlendFS,
                uniforms: [
                    'uMainSampler1',
                    'uMainSampler2',
                    'uStrength'
                ]
            },
            {
                name: 'ColorMatrix',
                fragShader: ColorMatrixFS,
                uniforms: [
                    'uMainSampler',
                    'uColorMatrix'
                ]
            }
        ];
        config.attributes = GetFastValue(config, 'attributes', [
            {
                name: 'inPosition',
                size: 2,
                type: WEBGL_CONST.FLOAT
            },
            {
                name: 'inTexCoord',
                size: 2,
                type: WEBGL_CONST.FLOAT
            }
        ]);

        //  x, y, u, v (x/y in NDC)

        config.vertices = new Float32Array([
            -1, -1, 0, 0,
            -1, 1, 0, 1,
            1, 1, 1, 1,
            -1, -1, 0, 0,
            1, 1, 1, 1,
            1, -1, 1, 0
        ]);

        config.batchSize = 1;

        WebGLPipeline.call(this, config);

        this.colorMatrix = new ColorMatrix();

        this.copyShader;
        this.addShader;
        this.linearShader;
        this.colorMatrixShader;

        this.fullFrame1;
        this.fullFrame2;
        this.halfFrame1;
        this.halfFrame2;
    },

    boot: function ()
    {
        WebGLPipeline.prototype.boot.call(this);

        var shaders = this.shaders;
        var targets = this.renderTargets;

        this.copyShader = shaders[0];
        this.addShader = shaders[1];
        this.linearShader = shaders[2];
        this.colorMatrixShader = shaders[3];

        this.fullFrame1 = targets[0];
        this.fullFrame2 = targets[1];
        this.halfFrame1 = targets[2];
        this.halfFrame2 = targets[3];

        console.log(this);
    },

    //  params = RenderTargets
    copyFrame: function (source, target, brightness, clearAlpha)
    {
        if (brightness === undefined) { brightness = 1; }
        if (clearAlpha === undefined) { clearAlpha = true; }

        var gl = this.gl;

        this.set1i('uMainSampler', 0, this.copyShader);
        this.set1f('uBrightness', brightness, this.copyShader);

        if (target)
        {
            gl.viewport(0, 0, target.width, target.height);
        }
        else
        {
            gl.viewport(0, 0, source.width, source.height);
        }

        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, source.texture);

        if (target)
        {
            gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer);
            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture, 0);
        }

        if (clearAlpha)
        {
            gl.clearColor(0, 0, 0, 0);
        }
        else
        {
            gl.clearColor(0, 0, 0, 1);
        }

        gl.clear(gl.COLOR_BUFFER_BIT);

        gl.bufferData(gl.ARRAY_BUFFER, this.vertexData, gl.STATIC_DRAW);
        gl.drawArrays(gl.TRIANGLES, 0, 6);

        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
        gl.bindTexture(gl.TEXTURE_2D, null);
    },

    drawFrame: function (source, target, clearAlpha, colorMatrix)
    {
        if (clearAlpha === undefined) { clearAlpha = true; }
        if (colorMatrix === undefined) { colorMatrix = this.colorMatrix; }

        var gl = this.gl;

        this.set1i('uMainSampler', 0, this.colorMatrixShader);
        this.set1fv('uColorMatrix', colorMatrix.getData(), this.colorMatrixShader);

        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, source.texture);

        if (target)
        {
            gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer);
            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture, 0);
        }

        if (clearAlpha)
        {
            gl.clearColor(0, 0, 0, 0);
        }
        else
        {
            gl.clearColor(0, 0, 0, 1);
        }

        gl.clear(gl.COLOR_BUFFER_BIT);

        gl.bufferData(gl.ARRAY_BUFFER, this.vertexData, gl.STATIC_DRAW);
        gl.drawArrays(gl.TRIANGLES, 0, 6);

        gl.bindTexture(gl.TEXTURE_2D, null);
    },

    blendFrames: function (source1, source2, target, strength, clearAlpha, blendShader)
    {
        if (strength === undefined) { strength = 1; }
        if (clearAlpha === undefined) { clearAlpha = true; }
        if (blendShader === undefined) { blendShader = this.linearShader; }

        var gl = this.gl;

        this.set1i('uMainSampler1', 0, blendShader);
        this.set1i('uMainSampler2', 1, blendShader);
        this.set1f('uStrength', strength, blendShader);

        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, source1.texture);

        gl.activeTexture(gl.TEXTURE1);
        gl.bindTexture(gl.TEXTURE_2D, source2.texture);

        if (target)
        {
            gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer);
            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture, 0);
            gl.viewport(0, 0, target.width, target.height);
        }
        else
        {
            gl.viewport(0, 0, source1.width, source1.height);
        }

        if (clearAlpha)
        {
            gl.clearColor(0, 0, 0, 0);
        }
        else
        {
            gl.clearColor(0, 0, 0, 1);
        }

        gl.clear(gl.COLOR_BUFFER_BIT);

        gl.bufferData(gl.ARRAY_BUFFER, this.vertexData, gl.STATIC_DRAW);
        gl.drawArrays(gl.TRIANGLES, 0, 6);

        gl.bindTexture(gl.TEXTURE_2D, null);
    }

});

module.exports = UtilityPipeline;
<|endoftext|>


<commit_before>$(function () {
    $('[data-toggle="tooltip"]').tooltip();

    var code = $("#check-code").text();
    var url = $("#pitch-url").text();
    var lastPing = null;
    var lastPingHuman = null;

    $("#run-it").click(function() {
        $.get(url);
    });

    function checkLastPing() {
        $.getJSON("/status/" + code + "/", function(data) {
            if (data.last_ping != lastPing) {
                lastPing = data.last_ping;
                $("#timer").data("timer", data.secs_to_alert);
            }

            var lph = data.last_ping_human;
            if (lph && lph.indexOf("seconds ago") > 0)
                data.last_ping_human = "seconds ago";

            if (data.last_ping_human != lastPingHuman) {
                lastPingHuman = data.last_ping_human;
                $("#last-ping").text(lastPingHuman);
            }
        });
    }

    function updateTimer() {
        var timer = parseInt($("#timer").data("timer"));
        if (timer == 0)
            return;

        var s = timer % 60;
        var m = parseInt(timer / 60) % 60;
        var h = parseInt(timer / 3600);
        $("#timer").text(h + "h " + m + "m " + s + "s");

        $("#timer").data("timer", timer - 1);
    }

    setInterval(checkLastPing, 3000);
    setInterval(updateTimer, 1000);

});<commit_msg>Don't specify schema in Javascript example<commit_after>$(function () {
    $('[data-toggle="tooltip"]').tooltip();

    var code = $("#check-code").text();
    var url = $("#pitch-url").text();
    url = url.replace("http://", "//");

    var lastPing = null;
    var lastPingHuman = null;

    $("#run-it").click(function() {
        $.get(url);
    });

    function checkLastPing() {
        $.getJSON("/status/" + code + "/", function(data) {
            if (data.last_ping != lastPing) {
                lastPing = data.last_ping;
                $("#timer").data("timer", data.secs_to_alert);
            }

            var lph = data.last_ping_human;
            if (lph && lph.indexOf("seconds ago") > 0)
                data.last_ping_human = "seconds ago";

            if (data.last_ping_human != lastPingHuman) {
                lastPingHuman = data.last_ping_human;
                $("#last-ping").text(lastPingHuman);
            }
        });
    }

    function updateTimer() {
        var timer = parseInt($("#timer").data("timer"));
        if (timer == 0)
            return;

        var s = timer % 60;
        var m = parseInt(timer / 60) % 60;
        var h = parseInt(timer / 3600);
        $("#timer").text(h + "h " + m + "m " + s + "s");

        $("#timer").data("timer", timer - 1);
    }

    setInterval(checkLastPing, 3000);
    setInterval(updateTimer, 1000);

});<|endoftext|>


<commit_before>/*
 * Content Widget Tests
 */
(function($){
	var mockEvent, proto = $.mobile.content.prototype;

	module("Content Widget _filterNavigateEvents", {
		setup: function() {
			mockEvent = $.Event( "mock" );
			mockEvent.originalEvent = $.Event( "hashchange" );
		}
	});

	test( "rejects navigate events where the origina event's default is prevented", function(){
		expect( 1 );

		mockEvent.originalEvent.isDefaultPrevented = function() {
			ok( true, "request for default status" );
			return true;
		};

		proto._handleNavigate = function() {
			throw "should not be called when the original event's default is prevented";
		};

		proto._filterNavigateEvents( mockEvent, {} );
	});

	test( "uses the hash in the state when the original event is a hashchange", function() {
		expect( 2 );

		proto._handleNavigate = function( url, state ) {
			equal( url, "foo", "the url is the hash stored in the state" );
			equal( state.hash, url, "hash stored in the state is used as the url" );
		};

		proto._filterNavigateEvents( mockEvent, { state: { hash: "foo" }} );
	});

	test( "uses the url in the state when the original event is NOT a hashchange", function() {
		expect( 2 );

		mockEvent.originalEvent = $.Event( "other" );

		proto._handleNavigate = function( url, state ) {
			equal( url, "bar", "the url is the url stored in the state: " + url );
			equal( state.url, url, "url stored in the state is used as the url: " + state.url );
		};

		proto._filterNavigateEvents( mockEvent, { state: { url: "bar" }} );
	});

	test( "uses the current hash when no url or hash is present", function() {
		expect( 1 );

		proto._handleNavigate = function( url, state ) {
			equal( url, "baz", "the url is the hash stored in the state" );
		};

		proto._getHash = function() {
			return "baz";
		};

		proto._filterNavigateEvents( mockEvent, { state: {}} );
	});

	test( "uses the current url when no hash is present", function() {
		expect( 1 );

		proto._handleNavigate = function( url, state ) {
			equal( url, location.href, "the url is the hash stored in the state" );
		};

		proto._getHash = function() {
			return "";
		};

		proto._filterNavigateEvents( mockEvent, { state: {}} );
	});

	module("Content Widget _handleDialog", {
		setup: function() {
			proto = $.mobile.content.prototype;
		}
	});

	test( "continues backward when the active content isn't a dialog", function() {
		expect( 2 );

		proto._getActiveContent = function() {
			return $( "
" );
		};

		proto._back = function(){
			ok( true, "back called" );
		};

		ok( !proto._handleDialog( {}, {direction: "back"} ), "returns false to prevent action" );
	});

	test( "continues forward when the active content isn't a dialog", function() {
		expect( 2 );

		proto._getActiveContent = function() {
			return $( "
" );
		};

		proto._forward = function(){
			ok( true, "forward called" );
		};

		ok( !proto._handleDialog( {}, {direction: "forward"} ), "returns false to prevent action" );
	});

	test( "extends changePageOptions when current content is a dialog", function() {
		var result, opts = {};

		proto._getActiveContent = function() {
			return $( "
", {"class": "ui-dialog"} );
		};

		proto._getActiveHistory = function() {
			return {
				role: "foo",
				transition: "bar"
			};
		};

		equal( opts.role, undefined );
		equal( opts.transition, undefined );
		equal( opts.reverse, undefined );

		// the pageUrl is returned for use as the target url when the active content is a dialog
		equal( proto._handleDialog( opts, {direction: "back", pageUrl: "baz" } ), "baz" );

		equal( opts.role, "foo" );
		equal( opts.transition, "bar" );
		equal( opts.reverse, true );
	});

	var base = "http://example.com/";

	module("Content Widget _handleDestination", {
		setup: function() {
			proto = $.mobile.content.prototype;
			proto._getHistory = function() {
				return {
					initialDst: "foo",
					stack: []
				};
			};

			proto._getDocumentBase = function() {
				return base;
			};
		}
	});

	test( "skips manipulation and returns the initial content if two is falsey", function() {
		proto._getInitialContent = function() {
			return "initial content";
		};

		equal( "initial content", proto._handleDestination( "" ), "avoids manip" );
	});

	test( "returns an absolute url when the argument is just a hash", function() {
		equal( base + "#foo", proto._handleDestination( "#foo" ) );
	});

	test( "returns the hashless value when the argument is a path", function() {
		equal( "foo/bar", proto._handleDestination( "#foo/bar" ) );
	});

	test( "returns initial content when the url is base plus initial destination", function() {
		var initialContent = $( "
" );

		proto._getHistory = function() {
			return {
				initialDst: "foo",
				stack: [ {url: "will not be equal to initial destination"} ]
			};
		};

		proto._getInitialContent = function() {
			return initialContent;
		};

		equal( initialContent, proto._handleDestination(base + "#" + proto._getHistory().initialDst) );
	});

	module( "Content Widget _recordScroll" );

	test( "does not record scroll position when disabled", function() {
		expect( 0 );

		proto._getActiveHistory = function() {
			ok( false, "_getActiveHistory should never be called" );
		};

		proto._disableRecordScroll();
		proto._recordScroll();
	});

	test( "prefers last scroll when it's larger than the minimum scroll", function() {
		expect( 1 );

		var active = {};

		proto._getActiveHistory = function() {
			return active;
		};

		proto._getMinScroll = function() {
			return 50;
		};

		proto._getScroll = function() {
			return 100;
		};

		proto._enableRecordScroll();
		proto._recordScroll();

		equal( active.lastScroll, 100, "should be equal to _getScroll value" );
	});

	test( "prefers default scroll when current scroll < default scroll", function() {
		expect( 1 );

		var active = {};

		proto._getActiveHistory = function() {
			return active;
		};

		// min scroll
		proto._getMinScroll = function() {
			return 50;
		};

		// current scroll
		proto._getScroll = function() {
			return 25;
		};

		// default scroll
		proto._getDefaultScroll = function() {
			return 1;
		};

		proto._enableRecordScroll();
		proto._recordScroll();

		equal( active.lastScroll, 1, "should be equal to _getScroll value" );
	});

	module( "Content Widget _getExistingPage", {
		setup: function() {
			proto._getNs = function() {
				return "foo-";
			};
		}
	});

	test( "returns the page container child matching the dataUrl first", function() {
		var settings = {
			pageContainer: $( "

" )
		};

		equal(
			proto._getExistingPage( settings, "bar" )[0],
			settings.pageContainer.children()[0],
			"returns the first child of the page container"
		);
	});

	test( "returns the child with the dataUrl id and corrects the data-url attr", function() {
		var result, settings = {
			pageContainer: $( "

" )
		};

		equal( settings.pageContainer.children().first().attr( "data-foo-url" ), undefined );

		result = proto._getExistingPage( settings, "bar" ),

		equal(
			result[0],
			settings.pageContainer.children()[0],
			"returns the first child of the page container"
		);

		equal( result.attr( "data-foo-url"), "bar" );
	});
})(jQuery);
<commit_msg>test fallback to first page url check<commit_after>/*
 * Content Widget Tests
 */
(function($){
	// TODO !! reset the prototype after every test

	var mockEvent, proto = $.mobile.content.prototype;

	module("Content Widget _filterNavigateEvents", {
		setup: function() {
			mockEvent = $.Event( "mock" );
			mockEvent.originalEvent = $.Event( "hashchange" );
		}
	});

	test( "rejects navigate events where the origina event's default is prevented", function(){
		expect( 1 );

		mockEvent.originalEvent.isDefaultPrevented = function() {
			ok( true, "request for default status" );
			return true;
		};

		proto._handleNavigate = function() {
			throw "should not be called when the original event's default is prevented";
		};

		proto._filterNavigateEvents( mockEvent, {} );
	});

	test( "uses the hash in the state when the original event is a hashchange", function() {
		expect( 2 );

		proto._handleNavigate = function( url, state ) {
			equal( url, "foo", "the url is the hash stored in the state" );
			equal( state.hash, url, "hash stored in the state is used as the url" );
		};

		proto._filterNavigateEvents( mockEvent, { state: { hash: "foo" }} );
	});

	test( "uses the url in the state when the original event is NOT a hashchange", function() {
		expect( 2 );

		mockEvent.originalEvent = $.Event( "other" );

		proto._handleNavigate = function( url, state ) {
			equal( url, "bar", "the url is the url stored in the state: " + url );
			equal( state.url, url, "url stored in the state is used as the url: " + state.url );
		};

		proto._filterNavigateEvents( mockEvent, { state: { url: "bar" }} );
	});

	test( "uses the current hash when no url or hash is present", function() {
		expect( 1 );

		proto._handleNavigate = function( url, state ) {
			equal( url, "baz", "the url is the hash stored in the state" );
		};

		proto._getHash = function() {
			return "baz";
		};

		proto._filterNavigateEvents( mockEvent, { state: {}} );
	});

	test( "uses the current url when no hash is present", function() {
		expect( 1 );

		proto._handleNavigate = function( url, state ) {
			equal( url, location.href, "the url is the hash stored in the state" );
		};

		proto._getHash = function() {
			return "";
		};

		proto._filterNavigateEvents( mockEvent, { state: {}} );
	});

	module("Content Widget _handleDialog", {
		setup: function() {
			proto = $.mobile.content.prototype;
		}
	});

	test( "continues backward when the active content isn't a dialog", function() {
		expect( 2 );

		proto._getActiveContent = function() {
			return $( "
" );
		};

		proto._back = function(){
			ok( true, "back called" );
		};

		ok( !proto._handleDialog( {}, {direction: "back"} ), "returns false to prevent action" );
	});

	test( "continues forward when the active content isn't a dialog", function() {
		expect( 2 );

		proto._getActiveContent = function() {
			return $( "
" );
		};

		proto._forward = function(){
			ok( true, "forward called" );
		};

		ok( !proto._handleDialog( {}, {direction: "forward"} ), "returns false to prevent action" );
	});

	test( "extends changePageOptions when current content is a dialog", function() {
		var result, opts = {};

		proto._getActiveContent = function() {
			return $( "
", {"class": "ui-dialog"} );
		};

		proto._getActiveHistory = function() {
			return {
				role: "foo",
				transition: "bar"
			};
		};

		equal( opts.role, undefined );
		equal( opts.transition, undefined );
		equal( opts.reverse, undefined );

		// the pageUrl is returned for use as the target url when the active content is a dialog
		equal( proto._handleDialog( opts, {direction: "back", pageUrl: "baz" } ), "baz" );

		equal( opts.role, "foo" );
		equal( opts.transition, "bar" );
		equal( opts.reverse, true );
	});

	var base = "http://example.com/";

	module("Content Widget _handleDestination", {
		setup: function() {
			proto = $.mobile.content.prototype;
			proto._getHistory = function() {
				return {
					initialDst: "foo",
					stack: []
				};
			};

			proto._getDocumentBase = function() {
				return base;
			};
		}
	});

	test( "skips manipulation and returns the initial content if two is falsey", function() {
		proto._getInitialContent = function() {
			return "initial content";
		};

		equal( "initial content", proto._handleDestination( "" ), "avoids manip" );
	});

	test( "returns an absolute url when the argument is just a hash", function() {
		equal( base + "#foo", proto._handleDestination( "#foo" ) );
	});

	test( "returns the hashless value when the argument is a path", function() {
		equal( "foo/bar", proto._handleDestination( "#foo/bar" ) );
	});

	test( "returns initial content when the url is base plus initial destination", function() {
		var initialContent = $( "
" );

		proto._getHistory = function() {
			return {
				initialDst: "foo",
				stack: [ {url: "will not be equal to initial destination"} ]
			};
		};

		proto._getInitialContent = function() {
			return initialContent;
		};

		equal( initialContent, proto._handleDestination(base + "#" + proto._getHistory().initialDst) );
	});

	module( "Content Widget _recordScroll" );

	test( "does not record scroll position when disabled", function() {
		expect( 0 );

		proto._getActiveHistory = function() {
			ok( false, "_getActiveHistory should never be called" );
		};

		proto._disableRecordScroll();
		proto._recordScroll();
	});

	test( "prefers last scroll when it's larger than the minimum scroll", function() {
		expect( 1 );

		var active = {};

		proto._getActiveHistory = function() {
			return active;
		};

		proto._getMinScroll = function() {
			return 50;
		};

		proto._getScroll = function() {
			return 100;
		};

		proto._enableRecordScroll();
		proto._recordScroll();

		equal( active.lastScroll, 100, "should be equal to _getScroll value" );
	});

	test( "prefers default scroll when current scroll < default scroll", function() {
		expect( 1 );

		var active = {};

		proto._getActiveHistory = function() {
			return active;
		};

		// min scroll
		proto._getMinScroll = function() {
			return 50;
		};

		// current scroll
		proto._getScroll = function() {
			return 25;
		};

		// default scroll
		proto._getDefaultScroll = function() {
			return 1;
		};

		proto._enableRecordScroll();
		proto._recordScroll();

		equal( active.lastScroll, 1, "should be equal to _getScroll value" );
	});

	module( "Content Widget _getExistingPage", {
		setup: function() {
			proto._getNs = function() {
				return "foo-";
			};
		}
	});

	test( "returns the page container child matching the dataUrl first", function() {
		var settings = {
			pageContainer: $( "

" )
		};

		equal(
			proto._getExistingPage( settings, "bar" )[0],
			settings.pageContainer.children()[0],
			"returns the first child of the page container"
		);
	});

	test( "returns the child with the dataUrl id and corrects the data-url attr", function() {
		var result, settings = {
			pageContainer: $( "

" )
		};

		equal( settings.pageContainer.children().first().attr( "data-foo-url" ), undefined );

		result = proto._getExistingPage( settings, "bar" ),

		equal(
			result[0],
			settings.pageContainer.children()[0],
			"returns the first child of the page container"
		);

		equal( result.attr( "data-foo-url"), "bar" );
	});

	test( "returns the child with the dataUrl id and corrects the data-url attr", function() {
		var settings = {
			pageContainer: $( "

" )
		};

		proto._getInitialContent = function() {
			return $( "

" ).children().first();
		};

		// using location.href as the fileUrl param ensures that path.isFirstPageUrl returns true
		ok( proto._getExistingPage(settings, "bar", location.href ).is("#initial") );
	});
})(jQuery);
<|endoftext|>


<commit_before>/**
 * DataTables internal date sorting replies on `Date.parse()` which is part of
 * the Javascript language, but you may wish to sort on dates which is doesn't
 * recognise. The following is a plug-in for sorting dates in the format
 * `dd/mm/yy`.
 *
 * An automatic type detection plug-in is available for this sorting plug-in.
 *
 *  @name Date (dd/mm/YY)
 *  @summary Sort dates in the format `dd/mm/YY`
 *  @author Andy McMaster
 *
 *  @example
 *    $('#example').dataTable( {
 *       columnDefs: [
 *         { type: 'date-uk', targets: 0 }
 *       ]
 *    } );
 */

 jQuery.extend( jQuery.fn.dataTableExt.oSort, {
	"date-uk-pre": function ( a ) {
		var ukDatea = a.split('/');
		return (ukDatea[2] + ukDatea[1] + ukDatea[0]) * 1;
	},

	"date-uk-asc": function ( a, b ) {
		return ((a < b) ? -1 : ((a > b) ? 1 : 0));
	},

	"date-uk-desc": function ( a, b ) {
		return ((a < b) ? 1 : ((a > b) ? -1 : 0));
	}
} );
<commit_msg>Handle blank values<commit_after>/**
 * DataTables internal date sorting replies on `Date.parse()` which is part of
 * the Javascript language, but you may wish to sort on dates which is doesn't
 * recognise. The following is a plug-in for sorting dates in the format
 * `dd/mm/yy`.
 *
 * An automatic type detection plug-in is available for this sorting plug-in.
 *
 *  @name Date (dd/mm/YY)
 *  @summary Sort dates in the format `dd/mm/YY`
 *  @author Andy McMaster
 *
 *  @example
 *    $('#example').dataTable( {
 *       columnDefs: [
 *         { type: 'date-uk', targets: 0 }
 *       ]
 *    } );
 */

 jQuery.extend( jQuery.fn.dataTableExt.oSort, {
	"date-uk-pre": function ( a ) {
		if (a == null || a == "") return 1;
		var ukDatea = a.split('/');
		return (ukDatea[2] + ukDatea[1] + ukDatea[0]) * 1;
	},

	"date-uk-asc": function ( a, b ) {
		return ((a < b) ? -1 : ((a > b) ? 1 : 0));
	},

	"date-uk-desc": function ( a, b ) {
		return ((a < b) ? 1 : ((a > b) ? -1 : 0));
	}
} );
<|endoftext|>


<commit_before><commit_msg>Remove obsolete webpack define<commit_after><|endoftext|>


<commit_before>(function($){

	/* ---------------------------------- *\
					瀑 布 流
	\* ---------------------------------- */

	var sample_code, gridNumber, jdata_stored, dataNumber;
	var currentGrid = 0;
	var add_running = 0;

	$.fn.initialize = function( framework, options, jdata, callback_func ) {

		sample_code = '
' + framework + '
';
		dataNumber = jdata['data'].length;

		var settings = $.extend({
			gridNumber: 20,
			columnNumber: 1,
			margin_left: '0px',
			margin_right: '0px',
			color: 'black'
		}, options);

		gridNumber = settings.gridNumber;

		for( var i = 0; i < settings.columnNumber; i++ ) {
			this.append( '

' );
		}

		this.find('.outline').css({
			'float': 'left',
			'margin-left': settings.margin_left,
			'margin-right': settings.margin_right,
			'color': settings.color,
			'width': ( this.width() - ( parseInt(settings.margin_left) + parseInt(settings.margin_right) +4 ) *settings.columnNumber ) / settings.columnNumber
		});

		setContent( jdata, callback_func );
		jdata_stored = jdata;

	};

	$.fn.giveMeMore = function( more_callback ) {

		var plugin_status = 0;

		if( add_running == 0 ) {

			if( currentGrid +1 < jdata_stored['data'].length ) {

				add_running = 1;

				currentGrid++;
				var limitNum = currentGrid  + gridNumber;
				for( var i = currentGrid; i < limitNum; i++ ) {

					if( typeof jdata_stored['data'][i] != "undefined" ) {

						createGrid( i, jdata_stored, 'down' );
						currentGrid = i;

					} else {
						// 這一輪跑到一半就用光了
						plugin_status = 1;
						break;
					}

					if( i+1 == limitNum ) {
						// 這一輪全部跑完 nice!
						plugin_status = 2;
					}

				}

			} else {
				// 已經用光了 別在摳了>///<
				plugin_status = 3;
			}

		} else {
			// plugin is working~~~~
			plugin_status = 4;
		}

		switch( plugin_status ) {
			case 1:
					add_running = 0;
					if( more_callback != null )
						more_callback();
					return "oh_no";
				break;
			case 2:
					add_running = 0;
					if( more_callback != null )
						more_callback();
					return "finish";
				break;
			case 3:
					return "no_more_data";
				break;
			case 4:
					return "running";
				break;
			default:
				break;
		}

	};

	$.fn.addNewGrid = function( jdata, callback_func ) {

		createGrid( 0, jdata, 'up' );

		if( callback_func != null )
			callback_func();

	};

	function setContent( jdata, callback_func ) {

		for( var i = currentGrid; i < gridNumber; i++ ) {
			if( typeof jdata['data'][i] != "undefined" ) {
				createGrid( i, jdata, 'down' );
				currentGrid = i;
			}
		}

		if( callback_func != null )
			callback_func();

	}

	function createGrid( i, data, direction ) {

		var shortest = getShortest();
		var thisCode = sample_code;

		for( var j = 0; j < dataNumber; j++ ) {
			thisCode = thisCode.replace( 'fallwall_#'+(j+1), data['data'][i][j] );
		}

		if( direction == 'down' ) {
			$('.outline').eq( shortest ).append( thisCode );
			var creatingElement = $('.outline').eq( shortest ).find('.grid').last();
		} else {
			$('.outline').eq( shortest ).prepend( thisCode );
			var creatingElement = $('.outline').eq( shortest ).find('.grid').first();
		}

	}

	function getShortest() {

		var heightArray = [];

		$.each( $('.outline'), function(){
			heightArray.push( parseInt( $(this).height() ) );
		});

		var min_of_array = Math.min.apply( null, heightArray );
		return $.inArray( min_of_array, heightArray );

	}

}(jQuery));

<commit_msg>Add enterAnimation option<commit_after>(function($){

	/* ---------------------------------- *\
					瀑 布 流
	\* ---------------------------------- */

	var settings, sample_code, jdata_stored, dataNumber, fatherBox;
	var currentGrid = 0;
	var its_running = 0;

	$.fn.initialize = function( framework, options, jdata, callback_func ) {

		sample_code = '
' + framework + '
';
		dataNumber = jdata['data'].length;
		fatherBox = this;

		settings = $.extend({
			gridNumber: 20,
			columnNumber: 1,
			margin_left: '0px',
			margin_right: '0px',
			color: 'black',
			enterAnimation: 'animated zoomIn'
		}, options);

		for( var i = 0; i < settings.columnNumber; i++ ) {
			this.append( '

' );
		}

		this.find('.outline').css({
			'float': 'left',
			'margin-left': settings.margin_left,
			'margin-right': settings.margin_right,
			'color': settings.color,
			'width': ( this.width() - ( parseInt(settings.margin_left) + parseInt(settings.margin_right) +4 ) *settings.columnNumber ) / settings.columnNumber
		});

		setContent( jdata, callback_func );
		jdata_stored = jdata;

	};

	$.fn.giveMeMore = function( more_callback ) {

		var plugin_status = 0;

		if( its_running == 0 ) {

			if( currentGrid +1 < jdata_stored['data'].length ) {

				its_running = 1;

				currentGrid++;
				var limitNum = currentGrid  + settings.gridNumber;
				for( var i = currentGrid; i < limitNum; i++ ) {

					if( typeof jdata_stored['data'][i] != "undefined" ) {

						createGrid( i, jdata_stored, 'down' );
						currentGrid = i;

					} else {
						// 這一輪跑到一半就用光了
						plugin_status = 1;
						break;
					}

					if( i+1 == limitNum ) {
						// 這一輪全部跑完 nice!
						plugin_status = 2;
					}

				}

			} else {
				// 已經用光了 別在摳了>///<
				plugin_status = 3;
			}

		} else {
			// plugin is working~~~~
			plugin_status = 4;
		}

		switch( plugin_status ) {
			case 1:
					its_running = 0;
					if( more_callback != null )
						more_callback();
					return "oh_no";
				break;
			case 2:
					its_running = 0;
					if( more_callback != null )
						more_callback();
					return "finish";
				break;
			case 3:
					return "no_more_data";
				break;
			case 4:
					return "running";
				break;
			default:
				break;
		}

	};

	$.fn.addNewGrid = function( jdata, callback_func ) {

		createGrid( 0, jdata, 'up' );

		if( callback_func != null )
			callback_func();

	};

	function setContent( jdata, callback_func ) {

		for( var i = currentGrid; i < settings.gridNumber; i++ ) {
			if( typeof jdata['data'][i] != "undefined" ) {
				createGrid( i, jdata, 'down' );
				currentGrid = i;
			}
		}

		fatherBox.append('
');

		if( callback_func != null )
			callback_func();

	}

	function createGrid( i, data, direction ) {

		var shortest = getShortest();
		var thisCode = sample_code;

		for( var j = 0; j < dataNumber; j++ ) {
			thisCode = thisCode.replace( 'fallwall_#'+(j+1), data['data'][i][j] );
		}

		if( direction == 'down' ) {
			$('.outline').eq( shortest ).append( thisCode );
			var creatingElement = $('.outline').eq( shortest ).find('.grid').last();
		} else {
			$('.outline').eq( shortest ).prepend( thisCode );
			var creatingElement = $('.outline').eq( shortest ).find('.grid').first();
		}

		if( settings.enterAnimation != '' )
			creatingElement.addClass( settings.enterAnimation );

	}

	// get the shortest 'outline' div
	function getShortest() {

		var heightArray = [];

		$.each( $('.outline'), function(){
			heightArray.push( parseInt( $(this).height() ) );
		});

		var min_of_array = Math.min.apply( null, heightArray );
		return $.inArray( min_of_array, heightArray );

	}

}(jQuery));

<|endoftext|>


<commit_before><commit_msg>Complete 7.5 challenge and add reflection<commit_after><|endoftext|>


<commit_before>/*
 * Cordova Device Name Plugin
 *
 * ZeroConf plugin for Cordova/Phonegap
 * by Sylvain Brejeon
 */

var argscheck = require('cordova/argscheck');
var channel = require('cordova/channel');
var utils = require('cordova/utils');
var exec = require('cordova/exec');
var cordova = require('cordova');

channel.createSticky('onDeviceNameReady');
// Tell cordova channel to wait on the DeviceNameReady event
channel.waitForInitialization('onDeviceNameReady');

function DeviceName() {
    this.name = null;
    var me = this;
    channel.onCordovaReady.subscribe(function() {
        me.get(function(info) {
            me.name = info.name;
            channel.onDeviceNameReady.fire();
        }, function(e) {
            utils.alert("[ERROR] Error initializing Cordova: " + e);
        });
    });
}

DeviceName.prototype.get = function(successCallback, errorCallback) {
    argscheck.checkArgs('fF', 'DeviceName.get', arguments);
    exec(successCallback, errorCallback, "DeviceName", "get", []);
};

module.exports = new DeviceName();
<commit_msg>Fix: Make source of error clear in the message<commit_after>/*
 * Cordova Device Name Plugin
 *
 * ZeroConf plugin for Cordova/Phonegap
 * by Sylvain Brejeon
 */

var argscheck = require('cordova/argscheck');
var channel = require('cordova/channel');
var utils = require('cordova/utils');
var exec = require('cordova/exec');
var cordova = require('cordova');

channel.createSticky('onDeviceNameReady');
// Tell cordova channel to wait on the DeviceNameReady event
channel.waitForInitialization('onDeviceNameReady');

function DeviceName() {
    this.name = null;
    var me = this;
    channel.onCordovaReady.subscribe(function() {
        me.get(function(info) {
            me.name = info.name;
            channel.onDeviceNameReady.fire();
        }, function(e) {
            utils.alert("[DeviceName] Error initializing Cordova: " + e);
        });
    });
}

DeviceName.prototype.get = function(successCallback, errorCallback) {
    argscheck.checkArgs('fF', 'DeviceName.get', arguments);
    exec(successCallback, errorCallback, "DeviceName", "get", []);
};

module.exports = new DeviceName();
<|endoftext|>


<commit_before>var core_services = [
	{
		"name": "urac",
		"extKeyRequired": true,
		"port": 4001,
		"apis": [
			{
				"l": "Change Email",
				"group": "My Account",
				'v': "/account/changeEmail"
			},
			{
				"l": "Change Password",
				"group": "My Account",
				'v': "/account/changePassword"
			},
			{
				"l": "Edit Profile",
				"group": "My Account",
				'v': "/account/editProfile"
			},
			{
				"l": "Get User Info",
				"group": "My Account",
				"groupMain": true,
				'v': "/account/getUser"
			},
			{
				"l": "Add new User",
				"group": "Administration",
				'v': "/admin/addUser"
			},
			{
				"l": "Change User Status",
				"group": "Administration",
				'v': "/admin/changeUserStatus"
			},
			{
				"l": "Edit User Record",
				"group": "Administration",
				'v': "/admin/editUser"
			},
			{
				"l": "Add new Group",
				"group": "Administration",
				'v': "/admin/group/add"
			},
			{
				"l": "Add Users to Group",
				"group": "Administration",
				'v': "/admin/group/addUsers"
			},
			{
				"l": "Delete Group",
				"group": "Administration",
				'v': "/admin/group/delete"
			},
			{
				"l": "Edit Group",
				"group": "Administration",
				'v': "/admin/group/edit"
			},
			{
				"l": "List Groups",
				"group": "Administration",
				'v': "/admin/group/list"
			},
			{
				"l": "List Users",
				"group": "Administration",
				"groupMain": true,
				'v': "/admin/listUsers"
			},
			{
				"l": "Edit Multiple Groups",
				"group": "Administration",
				'v': "/admin/user/editGroups"
			},
			{
				"l": "Validate Change Email",
				"group": "Guest",
				'v': "/changeEmail/validate"
			},
			{
				"l": "Forgot Password",
				"group": "Guest",
				'v': "/forgotPassword"
			},
			{
				"l": "Register",
				"group": "Guest",
				'v': "/join"
			},
			{
				"l": "Validate Register",
				"group": "Guest",
				'v': "/join/validate"
			},
			{
				"l": "Login",
				"group": "Guest",
				"groupMain": true,
				'v': "/login"
			},
			{
				"l": "Logout",
				"group": "Guest",
				'v': "/logout"
			},
			{
				"l": "Reset Password",
				"group": "Guest",
				'v': "/resetPassword"
			}
		]
	},
	{
		"name": "oauth",
		"extKeyRequired": true,
		"port": 4002,
		"apis": [
			{
				"l": "Create Token",
				'v': "/token",
				"groupMain": true
			},
			{
				"l": "Kill Token",
				'v': "/kill"
			}
		]

	},
	{
		"name": "dashboard",
		"extKeyRequired": true,
		"port": 4003,
		"apis": [
			{
				'l': "List Environments",
				'v': "/environment/list",
				"group": "Environment",
				"groupMain": true
			},
			{
				'l': "Add Environment",
				'v': "/environment/add",
				"group": "Environment"
			},
			{
				'l': "Delete Environment",
				'v': "/environment/delete",
				"group": "Environment"
			},
			{
				'l': "Update Environment",
				'v': "/environment/update",
				"group": "Environment"
			},
			{
				'l': "Update Product",
				'v': "/product/update",
				"group": "Product"
			},
			{
				'l': "Add Product",
				'v': "/product/add",
				"group": "Product"
			},
			{
				'l': "Delete Product",
				'v': "/product/delete",
				"group": "Product"
			},
			{
				'l': "List Products",
				'v': "/product/list",
				"group": "Product",
				"groupMain": true
			},
			{
				'l': "Get Product",
				'v': "/product/get",
				"group": "Product"
			},

			{
				'l': "Add Product Package",
				'v': "/product/packages/add",
				"group": "Product"
			},
			{
				"l": "Delete Product Package",
				"group": "Product",
				'v': "/product/packages/delete"
			},

			{
				"l": "List Product Packages",
				"group": "Product",
				'v': "/product/packages/list"
			},
			{
				"l": "Update Product Package",
				"group": "Product",
				'v': "/product/packages/update"
			},
			{
				"l": "List Tenants",
				"group": "Tenant",
				"groupMain": true,
				'v': "/tenant/list"
			},
			{
				"l": "Get Tenant Info",
				"group": "Tenant",
				'v': "/tenant/get"
			},

			{
				"l": "Add Tenant",
				"group": "Tenant",
				'v': "/tenant/add"
			},
			{
				"l": "Update Tenant",
				"group": "Tenant",
				'v': "/tenant/update"
			},
			{
				"l": "List Tenant Applications",
				"group": "Tenant Application",
				'v': "/tenant/application/list",
				"groupMain": true
			},
			{
				"l": "Add Tenant Application",
				"group": "Tenant Application",
				'v': "/tenant/application/add"
			},

			{
				"l": "Update Tenant Application",
				"group": "Tenant Application",
				'v': "/tenant/application/update"
			},
			{
				"l": "Delete Tenant",
				"group": "Tenant",
				'v': "/tenant/delete"
			},
			{
				"l": "Delete Tenant Application",
				"group": "Tenant Application",
				'v': "/tenant/application/delete"
			},

			{
				"l": "Add Tenant Application Key",
				"group": "Tenant Application",
				'v': "/tenant/application/key/add"
			},
			{
				"l": "List Application Key Configuration",
				"group": "Tenant Application",
				'v': "/tenant/application/key/config/list"
			},

			{
				"l": "Update Application Key Configuration",
				"group": "Tenant Application",
				'v': "/tenant/application/key/config/update"
			},

			{
				"l": "Delete Application Key",
				"group": "Tenant Application",
				'v': "/tenant/application/key/delete"
			},
			{
				"l": "Add Application External Key",
				"group": "Tenant Application",
				'v': "/tenant/application/key/ext/add"
			},
			{
				"l": "Delete Application External Key",
				"group": "Tenant Application",
				'v': "/tenant/application/key/ext/delete"
			},
			{
				"l": "List Application External Keys",
				"group": "Tenant Application",
				'v': "/tenant/application/key/ext/list"
			},
			{
				"l": "Update Application External Key",
				"group": "Tenant Application",
				'v': "/tenant/application/key/ext/update"
			},
			{
				"l": "List Application Keys",
				"group": "Tenant Application",
				'v': "/tenant/application/key/list"
			},
			{
				"l": "List Tenant oAuth Users",
				"group": "Tenant oAuth",
				"groupMain": true,
				'v': "/tenant/oauth/users/list"
			},
			{
				"l": "Add Tenant oAuth Configuration",
				"group": "Tenant oAuth",
				'v': "/tenant/oauth/add"
			},
			{
				"l": "Delete Tenant oAuth Configuration",
				"group": "Tenant oAuth",
				'v': "/tenant/oauth/delete"
			},
			{
				"l": "Get Tenant oAuth Configuration",
				"group": "Tenant oAuth",
				'v': "/tenant/oauth/list"
			},
			{
				"l": "Update Tenant oAuth Configuration",
				"group": "Tenant oAuth",
				'v': "/tenant/oauth/update"
			},
			{
				"l": "Add Tenant oAuth User",
				"group": "Tenant oAuth",
				'v': "/tenant/oauth/users/add"
			},
			{
				"l": "Delete Tenant oAuth User",
				"group": "Tenant oAuth",
				'v': "/tenant/oauth/users/delete"
			},
			{
				"l": "Update Tenant oAuth User",
				"group": "Tenant oAuth",
				'v': "/tenant/oauth/users/update"
			},
			{
				"l": "List Hosts",
				"group": "Hosts",
				'v': "/hosts/list",
				"groupMain": true
			},
			{
				"l": "List Services",
				"group": "Services",
				'v': "/services/list",
				"groupMain": true
			}
		]
	},
	{
		"name": "example01",
		"extKeyRequired": false,
		"port": 4010,
		"apis": [
			{
				"l": "Test Get",
				'v': "/testGet",
				"groupMain": true
			},
			{
				"l": "Test Delete",
				'v': "/testDel"
			},
			{
				'l': 'Build Name',
				'v': '/buildName'
			},
			{
				'l': 'Test Post',
				'v': '/testPost'
			},
			{
				'l': 'Test Put',
				'v': '/testPut'
			}
		]
	},
	{
		"name": "example02",
		"extKeyRequired": true,
		"port": 4011,
		"apis": [
			{
				'l': 'Build Name',
				'v': '/buildName',
				"groupMain": true
			}
		]
	},
	{
		"name": "example03",
		"extKeyRequired": true,
		"port": 4012,
		"apis": [
			{
				"l": "Test Get",
				'v': "/testGet",
				"groupMain": true
			},
			{
				'l': 'Build Name',
				'v': '/buildName'
			}
		]
	},
	{
		"name": "example04",
		"extKeyRequired": true,
		"port": 4013,
		"apis": [
			{
				'l': 'Build Name',
				'v': '/buildName',
				"groupMain": true
			},
			{
				"l": "Build Name Gold",
				'v': "/buildNameGold"
			},
			{
				"l": "Test Get",
				'v': "/testGet"
			}
		]
	}
];

var core_hosts = [
	{
		"env": "dev",
		"name": "tony",
		"ip": "127.0.0.1"
	}
];<commit_msg>added new api to dashboard apis list<commit_after>var core_services = [
	{
		"name": "urac",
		"extKeyRequired": true,
		"port": 4001,
		"apis": [
			{
				"l": "Change Email",
				"group": "My Account",
				'v': "/account/changeEmail"
			},
			{
				"l": "Change Password",
				"group": "My Account",
				'v': "/account/changePassword"
			},
			{
				"l": "Edit Profile",
				"group": "My Account",
				'v': "/account/editProfile"
			},
			{
				"l": "Get User Info",
				"group": "My Account",
				"groupMain": true,
				'v': "/account/getUser"
			},
			{
				"l": "Add new User",
				"group": "Administration",
				'v': "/admin/addUser"
			},
			{
				"l": "Change User Status",
				"group": "Administration",
				'v': "/admin/changeUserStatus"
			},
			{
				"l": "Edit User Record",
				"group": "Administration",
				'v': "/admin/editUser"
			},
			{
				"l": "Add new Group",
				"group": "Administration",
				'v': "/admin/group/add"
			},
			{
				"l": "Add Users to Group",
				"group": "Administration",
				'v': "/admin/group/addUsers"
			},
			{
				"l": "Delete Group",
				"group": "Administration",
				'v': "/admin/group/delete"
			},
			{
				"l": "Edit Group",
				"group": "Administration",
				'v': "/admin/group/edit"
			},
			{
				"l": "List Groups",
				"group": "Administration",
				'v': "/admin/group/list"
			},
			{
				"l": "List Users",
				"group": "Administration",
				"groupMain": true,
				'v': "/admin/listUsers"
			},
			{
				"l": "Edit Multiple Groups",
				"group": "Administration",
				'v': "/admin/user/editGroups"
			},
			{
				"l": "Validate Change Email",
				"group": "Guest",
				'v': "/changeEmail/validate"
			},
			{
				"l": "Forgot Password",
				"group": "Guest",
				'v': "/forgotPassword"
			},
			{
				"l": "Register",
				"group": "Guest",
				'v': "/join"
			},
			{
				"l": "Validate Register",
				"group": "Guest",
				'v': "/join/validate"
			},
			{
				"l": "Login",
				"group": "Guest",
				"groupMain": true,
				'v': "/login"
			},
			{
				"l": "Logout",
				"group": "Guest",
				'v': "/logout"
			},
			{
				"l": "Reset Password",
				"group": "Guest",
				'v': "/resetPassword"
			}
		]
	},
	{
		"name": "oauth",
		"extKeyRequired": true,
		"port": 4002,
		"apis": [
			{
				"l": "Create Token",
				'v': "/token",
				"groupMain": true
			},
			{
				"l": "Kill Token",
				'v': "/kill"
			}
		]

	},
	{
		"name": "dashboard",
		"extKeyRequired": true,
		"port": 4003,
		"apis": [
			{
				'l': "List Environments",
				'v': "/environment/list",
				"group": "Environment",
				"groupMain": true
			},
			{
				'l': "Add Environment",
				'v': "/environment/add",
				"group": "Environment"
			},
			{
				'l': "Delete Environment",
				'v': "/environment/delete",
				"group": "Environment"
			},
			{
				'l': "Update Environment",
				'v': "/environment/update",
				"group": "Environment"
			},
			{
				'l': "Update Product",
				'v': "/product/update",
				"group": "Product"
			},
			{
				'l': "Add Product",
				'v': "/product/add",
				"group": "Product"
			},
			{
				'l': "Delete Product",
				'v': "/product/delete",
				"group": "Product"
			},
			{
				'l': "List Products",
				'v': "/product/list",
				"group": "Product",
				"groupMain": true
			},
			{
				'l': "Get Product",
				'v': "/product/get",
				"group": "Product"
			},

			{
				'l': "Add Product Package",
				'v': "/product/packages/add",
				"group": "Product"
			},
			{
				'l': "Get Product Package",
				'v': "/product/packages/get",
				"group": "Product"
			},
			{
				"l": "Delete Product Package",
				"group": "Product",
				'v': "/product/packages/delete"
			},

			{
				"l": "List Product Packages",
				"group": "Product",
				'v': "/product/packages/list"
			},
			{
				"l": "Update Product Package",
				"group": "Product",
				'v': "/product/packages/update"
			},
			{
				"l": "List Tenants",
				"group": "Tenant",
				"groupMain": true,
				'v': "/tenant/list"
			},
			{
				"l": "Get Tenant Info",
				"group": "Tenant",
				'v': "/tenant/get"
			},
			{
				"l": "Add Tenant",
				"group": "Tenant",
				'v': "/tenant/add"
			},
			{
				"l": "Update Tenant",
				"group": "Tenant",
				'v': "/tenant/update"
			},
			{
				"l": "List Tenant Applications",
				"group": "Tenant Application",
				'v': "/tenant/application/list",
				"groupMain": true
			},
			{
				"l": "Add Tenant Application",
				"group": "Tenant Application",
				'v': "/tenant/application/add"
			},

			{
				"l": "Update Tenant Application",
				"group": "Tenant Application",
				'v': "/tenant/application/update"
			},
			{
				"l": "Delete Tenant",
				"group": "Tenant",
				'v': "/tenant/delete"
			},
			{
				"l": "Delete Tenant Application",
				"group": "Tenant Application",
				'v': "/tenant/application/delete"
			},

			{
				"l": "Add Tenant Application Key",
				"group": "Tenant Application",
				'v': "/tenant/application/key/add"
			},
			{
				"l": "List Application Key Configuration",
				"group": "Tenant Application",
				'v': "/tenant/application/key/config/list"
			},

			{
				"l": "Update Application Key Configuration",
				"group": "Tenant Application",
				'v': "/tenant/application/key/config/update"
			},

			{
				"l": "Delete Application Key",
				"group": "Tenant Application",
				'v': "/tenant/application/key/delete"
			},
			{
				"l": "Add Application External Key",
				"group": "Tenant Application",
				'v': "/tenant/application/key/ext/add"
			},
			{
				"l": "Delete Application External Key",
				"group": "Tenant Application",
				'v': "/tenant/application/key/ext/delete"
			},
			{
				"l": "List Application External Keys",
				"group": "Tenant Application",
				'v': "/tenant/application/key/ext/list"
			},
			{
				"l": "Update Application External Key",
				"group": "Tenant Application",
				'v': "/tenant/application/key/ext/update"
			},
			{
				"l": "List Application Keys",
				"group": "Tenant Application",
				'v': "/tenant/application/key/list"
			},
			{
				"l": "List Tenant oAuth Users",
				"group": "Tenant oAuth",
				"groupMain": true,
				'v': "/tenant/oauth/users/list"
			},
			{
				"l": "Add Tenant oAuth Configuration",
				"group": "Tenant oAuth",
				'v': "/tenant/oauth/add"
			},
			{
				"l": "Delete Tenant oAuth Configuration",
				"group": "Tenant oAuth",
				'v': "/tenant/oauth/delete"
			},
			{
				"l": "Get Tenant oAuth Configuration",
				"group": "Tenant oAuth",
				'v': "/tenant/oauth/list"
			},
			{
				"l": "Update Tenant oAuth Configuration",
				"group": "Tenant oAuth",
				'v': "/tenant/oauth/update"
			},
			{
				"l": "Add Tenant oAuth User",
				"group": "Tenant oAuth",
				'v': "/tenant/oauth/users/add"
			},
			{
				"l": "Delete Tenant oAuth User",
				"group": "Tenant oAuth",
				'v': "/tenant/oauth/users/delete"
			},
			{
				"l": "Update Tenant oAuth User",
				"group": "Tenant oAuth",
				'v': "/tenant/oauth/users/update"
			},
			{
				"l": "List Hosts",
				"group": "Hosts",
				'v': "/hosts/list",
				"groupMain": true
			},
			{
				"l": "List Services",
				"group": "Services",
				'v': "/services/list",
				"groupMain": true
			}
		]
	},
	{
		"name": "example01",
		"extKeyRequired": false,
		"port": 4010,
		"apis": [
			{
				"l": "Test Get",
				'v': "/testGet",
				"groupMain": true
			},
			{
				"l": "Test Delete",
				'v': "/testDel"
			},
			{
				'l': 'Build Name',
				'v': '/buildName'
			},
			{
				'l': 'Test Post',
				'v': '/testPost'
			},
			{
				'l': 'Test Put',
				'v': '/testPut'
			}
		]
	},
	{
		"name": "example02",
		"extKeyRequired": true,
		"port": 4011,
		"apis": [
			{
				'l': 'Build Name',
				'v': '/buildName',
				"groupMain": true
			}
		]
	},
	{
		"name": "example03",
		"extKeyRequired": true,
		"port": 4012,
		"apis": [
			{
				"l": "Test Get Api",
				'v': "/testGet",
				"group" :"Test Get",
				"groupMain": true
			},
			{
				'l': 'Build Name Api',
				'v': '/buildName',
				"group" :"Build Name",
				"groupMain": true
			}
		]
	},
	{
		"name": "example04",
		"extKeyRequired": true,
		"port": 4013,
		"apis": [
			{
				'l': 'Build Name',
				'v': '/buildName',
				"groupMain": true
			},
			{
				"l": "Build Name Gold",
				'v': "/buildNameGold"
			},
			{
				"l": "Test Get",
				'v': "/testGet"
			}
		]
	}
];

var core_hosts = [
	{
		"env": "dev",
		"name": "tony",
		"ip": "127.0.0.1"
	}
];<|endoftext|>


<commit_before>document.addEventListener('DOMContentLoaded', function(){
   var aluContainer = document.querySelector('.comment-form-smilies');
    if ( !aluContainer ) return;
    aluContainer.addEventListener('click',function(e){
    var myField,
        _self = e.target.dataset.smilies ? e.target : e.target.parentNode,
        tag = ' ' + _self.dataset.smilies + ' ';
        if (document.getElementById('comment') && document.getElementById('comment').type == 'textarea') {
            myField = document.getElementById('comment')
        } else {
            return false
        }
        if (document.selection) {
            myField.focus();
            sel = document.selection.createRange();
            sel.text = tag;
            myField.focus()
        } else if (myField.selectionStart || myField.selectionStart == '0') {
            var startPos = myField.selectionStart;
            var endPos = myField.selectionEnd;
            var cursorPos = endPos;
            myField.value = myField.value.substring(0, startPos) + tag + myField.value.substring(endPos, myField.value.length);
            cursorPos += tag.length;
            myField.focus();
            myField.selectionStart = cursorPos;
            myField.selectionEnd = cursorPos
        } else {
            myField.value += tag;
            myField.focus()
        }
    });
 });<commit_msg>fix: fixed undefined error when click empty place<commit_after>document.addEventListener('DOMContentLoaded', function(){
   var aluContainer = document.querySelector('.comment-form-smilies');
    if ( !aluContainer ) return;
    aluContainer.addEventListener('click',function(e){
    var myField,
        _self = e.target.dataset.smilies ? e.target : e.target.parentNode;
        if ( typeof _self.dataset.smilies == 'undefined' ) return;
        var tag = ' ' + _self.dataset.smilies + ' ';
        if (document.getElementById('comment') && document.getElementById('comment').type == 'textarea') {
            myField = document.getElementById('comment')
        } else {
            return false
        }
        if (document.selection) {
            myField.focus();
            sel = document.selection.createRange();
            sel.text = tag;
            myField.focus()
        } else if (myField.selectionStart || myField.selectionStart == '0') {
            var startPos = myField.selectionStart;
            var endPos = myField.selectionEnd;
            var cursorPos = endPos;
            myField.value = myField.value.substring(0, startPos) + tag + myField.value.substring(endPos, myField.value.length);
            cursorPos += tag.length;
            myField.focus();
            myField.selectionStart = cursorPos;
            myField.selectionEnd = cursorPos
        } else {
            myField.value += tag;
            myField.focus()
        }
    });
 });<|endoftext|>


<commit_before>/*
This file is part of the GhostDriver project from Neustar inc.

Copyright (c) 2012, Ivan De Marino <ivan.de.marino@gmail.com> - Neustar inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * 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 HOLDER 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.
*/

var ghostdriver = ghostdriver || {};

ghostdriver.SessionReqHand = function(session) {
    // private:
    var
    _protoParent = ghostdriver.SessionReqHand.prototype,
    _session = session,
    _locator = new ghostdriver.WebElementLocator(_session),
    _const = {
        URL             : "url",
        ELEMENT         : "element",
        ELEMENTS        : "elements",
        ELEMENT_DIR     : "/element/",
        TITLE           : "title",
        WINDOW          : "window",
        FORWARD         : "forward",
        BACK            : "back"
    },
    _errors = require("./errors.js"),

    _handle = function(req, res) {
        var postObj,
            url,
            locator,
            element;

        _protoParent.handle.call(this, req, res);

        var responseAfterLoadFinished = function (func) {
            _session.getCurrentWindow().onLoadFinished = function () {
                res.writeJSON(_protoParent.buildSuccessResponseBody.call(this, _session.getId()));
                res.statusCode = 200;
                res.closeGracefully();
            };
            _session.getCurrentWindow().evaluate(func);
        };

        // Handle "/url" GET and POST
        if (req.urlParsed.file === _const.URL) {                                         //< ".../url"
            if (req.method === "GET") {
                // Get the URL at which the Page currently is
                url = _session.getCurrentWindow().evaluate(function() { return location.toString(); });
                res.statusCode = 200;
                res.writeJSON(_protoParent.buildSuccessResponseBody.call(this, _session.getId(), url));
                res.close();
            } else if (req.method === "POST") {
                // Load the given URL in the Page
                postObj = JSON.parse(req.post);
                if (typeof(postObj) === "object" && postObj.url) {
                    // Open the given URL and, when done, return "HTTP 200 OK"
                    _session.getCurrentWindow().open(postObj.url, function(status) {
                        if (status === "success") {
                            // TODO Handle situation where loading doesn't work
                            res.statusCode = 200;
                            res.closeGracefully();
                        } else {
                            throw _errors.createInvalidReqInvalidCommandMethodEH(req);
                        }
                    });
                } else {
                    throw _errors.createInvalidReqMissingCommandParameterEH(req);
                }
            }
            return;
        } else if (req.urlParsed.file === _const.TITLE && req.method === "GET") {       //< ".../title"
            // Get the current Page title
            _titleCommand(req, res);
            return;
        } else if (req.urlParsed.file === _const.WINDOW) {                              //< ".../window"
            if (req.method === "DELETE") {
                _windowCloseCommand(req, res);
            } else if (req.method === "POST") {
                _windowChangeFocusToCommand(req, res);
            }
            return;
        } else if (req.urlParsed.file === _const.ELEMENT && req.method === "POST") {    //< ".../element"
            _elementCommand(req, res);
            return;
        } else if (req.urlParsed.directory === _const.ELEMENT_DIR) {                    //< ".../element/:elementId" or ".../element/active"
            // TODO
        } else if (req.urlParsed.path.indexOf(_const.ELEMENT_DIR) === 0) {              //< ".../element/:elementId/COMMAND"
            // Get the WebElementRH and, if found, re-route request to it
            element = _locator.getElement(decodeURIComponent(req.urlParsed.chunks[1]));
            if (element !== null) {
                _protoParent.reroute.call(element, req, res, _const.ELEMENT_DIR + req.urlParsed.chunks[1]);
            } else {
                throw _errors.createInvalidReqVariableResourceNotFoundEH(req);
            }
            return;
        } else if (req.urlParsed.file === _const.FORWARD && req.method === "POST") {
            responseAfterLoadFinished(require("./webdriver_atoms.js").get("forward"));
            return;
        } else if (req.urlParsed.file === _const.BACK && req.method === "POST") {
            responseAfterLoadFinished(require("./webdriver_atoms.js").get("back"));
            return;
        }

        throw _errors.createInvalidReqInvalidCommandMethodEH(req);
    },

    _windowCloseCommand = function(req, res) {
        // TODO An optional JSON parameter "name" might be given
        _session.closeCurrentWindow();
        res.statusCode = 200;
        res.closeGracefully();
    },

    _windowChangeFocusToCommand = function(req, res) {
        // TODO
        // TODO An optional JSON parameter "name" might be given
    },

    _titleCommand = function(req, res) {
        var result = _session.getCurrentWindow().evaluate(function() { return document.title; });
        res.statusCode = 200;
        res.writeJSON(_protoParent.buildSuccessResponseBody.call(this, _session.getId(), result));
        res.close();
    },

    _elementCommand = function(req, res) {
        // Search for a WebElement on the Page
        var element = _locator.locateElement(JSON.parse(req.post));
        if (element) {
            res.statusCode = 200;
            res.writeJSON(_protoParent.buildSuccessResponseBody.call(this, _session.getId(), element.getJSON()));
            res.close();
            return;
        }

        throw _errors.createInvalidReqVariableResourceNotFoundEH(req);
    };

    // public:
    return {
        handle : _handle,
        setSession : function(s) { _session = s; },
        getSessionId : function() { return _session.getId(); }
    };
};
// prototype inheritance:
ghostdriver.SessionReqHand.prototype = new ghostdriver.RequestHandler();
<commit_msg>Fully completed some commands (with error handling now).<commit_after>/*
This file is part of the GhostDriver project from Neustar inc.

Copyright (c) 2012, Ivan De Marino <ivan.de.marino@gmail.com> - Neustar inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * 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 HOLDER 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.
*/

var ghostdriver = ghostdriver || {};

ghostdriver.SessionReqHand = function(session) {
    // private:
    var
    _protoParent = ghostdriver.SessionReqHand.prototype,
    _session = session,
    _locator = new ghostdriver.WebElementLocator(_session),
    _const = {
        URL             : "url",
        ELEMENT         : "element",
        ELEMENTS        : "elements",
        ELEMENT_DIR     : "/element/",
        TITLE           : "title",
        WINDOW          : "window",
        FORWARD         : "forward",
        BACK            : "back"
    },
    _errors = require("./errors.js"),

    _handle = function(req, res) {
        var element;

        _protoParent.handle.call(this, req, res);

        // Handle "/url" GET and POST
        if (req.urlParsed.file === _const.URL) {                                         //< ".../url"
            if (req.method === "GET") {
                _getUrlCommand(req, res);
            } else if (req.method === "POST") {
                _postUrlCommand(req, res);
            }
            return;
        } else if (req.urlParsed.file === _const.TITLE && req.method === "GET") {       //< ".../title"
            // Get the current Page title
            _titleCommand(req, res);
            return;
        } else if (req.urlParsed.file === _const.WINDOW) {                              //< ".../window"
            if (req.method === "DELETE") {
                _windowCloseCommand(req, res);
            } else if (req.method === "POST") {
                _windowChangeFocusToCommand(req, res);
            }
            return;
        } else if (req.urlParsed.file === _const.ELEMENT && req.method === "POST") {    //< ".../element"
            _elementCommand(req, res);
            return;
        } else if (req.urlParsed.directory === _const.ELEMENT_DIR) {                    //< ".../element/:elementId" or ".../element/active"
            // TODO
        } else if (req.urlParsed.path.indexOf(_const.ELEMENT_DIR) === 0) {              //< ".../element/:elementId/COMMAND"
            // Get the WebElementRH and, if found, re-route request to it
            element = _locator.getElement(decodeURIComponent(req.urlParsed.chunks[1]));
            if (element !== null) {
                _protoParent.reroute.call(element, req, res, _const.ELEMENT_DIR + req.urlParsed.chunks[1]);
            } else {
                throw _errors.createInvalidReqVariableResourceNotFoundEH(req);
            }
            return;
        } else if (req.urlParsed.file === _const.FORWARD && req.method === "POST") {
            _backCommand(req, res);
            return;
        } else if (req.urlParsed.file === _const.BACK && req.method === "POST") {
            _forwardCommand(req, res);
            return;
        }

        throw _errors.createInvalidReqInvalidCommandMethodEH(req);
    },

    _backCommand = function(req, res) {
        var onSuccess = function (status) {
            res.statusCode = 200;
            res.writeJSON(_protoParent.buildSuccessResponseBody.call(this, _session.getId()));
            res.closeGracefully();
        };

        _session.getCurrentWindow().evaluateAndWaitForLoad(
            require("./webdriver_atoms.js").get("back"),
            onSuccess,
            onSuccess); //< We don't care if 'forward' fails
    },

    _forwardCommand = function(req, res) {
        var onSuccess = function (status) {
            res.statusCode = 200;
            res.writeJSON(_protoParent.buildSuccessResponseBody.call(this, _session.getId()));
            res.closeGracefully();
        };

        _session.getCurrentWindow().evaluateAndWaitForLoad(
            require("./webdriver_atoms.js").get("forward"),
            onSuccess,
            onSuccess); //< We don't care if 'forward' fails
    },

    _getUrlCommand = function(req, res) {
        // Get the URL at which the Page currently is
        var url = _session.getCurrentWindow().evaluate(function() { return location.toString(); });
        res.statusCode = 200;
        res.writeJSON(_protoParent.buildSuccessResponseBody.call(this, _session.getId(), url));
        res.close();
    },

    _postUrlCommand = function(req, res) {
        // Load the given URL in the Page
        var postObj = JSON.parse(req.post),
            maxWaitForOpen = 1000 * 60,     //< a website should take less than 1m to open
            timer;

        if (typeof(postObj) === "object" && postObj.url) {
            // Open the given URL and, when done, return "HTTP 200 OK"
            _session.getCurrentWindow().open(postObj.url, function(status) {
                // Callback received: don't need the timer anymore
                clearTimeout(timer);

                if (status === "success") {
                    res.statusCode = 200;
                    res.closeGracefully();
                } else {
                    _errors.handleInvalidReqInvalidCommandMethodEH(req, res);
                }
            });
            timer = setTimeout(function() {
                // Command Failed (Timed-out)
                _errors.handleFailedCommandEH(
                    _errors.FAILED_CMD_STATUS.TIMEOUT,
                    "URL '"+postObj.url+"' didn't load within "+maxWaitForOpen+"ms",
                    req,
                    res,
                    _session,
                    "SessionReqHand");
            }, 1000 * 60);
        } else {
            throw _errors.createInvalidReqMissingCommandParameterEH(req);
        }
    },

    _windowCloseCommand = function(req, res) {
        // TODO An optional JSON parameter "name" might be given
        _session.closeCurrentWindow();
        res.statusCode = 200;
        res.closeGracefully();
    },

    _windowChangeFocusToCommand = function(req, res) {
        // TODO
        // TODO An optional JSON parameter "name" might be given
    },

    _titleCommand = function(req, res) {
        var result = _session.getCurrentWindow().evaluate(function() { return document.title; });
        res.statusCode = 200;
        res.writeJSON(_protoParent.buildSuccessResponseBody.call(this, _session.getId(), result));
        res.close();
    },

    _elementCommand = function(req, res) {
        // Search for a WebElement on the Page
        var element = _locator.locateElement(JSON.parse(req.post));
        if (element) {
            res.statusCode = 200;
            res.writeJSON(_protoParent.buildSuccessResponseBody.call(this, _session.getId(), element.getJSON()));
            res.close();
            return;
        }

        throw _errors.createInvalidReqVariableResourceNotFoundEH(req);
    };

    // public:
    return {
        handle : _handle,
        setSession : function(s) { _session = s; },
        getSessionId : function() { return _session.getId(); }
    };
};
// prototype inheritance:
ghostdriver.SessionReqHand.prototype = new ghostdriver.RequestHandler();
<|endoftext|>


<commit_before>(function () {

    function makeFakePosRange(t, l, r, b) {
        return {top: t, left: l, right: r, bottom: b};
    }

    function maybeAddPx(v) {
        return typeof v === 'string' ? v : v + 'px';
    }

    var $ = require('jquery');
    var tools = require('./index.js');

    var matchers = {

        toBeANumber: tools.defineBasicMatcher(function (actual) {
            return angular.isNumber(actual);
        }),
        toBeAFunction: tools.defineBasicMatcher(function (actual) {
            return angular.isFunction(actual);
        }),

        toBeAnObject: tools.defineBasicMatcher(function (actual) {
            return angular.isObject(actual);
        }),

        toBeAnArray: tools.defineBasicMatcher(function (actual) {
            return angular.isArray(actual);
        }),
        toBeAString: tools.defineBasicMatcher(function (actual) {
            return angular.isString(actual);
        }),
        toBeNully: tools.defineBasicMatcher(function (actual) {
            return actual === undefined || actual === null;
        }),
        toBeAnElement: tools.defineBasicMatcher(function (actual) {
            return !!(actual &&
                (actual.nodeName || // we are a direct element
                    (actual.prop && actual.attr && actual.find)));
        }),
        toHaveField: tools.defineBasicMatcher(function (actual, exp) {
            return exp in actual;
        }, function (actual, exp, pass) {
            return tools.expectedObjectWithNot(actual, pass) + ' to have field: ' + exp;
        }),
        toContainAll: tools.defineBasicMatcher(function (actual, array) {
            array.forEach(function (item) {
                if (actual.indexOf(item) === -1) {
                    return false;
                }
            });
            return true;
        }),
        toHaveClass: tools.defineBasicMatcher(function (actual, className) {
            return $(actual).hasClass(className);
        }, function (actual, expected, pass) {
            return 'Expected "' + $(actual).attr('class') + '"' + (pass ? ' not' : '') + ' to have class "' + expected + '"';
        }),
        toBePositioned: function () {
            return {
                compare: function (actual, t, l, b, r) {
                    var top = $(actual).css('top');
                    var left = $(actual).css('left');
                    var right = $(actual).css('right');
                    var bottom = $(actual).css('bottom');
                    var pos = $(actual).css('position');
                    var pass = top === maybeAddPx(t) &&
                        left === maybeAddPx(l) &&
                        right === maybeAddPx(r) &&
                        bottom === maybeAddPx(b) &&
                        pos === 'absolute';
                    return {
                        pass: pass,
                        message: tools.expectedObjectWithNot(actual, pass, makeFakePosRange(top, left, right, bottom)) + ' to be positioned ' + JSON.stringify(makeFakePosRange(t, l, r, b))
                    };
                }
            };
        }

    };

    beforeEach(function () {
        jasmine.addMatchers(matchers);
    });
})
();<commit_msg>add toHaveOnlyTruthyProperty matcher<commit_after>(function () {

    function makeFakePosRange(t, l, r, b) {
        return {top: t, left: l, right: r, bottom: b};
    }

    function maybeAddPx(v) {
        return typeof v === 'string' ? v : v + 'px';
    }

    var $ = require('jquery');
    var tools = require('./index.js');

    var matchers = {

        toBeANumber: tools.defineBasicMatcher(function (actual) {
            return angular.isNumber(actual);
        }),
        toBeAFunction: tools.defineBasicMatcher(function (actual) {
            return angular.isFunction(actual);
        }),

        toBeAnObject: tools.defineBasicMatcher(function (actual) {
            return angular.isObject(actual);
        }),

        toBeAnArray: tools.defineBasicMatcher(function (actual) {
            return angular.isArray(actual);
        }),
        toBeAString: tools.defineBasicMatcher(function (actual) {
            return angular.isString(actual);
        }),
        toBeNully: tools.defineBasicMatcher(function (actual) {
            return actual === undefined || actual === null;
        }),
        toBeAnElement: tools.defineBasicMatcher(function (actual) {
            return !!(actual &&
                (actual.nodeName || // we are a direct element
                    (actual.prop && actual.attr && actual.find)));
        }),
        toHaveField: tools.defineBasicMatcher(function (actual, exp) {
            return exp in actual;
        }, function (actual, exp, pass) {
            return tools.expectedObjectWithNot(actual, pass) + ' to have field: ' + exp;
        }),
        toContainAll: tools.defineBasicMatcher(function (actual, array) {
            array.forEach(function (item) {
                if (actual.indexOf(item) === -1) {
                    return false;
                }
            });
            return true;
        }),
        toHaveClass: tools.defineBasicMatcher(function (actual, className) {
            return $(actual).hasClass(className);
        }, function (actual, expected, pass) {
            return 'Expected "' + $(actual).attr('class') + '"' + (pass ? ' not' : '') + ' to have class "' + expected + '"';
        }),
        toBePositioned: function () {
            return {
                compare: function (actual, t, l, b, r) {
                    var top = $(actual).css('top');
                    var left = $(actual).css('left');
                    var right = $(actual).css('right');
                    var bottom = $(actual).css('bottom');
                    var pos = $(actual).css('position');
                    var pass = top === maybeAddPx(t) &&
                        left === maybeAddPx(l) &&
                        right === maybeAddPx(r) &&
                        bottom === maybeAddPx(b) &&
                        pos === 'absolute';
                    return {
                        pass: pass,
                        message: tools.expectedObjectWithNot(actual, pass, makeFakePosRange(top, left, right, bottom)) + ' to be positioned ' + JSON.stringify(makeFakePosRange(t, l, r, b))
                    };
                }
            };
        },
        toHaveOnlyTruthyProperty: tools.defineBasicMatcher(function (actual, propertyName) {
            return Object.keys(this).every(function (key) {
                return key === propertyName ? !!this[key] : !this[key];
            }, function (actual, expected, pass) {
                return 'Expected "' + propertyName + '"' + (pass ? ' not' : '') + ' to be only truthy value of the given object.';
            });
        })

    };

    beforeEach(function () {
        jasmine.addMatchers(matchers);
    });
})
();<|endoftext|>