<commit_before>var C = 10;
var colors = require('./colors.js');
var mapCX = 1000;
var mapCY = 1000;
var unit = mapCX/30;

function u(n) { return unit*n; }

function createPoly(cX, cY, w, h, color, b1)
{
var retArray = [];
if(b1[0])
{
	retArray=retArray.concat([{
      position : {x: cX, y: cY - (h/2)},
      spatial: {x : w/2 , y: C},
      color: color[0]
    }]);
}if(b1[1])
{

	retArray=retArray.concat([{
      position : {x: cX +(w/2) + C, y: cY},
      spatial: {x : C, y: h/2 + C},
      color: color[1]
    }]);
}
if(b1[2])
{
	retArray=retArray.concat([{
      position : {x: cX, y: cY +(h/2)},
      spatial: {x : w/2, y: C},
      color: color[2]
    }]);
}
if(b1[3])
{
	retArray=retArray.concat( [  {
      position : {x: cX-(w/2)-C, y: cY},
      spatial: {x : C, y: h/2 + C},
      color: color[3]
    }]);
}
return retArray;
}

module.exports = {
  levelObjects:{
    playerStart: {x: C + 100, y: 50 + C},
    levelFinish:{x: (3*(mapCX/4)), y: (mapCY/3)}
  },
  gems: [
  ],
  walls: [
    {
      position : {x:u(6), y: u(17)},
      spatial: {x : C, y: u(8)},
      color: colors.green,
	text: 'g1'
    },
    {
      position : {x:u(6), y: u(4)},
      spatial: {x : C, y: u(5)},
      color: colors.yellow,
	text: 'o1'
    },
    {
      position : {x:u(12)+C, y: u(12)},
      spatial: {x : C, y: u(12)},
      color: colors.red,
	text:'r1'
    },
    {
      position : {x:u(18), y: u(18)},
      spatial: {x : C, y: u(6)},
      color: colors.yellow,
	text: 'o2'
    },
    {
      position : {x:u(18), y: u(6)},
      spatial: {x : C, y: u(6)},
      color: colors.purple,
	text:'p1'
    },
    {
      position : {x:u(22), y: u(4)},
      spatial: {x : C, y: u(4)},
      color: colors.blue,
	text:'b3'
    },
    {
      position : {x:u(26), y: u(8)-C},
      spatial: {x : u(4), y: C},
      color: colors.blue,
	text:'b4'
    },
    {
      position : {x:u(22), y: u(10)},
      spatial: {x : C, y: u(2)},
      color: colors.green
    },
    {
      position : {x:u(20)+C, y: u(12)},
      spatial: {x : u(2), y: C},
      color: colors.blue,
	text:'b5'
    },
    {
      position : {x:u(26), y: u(12)},
      spatial: {x : u(4), y: C},
      color: colors.purple,
	text:'p3'
    },
    {
      position : {x:u(25), y: u(3)},
      spatial: {x : C, y: u(3)},
      color: colors.green,
	text:'g2'
    },
    {
      position : {x:u(28), y: u(6)-C},
      spatial: {x : u(3), y: C},
      color: colors.green,
	text:'g3'
    },
    {
      position : {x:u(32)+C, y: u(6)-C},
      spatial: {x : u(2), y: C},
      color: colors.purple,
	text:'p4'
    },
    {
      position : {x:u(30), y: u(15)},
      spatial: {x : C, y: u(9)},
      color: colors.red,
	text: 'r3'
    },
    {
      position : {x:u(24)+C, y: u(17)},
      spatial: {x : u(6), y: C},
      color: colors.green,
	text:'g4'
    },
    {
      position : {x:u(32)+C, y: u(8)-C},
      spatial: {x : u(2), y: C},
      color: colors.green,
	text:'g5'
    },
    {
      position : {x:u(32)+C, y: u(12)},
      spatial: {x : u(2), y: C},
      color: colors.blue,
	text:'b6'
    }
].concat(createPoly(u(9), u(13), u(6), u(8),
	[colors.blue,colors.yellow,colors.purple,colors.red],
	[1,0,1,0] ) ).concat(
	createPoly(u(3), u(13), u(6), u(8),
	[colors.red,null,colors.blue,null],
	[true,false,true,false] )
	)

};
<commit_msg>level 4 gems complete<commit_after>var C = 10;
var colors = require('./colors.js');
var mapCX = 1000;
var mapCY = 1000;
var unit = mapCX/30;

function u(n) { return unit*n; }

function createPoly(cX, cY, w, h, color, b1)
{
var retArray = [];
if(b1[0])
{
	retArray=retArray.concat([{
      position : {x: cX, y: cY - (h/2)},
      spatial: {x : w/2 , y: C},
      color: color[0]
    }]);
}if(b1[1])
{

	retArray=retArray.concat([{
      position : {x: cX +(w/2) + C, y: cY},
      spatial: {x : C, y: h/2 + C},
      color: color[1]
    }]);
}
if(b1[2])
{
	retArray=retArray.concat([{
      position : {x: cX, y: cY +(h/2)},
      spatial: {x : w/2, y: C},
      color: color[2]
    }]);
}
if(b1[3])
{
	retArray=retArray.concat( [  {
      position : {x: cX-(w/2)-C, y: cY},
      spatial: {x : C, y: h/2 + C},
      color: color[3]
    }]);
}
return retArray;
}

module.exports = {
  levelObjects:{
    playerStart: {x: C + 100, y: 50 + C},
    levelFinish:{x: (3*(mapCX/4)), y: (mapCY/3)}
  },
  gems: [
  {
    position : {x: u(1), y: u(1)},
    color : colors.yellow
  },
  {
    position : {x: u(1), y: u(11)},
    color : colors.green
  },
  {
    position : {x: u(1), y: u(15)},
    color : colors.red
  },
  {
    position : {x: u(1), y: u(19)},
    color : colors.green
  },
  {
    position : {x: u(4), y: u(23)},
    color : colors.blue
  },
  {
    position : {x: u(11), y: u(1)},
    color : colors.blue
  },
  {
    position : {x: u(7), y: u(7)},
    color : colors.red
  },
  {
    position : {x: u(11), y: u(11)},
    color : colors.purple
  },
  {
    position : {x: u(11), y: u(19)},
    color : colors.yellow
  },
  {
    position : {x: u(15), y: u(1)},
    color : colors.yellow
  },
  {
    position : {x: u(15), y: u(23)},
    color : colors.purple
  },
  {
    position : {x: u(20), y: u(1)},
    color : colors.purple
  },
  {
    position : {x: u(23), y: u(6)},
    color : colors.red
  },
  {
    position : {x: u(23), y: u(11)},
    color : colors.blue
  },
  {
    position : {x: u(26), y: u(11)},
    color : colors.green
  },
  {
    position : {x: u(26), y: u(16)},
    color : colors.blue
  },
  {
    position : {x: u(20), y: u(23)},
    color : colors.red
  },
  {
    position : {x: u(32)+C, y: u(6)+2*C},
    color : colors.purple
  },
  {
    position : {x: u(32)+C, y: u(11)},
    color : colors.red
  },
  {
    position : {x: u(32)+C, y: u(23)},
    color : colors.blue
  }

  ],
  walls: [
    {
      position : {x:u(6), y: u(17)},
      spatial: {x : C, y: u(8)},
      color: colors.green,
	text: 'g1'
    },
    {
      position : {x:u(6), y: u(4)},
      spatial: {x : C, y: u(5)},
      color: colors.yellow,
	text: 'o1'
    },
    {
      position : {x:u(12)+C, y: u(12)},
      spatial: {x : C, y: u(12)},
      color: colors.red,
	text:'r1'
    },
    {
      position : {x:u(18), y: u(18)},
      spatial: {x : C, y: u(6)},
      color: colors.yellow,
	text: 'o2'
    },
    {
      position : {x:u(18), y: u(6)},
      spatial: {x : C, y: u(6)},
      color: colors.purple,
	text:'p1'
    },
    {
      position : {x:u(22), y: u(4)},
      spatial: {x : C, y: u(4)},
      color: colors.blue,
	text:'b3'
    },
    {
      position : {x:u(26), y: u(8)-C},
      spatial: {x : u(4), y: C},
      color: colors.blue,
	text:'b4'
    },
    {
      position : {x:u(22), y: u(10)},
      spatial: {x : C, y: u(2)},
      color: colors.green
    },
    {
      position : {x:u(20)+C, y: u(12)},
      spatial: {x : u(2), y: C},
      color: colors.blue,
	text:'b5'
    },
    {
      position : {x:u(26), y: u(12)},
      spatial: {x : u(4), y: C},
      color: colors.purple,
	text:'p3'
    },
    {
      position : {x:u(25), y: u(3)},
      spatial: {x : C, y: u(3)},
      color: colors.green,
	text:'g2'
    },
    {
      position : {x:u(28), y: u(6)-C},
      spatial: {x : u(3), y: C},
      color: colors.green,
	text:'g3'
    },
    {
      position : {x:u(32)+C, y: u(6)-C},
      spatial: {x : u(2), y: C},
      color: colors.purple,
	text:'p4'
    },
    {
      position : {x:u(30), y: u(15)},
      spatial: {x : C, y: u(9)},
      color: colors.red,
	text: 'r3'
    },
    {
      position : {x:u(24)+C, y: u(17)},
      spatial: {x : u(6), y: C},
      color: colors.green,
	text:'g4'
    },
    {
      position : {x:u(32)+C, y: u(8)-C},
      spatial: {x : u(2), y: C},
      color: colors.green,
	text:'g5'
    },
    {
      position : {x:u(32)+C, y: u(12)},
      spatial: {x : u(2), y: C},
      color: colors.blue,
	text:'b6'
    }
].concat(createPoly(u(9), u(13), u(6), u(8),
	[colors.blue,colors.yellow,colors.purple,colors.red],
	[1,0,1,0] ) ).concat(
	createPoly(u(3), u(13), u(6), u(8),
	[colors.red,null,colors.blue,null],
	[true,false,true,false] )
	)

};
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
  A -> foo(C)
       foo(D)
  B -> foo(C)

  How does B.foo(D) work?
  Copy methods? Then what if A gets refined?
  Lookup B.foo, otherwise lookup A.foo()?
    Then what about FObject vs. particular class lookup?
  What about treating 'this' as first argument?
*/

foam.CLASS({
  package: 'foam.core',
  name: 'MultiMethod',
  extends: 'foam.core.AbstractMethod',

  properties: [
    {
      name: 'name',
      factory: function() {
        return this.methodName +
          this.args.map(function(a) { return a.typeName; }).join(':');
      }
    },
    {
      name: 'methodName',
      required: true
    }
  ],

  methods: [
    function installInProto(proto) {
      var key = this.cls_.id.replace(/\./g,':') + ':' + this.methodName;
      console.log('Installing: ' + key);
      var dispath = this.createDispatch(proto, key, 0, this.args);
      displatch.code = this.code;
    },

    function createDispatch(proto, prefix, pos, args) {
      var d = proto[prefix];

      if ( ! d ) {
        var prefix2 = prefix + ':' + args[pos] + typeName;
        proto[prefix] = function dispatch() {
          if ( arguments.length === pos ) {
            return arguments.callee.code.apply(this, arguments);
          }
          var t = foam.typeOf(arguments[pos]);
          var f = t[prefix2];
          return f.apply(this, arguments);
        };
      }

      if ( pos === args.length ) return proto[prefix];
    },

    function exportAs(obj) {
      var m = obj[this.name];
      /** Bind the method to 'this' when exported so that it still works. **/
      return function exportedMethod() { return m.apply(obj, arguments); };
    }
  ]
});
<commit_msg>foam.core.MultiMethod typeName -> type<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
  A -> foo(C)
       foo(D)
  B -> foo(C)

  How does B.foo(D) work?
  Copy methods? Then what if A gets refined?
  Lookup B.foo, otherwise lookup A.foo()?
    Then what about FObject vs. particular class lookup?
  What about treating 'this' as first argument?
*/

foam.CLASS({
  package: 'foam.core',
  name: 'MultiMethod',
  extends: 'foam.core.AbstractMethod',

  properties: [
    {
      name: 'name',
      factory: function() {
        return this.methodName +
          this.args.map(function(a) { return a.type; }).join(':');
      }
    },
    {
      name: 'methodName',
      required: true
    }
  ],

  methods: [
    function installInProto(proto) {
      var key = this.cls_.id.replace(/\./g,':') + ':' + this.methodName;
      console.log('Installing: ' + key);
      var dispath = this.createDispatch(proto, key, 0, this.args);
      displatch.code = this.code;
    },

    function createDispatch(proto, prefix, pos, args) {
      var d = proto[prefix];

      if ( ! d ) {
        var prefix2 = prefix + ':' + args[pos] + typeName;
        proto[prefix] = function dispatch() {
          if ( arguments.length === pos ) {
            return arguments.callee.code.apply(this, arguments);
          }
          var t = foam.typeOf(arguments[pos]);
          var f = t[prefix2];
          return f.apply(this, arguments);
        };
      }

      if ( pos === args.length ) return proto[prefix];
    },

    function exportAs(obj) {
      var m = obj[this.name];
      /** Bind the method to 'this' when exported so that it still works. **/
      return function exportedMethod() { return m.apply(obj, arguments); };
    }
  ]
});
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2019 The FOAM Authors. All Rights Reserved.
 *     http://www.apache.org/licenses/LICENSE-2.0
 */

 foam.CLASS({
  package: 'foam.nanos.ruler',
  name: 'Rule',

  documentation: 'Rule model represents rules(actions) that need to be applied in case passed object satisfies provided predicate.',

  javaImports: [
    'foam.core.FObject',
    'foam.core.X',
    'foam.nanos.logger.Logger',
    'java.util.Collection'
  ],

  properties: [
    {
      class: 'Long',
      name: 'id',
      documentation: 'Sequence number.'
    },
    {
      class: 'String',
      name: 'name',
      documentation: 'Rule name for human readability.'
    },
    {
      class: 'Int',
      name: 'priority',
      documentation: 'Priority defines the order in which rules are to be applied.'+
      'Rules with a higher priority are to be applied first.'+
      'The convention for values is ints that are multiple of 10.'
    },
    {
      class: 'String',
      name: 'ruleGroup',
      documentation: 'ruleGroup defines sets of rules related to the same action.'
    },
    {
      class: 'String',
      name: 'documentation',
      view: {
        class: 'foam.u2.tag.TextArea',
        rows: 12, cols: 80
      }
    },
    {
      class: 'String',
      name: 'daoKey',
      documentation: 'dao name that the rule is applied on.',
      view: function(_, X) {
        var E = foam.mlang.Expressions.create();
        return {
          class: 'foam.u2.view.RichChoiceView',
          sections: [
            {
              heading: 'Services',
              dao: X.nSpecDAO.where(E.ENDS_WITH(foam.nanos.boot.NSpec.ID, 'DAO'))
            }
          ]
        };
      },
    },
    {
      class: 'Enum',
      of: 'foam.nanos.ruler.Operations',
      name: 'operation',
      documentation: 'Defines when the rules is to be applied: put/removed'
    },
    {
      class: 'Boolean',
      name: 'after',
      documentation: 'Defines if the rule needs to be applied before or after operation is completed'+
      'E.g. on dao.put: before object was stored in a dao or after.'
    },
    {
      class: 'FObjectProperty',
      of: 'foam.mlang.predicate.Predicate',
      name: 'predicate',
      javaFactory: `
      return foam.mlang.MLang.TRUE;
      `,
      documentation: 'predicate is checked against an object; if returns true, the action is executed.'+
      'Defaults to return true.'
    },
    {
      class: 'FObjectProperty',
      of: 'foam.nanos.ruler.RuleAction',
      name: 'action',
      documentation: 'The action to be executed if predicates returns true for passed object.'
    },
    {
      class: 'FObjectProperty',
      of: 'foam.nanos.ruler.RuleAction',
      name: 'asyncAction',
      documentation: 'The action to be executed asynchronously if predicates returns true for passed object.'
    },
    {
      class: 'Boolean',
      name: 'enabled',
      value: true,
      documentation: 'Enables the rule.'
    },
    {
      class: 'Boolean',
      name: 'saveHistory',
      value: false,
      documentation: 'Determines if history of rule execution should be saved.',
      help: 'Automatically sets to true when validity is greater than zero.',
      adapt: function(_, nu) {
        return nu || this.validity > 0;
      }
    },
    {
      class: 'Int',
      name: 'validity',
      documentation: 'Validity of the rule (in days) for automatic rescheduling.',
      postSet: function(_, nu) {
        if ( nu > 0
          && ! this.saveHistory
        ) {
          this.saveHistory = true;
        }
      }
    },
    {
      class: 'Object',
      name: 'cmd',
      transient: true,
      hidden: true,
      javaFactory: `
        if ( Operations.CREATE == getOperation()
          || Operations.UPDATE == getOperation()
          || Operations.CREATE_OR_UPDATE == getOperation()
        ) {
          return RulerDAO.PUT_CMD;
        }
        return null;
      `
    }
  ],

  methods: [
    {
      name: 'f',
      type: 'Boolean',
      args: [
        {
          name: 'x',
          type: 'Context'
        },
        {
          name: 'obj',
          type: 'FObject'
        },
        {
          name: 'oldObj',
          type: 'FObject'
        }
      ],
      javaCode: `
        try {
          return getEnabled()
            && getPredicate().f(
              x.put("NEW", obj).put("OLD", oldObj)
            );
        } catch ( Throwable t ) {
          ((Logger) x.get("logger")).error(
            "Failed to evaluate predicate of rule: " + getId(), t);
          return false;
        }
      `
    },
    {
      name: 'apply',
      args: [
        {
          name: 'x',
          type: 'Context'
        },
        {
          name: 'obj',
          type: 'FObject'
        },
        {
          name: 'oldObj',
          type: 'FObject'
        },
        {
          name: 'ruler',
          type: 'foam.nanos.ruler.RuleEngine'
        }
      ],
      javaCode: `
        getAction().applyAction(x, obj, oldObj, ruler);
        if ( ! getAfter() ) {
          ruler.getDelegate().cmd_(x.put("OBJ", obj), getCmd());
        }
      `
    },
    {
      name: 'asyncApply',
      args: [
        {
          name: 'x',
          type: 'Context'
        },
        {
          name: 'obj',
          type: 'FObject'
        },
        {
          name: 'oldObj',
          type: 'FObject'
        },
        {
          name: 'ruler',
          type: 'foam.nanos.ruler.RuleEngine'
        }
      ],
      javaCode: `
        getAsyncAction().applyAction(x, obj, oldObj, ruler);
        if ( ! getAfter() ) {
          ruler.getDelegate().cmd_(x.put("OBJ", obj), getCmd());
        }
      `
    },
    {
      name: 'updateRule',
      type: 'foam.nanos.ruler.Rule',
      documentation: 'since rules are stored as lists in the RulerDAO we use listeners to update them whenever ruleDAO is updated.' +
      'the method provides logic for modifying already stored rule. If not overridden, the incoming rule will be stored in the list as it is.',
      args: [
        {
          name: 'rule',
          type: 'foam.nanos.ruler.Rule'
        }
      ],
      javaCode: `
      return rule;`
    }
  ],

  axioms: [
    {
      name: 'javaExtras',
      buildJavaClass: function(cls) {
        cls.extras.push(`
        public static Rule findById(Collection<Rule> listRule, Long passedId) {
          return listRule.stream().filter(rule -> passedId.equals(rule.getId())).findFirst().orElse(null);
      }
        `);
      }
    }
  ]
});
<commit_msg>Fix bug in Rule Engine<commit_after>/**
 * @license
 * Copyright 2019 The FOAM Authors. All Rights Reserved.
 *     http://www.apache.org/licenses/LICENSE-2.0
 */

 foam.CLASS({
  package: 'foam.nanos.ruler',
  name: 'Rule',

  documentation: 'Rule model represents rules(actions) that need to be applied in case passed object satisfies provided predicate.',

  javaImports: [
    'foam.core.FObject',
    'foam.core.X',
    'foam.nanos.logger.Logger',
    'java.util.Collection'
  ],

  properties: [
    {
      class: 'Long',
      name: 'id',
      documentation: 'Sequence number.'
    },
    {
      class: 'String',
      name: 'name',
      documentation: 'Rule name for human readability.'
    },
    {
      class: 'Int',
      name: 'priority',
      documentation: 'Priority defines the order in which rules are to be applied.'+
      'Rules with a higher priority are to be applied first.'+
      'The convention for values is ints that are multiple of 10.'
    },
    {
      class: 'String',
      name: 'ruleGroup',
      documentation: 'ruleGroup defines sets of rules related to the same action.'
    },
    {
      class: 'String',
      name: 'documentation',
      view: {
        class: 'foam.u2.tag.TextArea',
        rows: 12, cols: 80
      }
    },
    {
      class: 'String',
      name: 'daoKey',
      documentation: 'dao name that the rule is applied on.',
      view: function(_, X) {
        var E = foam.mlang.Expressions.create();
        return {
          class: 'foam.u2.view.RichChoiceView',
          sections: [
            {
              heading: 'Services',
              dao: X.nSpecDAO.where(E.ENDS_WITH(foam.nanos.boot.NSpec.ID, 'DAO'))
            }
          ]
        };
      },
    },
    {
      class: 'Enum',
      of: 'foam.nanos.ruler.Operations',
      name: 'operation',
      documentation: 'Defines when the rules is to be applied: put/removed'
    },
    {
      class: 'Boolean',
      name: 'after',
      documentation: 'Defines if the rule needs to be applied before or after operation is completed'+
      'E.g. on dao.put: before object was stored in a dao or after.'
    },
    {
      class: 'FObjectProperty',
      of: 'foam.mlang.predicate.Predicate',
      name: 'predicate',
      javaFactory: `
      return foam.mlang.MLang.TRUE;
      `,
      documentation: 'predicate is checked against an object; if returns true, the action is executed.'+
      'Defaults to return true.'
    },
    {
      class: 'FObjectProperty',
      of: 'foam.nanos.ruler.RuleAction',
      name: 'action',
      documentation: 'The action to be executed if predicates returns true for passed object.'
    },
    {
      class: 'FObjectProperty',
      of: 'foam.nanos.ruler.RuleAction',
      name: 'asyncAction',
      documentation: 'The action to be executed asynchronously if predicates returns true for passed object.'
    },
    {
      class: 'Boolean',
      name: 'enabled',
      value: true,
      documentation: 'Enables the rule.'
    },
    {
      class: 'Boolean',
      name: 'saveHistory',
      value: false,
      documentation: 'Determines if history of rule execution should be saved.',
      help: 'Automatically sets to true when validity is greater than zero.',
      adapt: function(_, nu) {
        return nu || this.validity > 0;
      }
    },
    {
      class: 'Int',
      name: 'validity',
      documentation: 'Validity of the rule (in days) for automatic rescheduling.',
      postSet: function(_, nu) {
        if ( nu > 0
          && ! this.saveHistory
        ) {
          this.saveHistory = true;
        }
      }
    },
    {
      class: 'Object',
      name: 'cmd',
      transient: true,
      hidden: true,
      javaFactory: `
        if ( Operations.CREATE == getOperation()
          || Operations.UPDATE == getOperation()
          || Operations.CREATE_OR_UPDATE == getOperation()
        ) {
          return RulerDAO.PUT_CMD;
        }
        return null;
      `
    }
  ],

  methods: [
    {
      name: 'f',
      type: 'Boolean',
      args: [
        {
          name: 'x',
          type: 'Context'
        },
        {
          name: 'obj',
          type: 'FObject'
        },
        {
          name: 'oldObj',
          type: 'FObject'
        }
      ],
      javaCode: `
        try {
          return getEnabled()
            && getPredicate().f(
              x.put("NEW", obj).put("OLD", oldObj)
            );
        } catch ( Throwable t ) {
          ((Logger) x.get("logger")).error(
            "Failed to evaluate predicate of rule: " + getId(), t);
          return false;
        }
      `
    },
    {
      name: 'apply',
      args: [
        {
          name: 'x',
          type: 'Context'
        },
        {
          name: 'obj',
          type: 'FObject'
        },
        {
          name: 'oldObj',
          type: 'FObject'
        },
        {
          name: 'ruler',
          type: 'foam.nanos.ruler.RuleEngine'
        }
      ],
      javaCode: `
        getAction().applyAction(x, obj, oldObj, ruler);
      `
    },
    {
      name: 'asyncApply',
      args: [
        {
          name: 'x',
          type: 'Context'
        },
        {
          name: 'obj',
          type: 'FObject'
        },
        {
          name: 'oldObj',
          type: 'FObject'
        },
        {
          name: 'ruler',
          type: 'foam.nanos.ruler.RuleEngine'
        }
      ],
      javaCode: `
        getAsyncAction().applyAction(x, obj, oldObj, ruler);
        if ( ! getAfter() ) {
          ruler.getDelegate().cmd_(x.put("OBJ", obj), getCmd());
        }
      `
    },
    {
      name: 'updateRule',
      type: 'foam.nanos.ruler.Rule',
      documentation: 'since rules are stored as lists in the RulerDAO we use listeners to update them whenever ruleDAO is updated.' +
      'the method provides logic for modifying already stored rule. If not overridden, the incoming rule will be stored in the list as it is.',
      args: [
        {
          name: 'rule',
          type: 'foam.nanos.ruler.Rule'
        }
      ],
      javaCode: `
      return rule;`
    }
  ],

  axioms: [
    {
      name: 'javaExtras',
      buildJavaClass: function(cls) {
        cls.extras.push(`
        public static Rule findById(Collection<Rule> listRule, Long passedId) {
          return listRule.stream().filter(rule -> passedId.equals(rule.getId())).findFirst().orElse(null);
      }
        `);
      }
    }
  ]
});
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2020 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2',
  name: 'PropertyModal',
  extends: 'foam.u2.View',

  documentation: 'View for attaching a choice to a modal',

  imports: [
    'notify'
  ],

  requires: [
    'foam.u2.ControllerMode',
    'foam.u2.detail.SectionedDetailPropertyView'
  ],

  css: `
    ^ {
      border-radius: 3px;
      background-color: #fff;
      max-width: calc(100vw - 48px);
      max-height: calc(100vh - 116px);
      overflow-y: scroll;

      /* TODO: Left the below height as temp fix, need to figure out better way to handle properties rendering in the modal visibly */
      height: 80vh;
    }
    ^title {
      padding: 32px 0px;
      font-size: 1.5em;
      font-weight: bold;
    }
    ^main {
      padding: 0px 32px;
    }
    ^ .buttons {
      padding: 32px;
      box-sizing: border-box;
      display: flex;
      justify-content: flex-end;
    }
  `,

  messages: [
    { name: 'CONFIRM_DELETE_1', message: 'Are you sure you want to delete' },
    { name: 'SUCCESS_MSG', message: ' deleted' },
    { name: 'FAIL_MSG', message: 'Failed to delete' }
  ],

  properties: [
    {
      class: 'Function',
      name: 'onExecute'
    },
    {
      class: 'String',
      name: 'title',
      expression: function(isModalRequired) {
        if ( isModalRequired ) return 'Please provide fill out the following (required)';
        return 'Please fill out the following (optional)';
      }
    },
    {
      class: 'Property',
      name: 'property'
    },
    {
      class: 'Boolean',
      name: 'isModalRequired'
    }
  ],

  methods: [
    function initE() {
      this.SUPER();
      this
        .addClass(this.myClass())
        .start()
          .addClass(this.myClass('main'))
          .start()
            .addClass(this.myClass('title'))
            .add(this.title)
          .end()
          .startContext({ data: this, controllerMode: this.ControllerMode.EDIT })
          .tag(this.SectionedDetailPropertyView, {
            prop: this.property,
            data$: this.data$
          })
          .endContext()
        .end()
        .start()
          .addClass('buttons')
          .startContext({ data: this })
            .tag(this.CANCEL, { buttonStyle: 'SECONDARY' })
            .tag(this.OK)
          .endContext()
        .end();
    }
  ],

  actions: [
    {
      name: 'ok',
      isEnabled: (isModalRequired, property) => {
        if ( ! isModalRequired ) return true;
        return property != '';
      },
      code: function(X) {
        this.onExecute();
        X.closeDialog();
      }
    },
    {
      name: 'cancel',
      code: function(X) {
        X.closeDialog();
      }
    }
  ]
});
<commit_msg>Wired up PropertyModal to get passed in propertyData to make a generic action to slot isEnabled (#4450)<commit_after>/**
 * @license
 * Copyright 2020 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2',
  name: 'PropertyModal',
  extends: 'foam.u2.View',

  documentation: 'View for attaching a choice to a modal',

  imports: [
    'notify'
  ],

  requires: [
    'foam.u2.ControllerMode',
    'foam.u2.detail.SectionedDetailPropertyView'
  ],

  css: `
    ^ {
      border-radius: 3px;
      background-color: #fff;
      max-width: calc(100vw - 48px);
      max-height: calc(100vh - 116px);
      overflow-y: scroll;

      /* TODO: Left the below height as temp fix, need to figure out better way to handle properties rendering in the modal visibly */
      height: 80vh;
    }
    ^title {
      padding: 32px 0px;
      font-size: 1.5em;
      font-weight: bold;
    }
    ^main {
      padding: 0px 32px;
    }
    ^ .buttons {
      padding: 32px;
      box-sizing: border-box;
      display: flex;
      justify-content: flex-end;
    }
  `,

  messages: [
    { name: 'CONFIRM_DELETE_1', message: 'Are you sure you want to delete' },
    { name: 'SUCCESS_MSG', message: ' deleted' },
    { name: 'FAIL_MSG', message: 'Failed to delete' }
  ],

  properties: [
    {
      class: 'Function',
      name: 'onExecute'
    },
    {
      class: 'String',
      name: 'title',
      expression: function(isModalRequired) {
        if ( isModalRequired ) return 'Please provide fill out the following (required)';
        return 'Please fill out the following (optional)';
      }
    },
    {
      class: 'Property',
      name: 'property'
    },
    {
      class: 'Boolean',
      name: 'isModalRequired'
    },
    {
      name: 'propertyData',
      attribute: true
    },
  ],

  methods: [
    function initE() {
      this.SUPER();
      this
        .addClass(this.myClass())
        .start()
          .addClass(this.myClass('main'))
          .start()
            .addClass(this.myClass('title'))
            .add(this.title)
          .end()
          .startContext({ data: this, controllerMode: this.ControllerMode.EDIT })
          .tag(this.SectionedDetailPropertyView, {
            prop: this.property,
            data$: this.data$
          })
          .endContext()
        .end()
        .start()
          .addClass('buttons')
          .startContext({ data: this })
            .tag(this.CANCEL, { buttonStyle: 'SECONDARY' })
            .tag(this.OK)
          .endContext()
        .end();
    }
  ],

  actions: [
    {
      name: 'ok',
      isEnabled: (isModalRequired, propertyData) => {
        if ( ! isModalRequired ) return true;

        return propertyData;
      },
      code: function(X) {
        this.onExecute();
        X.closeDialog();
      }
    },
    {
      name: 'cancel',
      code: function(X) {
        X.closeDialog();
      }
    }
  ]
});
<|endoftext|>


<commit_before>const config = require("./../../config.json");
const yt = require('ytdl-core');
const fs = require('fs');
const MSS = require('./../../functions/');
const Discord = require("discord.js");
const request = require("request");

var playlist = [];
var stream = [];
var current = [];

exports.sound = sound;
exports.play = play;
exports.add = add;
exports.skip = skip;
exports.stop = stop;
exports.get = get;
exports.list = list;
exports.panel = panel;

//A function to keep playing that stream
function sound(message) {
	var voiceChannel = message.member.voiceChannel;

	voiceChannel.join()
	.then(connnection => {
		//Declare a function that will be called by itself so the play(message) command will be called when required, instead of all at once.
		var looper = function() {
			play(message);
			const dispatcher = connnection.playStream(stream[message.guild.id]);
			dispatcher.on('end', () => {
				looper();
			});
		}
		looper();
	});
}

//A function to generate the streams from the playlist
function play(message) {
	var voiceChannel = message.member.voiceChannel;

	if(!voiceChannel) {
		//Not in voice
		return MSS.msg.react(message, false, "call");
	}

	if (playlist[message.guild.id].length > 0) {
		current[message.guild.id] = JSON.parse(playlist[message.guild.id].shift());
		panel(message);
		switch (current[message.guild.id]["type"]) {
			case "youtube":
				stream[message.guild.id] = yt(current[message.guild.id]["url"], {audioonly: true});
				break;
			case "local":
				stream[message.guild.id] = fs.createReadStream(current[message.guild.id]["url"]);
				break;
			case "http":
			case "https":
				request(current[message.guild.id]["url"])
					.pipe(stream[message.guild.id])
					.on('close', function() {
						console.log("HTTP(s) Stream ended");
					});
		}
	} else {
		if (voiceChannel && voiceChannel.connection) voiceChannel.leave();
		playlist[message.guild.id] = [];
		if (stream[message.guild.id]) stream[message.guild.id].destroy();
		return;
	}
}

//A function to push a new video onto the playlist stack
function add(message, type, url, title, thumb_url) {
	playlist[message.guild.id] = playlist[message.guild.id] || [];
	playlist[message.guild.id].push(JSON.stringify({type: type, url: url, title: title, thumb_url: thumb_url}));
	if (!message.member.voiceChannel.connection) {
		sound(message);
	}
}

function skip(message) {
	var voiceChannel = message.member.voiceChannel;
	if (!voiceChannel || !voiceChannel.connection) {
		//No bot in channel
		return MSS.msg.react(message, false, "robot");
	}
	message.channel.send("Destroying stream...");
	stream[message.guild.id].destroy();
}

function stop(message) {
	var voiceChannel = message.member.voiceChannel;
	if (!voiceChannel || !voiceChannel.connection) {
		//No bot in channel
		return MSS.msg.react(message, false, "robot");
	}

	if (voiceChannel && voiceChannel.connection) voiceChannel.leave();
	current[message.guild.id] = [];
	playlist[message.guild.id] = [];
	if (stream[message.guild.id]) stream[message.guild.id].destroy();
	return;
}

function list(message) {
	//Check if it does not exist, or has less than 1 item remaining.
	if (!playlist[message.guild.id] || playlist[message.guild.id].length < 1) {
		return MSS.msg.rich(message, "MSS Music Player", "There is no music remaining in the playlist.", "#FF0000");
	} else {
		return MSS.msg.rich(message, "MSS Music Player", playlist[message.guild.id].map(function(sound){return JSON.parse(sound).title;}).join("\n"), "#00FF00");
	}
}

function get(message) {
	if(!current[message.guild.id]) {
		return MSS.msg.rich(message, "MSS Music Player", "There is no music currently playing.", "#FF0000");
	}

	var embed = new Discord.RichEmbed()
		.setTitle("MSS Music Player")
		.setAuthor("MSS", "http://moustacheminer.com/mss.png")
		.setColor("#00FF00")
		.setDescription("Now playing: " + current[message.guild.id]["title"])
		.setFooter("MSS-Discord, " + config.MSS.version, "")
		.setTimestamp()
		.setURL(current[message.guild.id]["url"])
		.setImage(current[message.guild.id]["thumb_url"]);

	message.channel.sendEmbed(embed, "", { disableEveryone: true });
}

function panel(message) {
	message.channel.sendMessage('**Music Control Panel**')
	.then(function(message) {
		message.react(String.fromCodePoint(10145));
		message.react(String.fromCodePoint(8505));
		message.react(String.fromCodePoint(128240));
	});
}
<commit_msg>QuickFix<commit_after>const config = require("./../../config.json");
const yt = require('ytdl-core');
const fs = require('fs');
const MSS = require('./../../functions/');
const Discord = require("discord.js");
const request = require("request");

var playlist = [];
var stream = [];
var current = [];

exports.sound = sound;
exports.play = play;
exports.add = add;
exports.skip = skip;
exports.stop = stop;
exports.get = get;
exports.list = list;
exports.panel = panel;

//A function to keep playing that stream
function sound(message) {
	var voiceChannel = message.member.voiceChannel;

	voiceChannel.join()
	.then(connnection => {
		//Declare a function that will be called by itself so the play(message) command will be called when required, instead of all at once.
		var looper = function() {
			play(message);
			const dispatcher = connnection.playStream(stream[message.guild.id]);
			dispatcher.on('end', () => {
				looper();
			});
		}
		looper();
	});
}

//A function to generate the streams from the playlist
function play(message) {
	var voiceChannel = message.member.voiceChannel;

	if(!voiceChannel) {
		//Not in voice
		return MSS.msg.react(message, false, "call");
	}

	if (playlist[message.guild.id].length > 0) {
		current[message.guild.id] = JSON.parse(playlist[message.guild.id].shift());
		panel(message);
		switch (current[message.guild.id]["type"]) {
			case "youtube":
				stream[message.guild.id] = yt(current[message.guild.id]["url"], {audioonly: true});
				break;
			case "local":
				stream[message.guild.id] = fs.createReadStream(current[message.guild.id]["url"]);
				break;
			case "http":
			case "https":
				request(current[message.guild.id]["url"])
					.pipe(stream[message.guild.id])
					.on('close', function() {
						console.log("HTTP(s) Stream ended");
					});
		}
	} else {
		if (voiceChannel && voiceChannel.connection) voiceChannel.leave();
		playlist[message.guild.id] = [];
		if (stream[message.guild.id]) stream[message.guild.id].destroy();
		return;
	}
}

//A function to push a new video onto the playlist stack
function add(message, type, url, title, thumb_url) {
	playlist[message.guild.id] = playlist[message.guild.id] || [];
	playlist[message.guild.id].push(JSON.stringify({type: type, url: url, title: title, thumb_url: thumb_url}));
	if (!message.member.voiceChannel.connection) {
		sound(message);
	}
}

function skip(message) {
	var voiceChannel = message.member.voiceChannel;
	if (!voiceChannel || !voiceChannel.connection) {
		//No bot in channel
		return MSS.msg.react(message, false, "robot");
	}
	message.channel.send("Destroying stream...");
	stream[message.guild.id].destroy();
}

function stop(message) {
	var voiceChannel = message.member.voiceChannel;
	if (!voiceChannel || !voiceChannel.connection) {
		//No bot in channel
		return MSS.msg.react(message, false, "robot");
	}

	if (voiceChannel && voiceChannel.connection) voiceChannel.leave();
	current[message.guild.id] = [];
	playlist[message.guild.id] = [];
	if (stream[message.guild.id]) stream[message.guild.id].destroy();
	return;
}

function list(message) {
	//Check if it does not exist, or has less than 1 item remaining.
	if (!playlist[message.guild.id] || playlist[message.guild.id].length < 1) {
		return MSS.msg.rich(message, "MSS Music Player", "There is no music remaining in the playlist.", "#FF0000");
	} else {
		return MSS.msg.rich(message, "MSS Music Player", playlist[message.guild.id].map(function(sound){return JSON.parse(sound).title;}).join("\n"), "#00FF00");
	}
}

function get(message) {
	if(!message.guild) {
		return MSS.msg.rich(message, "MSS Music Player", "You cannot use this in a DM channel!", "#FF0000");
	}

	if(!current[message.guild.id]) {
		return MSS.msg.rich(message, "MSS Music Player", "There is no music currently playing.", "#FF0000");
	}

	var embed = new Discord.RichEmbed()
		.setTitle("MSS Music Player")
		.setAuthor("MSS", "http://moustacheminer.com/mss.png")
		.setColor("#00FF00")
		.setDescription("Now playing: " + current[message.guild.id]["title"])
		.setFooter("MSS-Discord, " + config.MSS.version, "")
		.setTimestamp()
		.setURL(current[message.guild.id]["url"])
		.setImage(current[message.guild.id]["thumb_url"]);

	message.channel.sendEmbed(embed, "", { disableEveryone: true });
}

function panel(message) {
	message.channel.sendMessage('**Music Control Panel**')
	.then(function(message) {
		message.react(String.fromCodePoint(10145));
		message.react(String.fromCodePoint(8505));
		message.react(String.fromCodePoint(128240));
	});
}
<|endoftext|>


<commit_before>const Player = require("./player.js");
const MSS = require('./../../functions/');

const Players = [];

exports.init = init;
exports.add = add;
exports.stop = stop;
exports.skip = skip;
exports.list = list;

function init(message) {
	console.log(typeof Players[message.guild.id]);
	if(typeof Players[message.guild.id] === 'undefined') {
		Players[message.guild.id] = new Player(message);
	}
}

function add(message, type, url, title, thumb) {
	if (!message.guild) return guildError(message);
	init(message);
	Players[message.guild.id].add(type, url, title, thumb);
}

function stop(message) {
	if (!message.guild) return guildError(message);
	init(message);
	if (!botCheck(message)) return;
	if (!adminCheck(message)) return;
	Players[message.guild.id].stop();
}

function skip(message) {
	if (!message.guild) return guildError(message);
	init(message);
	if (!botCheck(message)) return;
	if (!adminCheck(message)) return;
	Players[message.guild.id].skip();
}

function list(message) {
	if (!message.guild) return;
	init(message);
	if (!botCheck(message)) return;
	if(Players[message.guild.id].playlist.length > 0) {
		var string = "Playlist\n"
		string += Players[message.guild.id].playlist.join("\n");
		Players[message.guild.id].channel.send(string)
	} else {
		Players[message.guild.id].channel.send("The Playlist is empty")
	}
}

function guildError(message) {
	message.channel.send("You cannot run this command outside a guild!");
}

function botCheck(message) {
	if (Players[message.guild.id].voicechannel && Players[message.guild.id].voicechannel.connection) {
		return true;
	} else {
		Players[message.guild.id].channel.send("There is no bot in your channel");
		return false;
	}
}

function adminCheck(message) {
	if(MSS.msg.isadmin(message)) {
		return true;
	} else {
		Players[message.guild.id].channel.send("You are not an Administrator!");
		return false;
	}
}
<commit_msg>Re-abuse every<commit_after>const Player = require("./player.js");
const MSS = require('./../../functions/');

const Players = [];

exports.init = init;
exports.add = add;
exports.stop = stop;
exports.skip = skip;
exports.list = list;

function init(message) {
	console.log(typeof Players[message.guild.id]);
	if(typeof Players[message.guild.id] === 'undefined') {
		Players[message.guild.id] = new Player(message);
	}
}

function add(message, type, url, title, thumb) {
	if (!message.guild) return guildError(message);
	init(message);
	Players[message.guild.id].add(type, url, title, thumb);
}

function stop(message) {
	if (!message.guild) return guildError(message);
	init(message);
	if (!botCheck(message)) return;
	if (!adminCheck(message)) return;
	Players[message.guild.id].stop();
}

function skip(message) {
	if (!message.guild) return guildError(message);
	init(message);
	if (!botCheck(message)) return;
	if (!adminCheck(message)) return;
	Players[message.guild.id].skip();
}

function list(message) {
	if (!message.guild) return;
	init(message);
	if (!botCheck(message)) return;
	if(Players[message.guild.id].playlist.length > 0) {
		var string = "Playlist\n"
		Players[message.guild.id].playlist.every((elem, index) => {
			if((`${string}\n${index} - ${elem.name}`).length < 1900) {
				string += `...`
				return false;
			} else {
				string += `\n${index} - ${elem.name}`;
				return true;
			}
		});
		Players[message.guild.id].channel.send(string)
	} else {
		Players[message.guild.id].channel.send("The Playlist is empty")
	}
}

function guildError(message) {
	message.channel.send("You cannot run this command outside a guild!");
}

function botCheck(message) {
	if (Players[message.guild.id].voicechannel && Players[message.guild.id].voicechannel.connection) {
		return true;
	} else {
		Players[message.guild.id].channel.send("There is no bot in your channel");
		return false;
	}
}

function adminCheck(message) {
	if(MSS.msg.isadmin(message)) {
		return true;
	} else {
		Players[message.guild.id].channel.send("You are not an Administrator!");
		return false;
	}
}
<|endoftext|>


<commit_before>'use strict';

//Start by defining the main module and adding the module dependencies
angular.module(ApplicationConfiguration.applicationModuleName, ApplicationConfiguration.applicationModuleVendorDependencies);

// Setting HTML5 Location Mode
angular.module(ApplicationConfiguration.applicationModuleName).config(['$locationProvider',
	function($locationProvider) {
		$locationProvider.hashPrefix('!');

        // use the HTML5 History API
        $locationProvider.html5Mode(true);
	}
]);

//Then define the init function for starting up the application
angular.element(document).ready(function() {
	//Fixing facebook bug with redirect
	if (window.location.hash === '#_=_') window.location.hash = '#!';

	//Then init the app
	angular.bootstrap(document, [ApplicationConfiguration.applicationModuleName]);

    // Initialize Stripe with your publisher key
    window.Stripe.setPublishableKey('pk_test_FCra1cSGL6KWxLBExXOfiaih');
});<commit_msg>turn off pushState, for now, to keep client and server routes distinct<commit_after>'use strict';

//Start by defining the main module and adding the module dependencies
angular.module(ApplicationConfiguration.applicationModuleName, ApplicationConfiguration.applicationModuleVendorDependencies);

// Setting HTML5 Location Mode
angular.module(ApplicationConfiguration.applicationModuleName).config(['$locationProvider',
	function($locationProvider) {
		$locationProvider.hashPrefix('!');

        // use the HTML5 History API
        // $locationProvider.html5Mode(true);
	}
]);

//Then define the init function for starting up the application
angular.element(document).ready(function() {
	//Fixing facebook bug with redirect
	if (window.location.hash === '#_=_') window.location.hash = '#!';

	//Then init the app
	angular.bootstrap(document, [ApplicationConfiguration.applicationModuleName]);

    // Initialize Stripe with your publisher key
    window.Stripe.setPublishableKey('pk_test_FCra1cSGL6KWxLBExXOfiaih');
});<|endoftext|>


<commit_before>var phaxMachine = {
	faxLogs: {
		render: function() {
			$.getJSON("/logs.json", {}, function(response, status, jqXHR) {
				if (response.success) {
					phaxMachine.createAlert("success", response.message)
					phaxMachine.faxLogs.populateFaxLogsTable(response.data)
					phaxMachine.faxLogs.makeRecipientsClickable()
				}
				else {
					phaxMachine.createAlert("danger", response.message)
				}

				phaxMachine.faxLogs.hideLoadingRow()
			})
		},

		hideLoadingRow: function() {
			$("#loading-row").hide()
		},

		populateFaxLogsTable: function(faxesData) {
			var logAttributes = [
				"id", "num_pages", "cost", "direction", "status", "type",
				"requested_at", "recipients"
			]

			faxesData.forEach(function(faxData) {
				faxData = phaxMachine.faxLogs.processFaxData(faxData)

				var tableRow = $("

")

				var faxFileCell = $(
					''
					+ ''
					+ ''
					+ ''
					+ '	'
				)

				tableRow.append(faxFileCell)

				logAttributes.forEach(function(logAttribute) {
					var cell = $("	")
					cell.data("fax-attribute", logAttribute)
					cell.append(faxData[logAttribute])
					tableRow.append(cell)
				})
				tableRow.data("recipients", faxData.recipientsData)
				$("#fax-log-table").find("tbody").append(tableRow)
			})
		},

		makeRecipientsClickable: function() {
			var recipientCells = $("#fax-log-table").find("td").filter(function() {
				return $(this).data("fax-attribute") === "recipients"
			})
			recipientCells.each(function() {
				var recipientCountStr = $(this).text()
				if (recipientCountStr === '-') {
					return
				}

				recipientCount = parseInt(recipientCountStr)
				recipientsDataLink = $("" + recipientCount + "")
				recipientsDataLink.on("click", phaxMachine.faxLogs.displayRecipientsDataModal)
				$(this).html(recipientsDataLink)
			})
		},

		displayRecipientsDataModal: function() {
			var tableRow = $(this).closest("tr")
			var recipientsData = tableRow.data("recipients")
			var modal = $("#recipientsDataModal")
			var recipientAttributes = [
				"bitrate", "completed_at", "number", "resolution", "status"
			]
			var recipientsTable = $("#recipientsDataTable")

			recipientsTable.find("tbody").find("tr").remove()

			recipientsData.forEach(function(recipientData) {
				var recipientRow = $("

")
				var recipientData = phaxMachine.faxLogs.processRecipientData(recipientData)

				recipientAttributes.forEach(function(recipientAttribute) {
					var cell = $("" + recipientData[recipientAttribute] + "	")
					recipientRow.append(cell)
				})

				recipientsTable.find("tbody").append(recipientRow)
			})
			modal.modal("show")
		},

		processRecipientData: function(recipientData) {
			return {
				"bitrate": recipientData.bitrate,
				"completed_at": phaxMachine.faxLogs.formatTimestamp(recipientData.completed_at),
				"number": recipientData.number,
				"resolution": recipientData.resolution,
				"status": phaxMachine.faxLogs.formatStatus(recipientData.status)
			}
		},

		processFaxData: function(faxData) {
			processedFaxData = {
				"id": faxData.id,
				"num_pages": faxData.num_pages,
				"cost": phaxMachine.faxLogs.formatMoney(faxData.cost),
				"direction": phaxMachine.faxLogs.capitalize(faxData.direction),
				"status": phaxMachine.faxLogs.formatStatus(faxData.status),
				"type": phaxMachine.faxLogs.formatType(faxData.is_test),
				"requested_at": phaxMachine.faxLogs.formatTimestamp(faxData.requested_at)
			}

			if (faxData.direction === 'sent') {
				processedFaxData.recipients = faxData.recipients.length
				processedFaxData.recipientsData = faxData.recipients
			}
			else {
				processedFaxData.recipients = '-'
			}

			return processedFaxData
		},

		formatMoney: function(valueInCents) {
			var valueString = String(valueInCents)
			while (valueString.length < 3)
				valueString = "0" + valueString
			var valueChars = valueString.split("")
			valueChars.splice(-2, 0, ".")
			return "$" + valueChars.join("")
		},

		capitalize: function(string) {
			chars = string.split('')
			chars[0] = chars[0].toUpperCase()
			return chars.join('')
		},

		formatStatus: function(statusStr) {
			var statusMap = {
				building:       ['Building',        'info'   ],
				pendingbatch:   ['Batching',        'info'   ],
				queued:         ['Queued',          'info'   ],
				inprogress:     ['In Progress',     'info'   ],
				ringing:        ['Ringing',         'info'   ],
				callactive:     ['Call Active',     'info'   ],
				success:        ['Success',         'success'],
				partialsuccess: ['Partial Success', 'warning'],
				willretry:      ['Will Retry',      'warning'],
				failure:        ['Failure',         'danger' ]
			}

			var [statusText, statusClass] = statusMap[statusStr]

			return "" + statusText + ""
		},

		formatType: function(isTest) {
			if (isTest) {
				return 'Test'
			}
			else {
				return 'Live'
			}
		},

		formatTimestamp: function(timeInSeconds) {
			// Value must be converted to milliseconds
			return String(new Date(timeInSeconds * 1000))
		}
	},

	sendFax: {
		render: function() {
			$("#sendFaxForm").on("submit", function(e) {
				$.ajax('/send', {
					type: 'POST',
					data: new FormData(this),
					cache: false,
					contentType: false,
					processData: false,
					xhr: function() {
						var jqXhr = $.ajaxSettings.xhr()

						if (jqXhr.upload) {
							jqXhr.upload.addEventListener('progress', function(e) {
								if (e.lengthComputable) {
									var percentStr = String(Math.floor(100 * (e.loaded / e.total)))
									$("#faxFileProgress").show().text(
										"Uploading file: " + percentStr + "%"
									)
								}
							},
							false)
						}

						return jqXhr
					}
				}).done(function(response, _textStatus, _jqXhr) {
					responseJson = JSON.parse(response)
					if (responseJson.success) {
						var message = "Fax #" + responseJson.faxId + " queued for sending."
						phaxMachine.createAlert("success", message)
					}
					else {
						phaxMachine.createAlert("danger", responseJson.message)
					}
				})

				e.preventDefault()
			})
		}
	},

	createAlert: function(type, message) {
		var alert = $("

")
		var closeAlertButton = $(
			'<button type="button" class="close" data-dismiss="alert" aria-label="Close">'
			+ '×'
			+ '</button>'
		)
		alert.append(closeAlertButton)
		alert.append(message)
		$("#alerts").append(alert)
	}
}

$(document).ready(function() {
	pageScript = phaxMachine[$("main").attr("id")]
	if (pageScript != null) {
		pageScript.render()
	}
})

<commit_msg>Omit file links for faxes without pages<commit_after>var phaxMachine = {
	faxLogs: {
		render: function() {
			$.getJSON("/logs.json", {}, function(response, status, jqXHR) {
				if (response.success) {
					phaxMachine.createAlert("success", response.message)
					phaxMachine.faxLogs.populateFaxLogsTable(response.data)
					phaxMachine.faxLogs.makeRecipientsClickable()
				}
				else {
					phaxMachine.createAlert("danger", response.message)
				}

				phaxMachine.faxLogs.hideLoadingRow()
			})
		},

		hideLoadingRow: function() {
			$("#loading-row").hide()
		},

		populateFaxLogsTable: function(faxesData) {
			var logAttributes = [
				"id", "num_pages", "cost", "direction", "status", "type",
				"requested_at", "recipients"
			]

			faxesData.forEach(function(faxData) {
				faxData = phaxMachine.faxLogs.processFaxData(faxData)

				var tableRow = $("

")

				var faxFileCell
				if (faxData.num_pages > 0) {
					faxFileCell = $(
						''
						+ ''
						+ ''
						+ ''
						+ '	'
					)
				}
				else {
					faxFileCell = $('-	')
				}

				tableRow.append(faxFileCell)

				logAttributes.forEach(function(logAttribute) {
					var cell = $("	")
					cell.data("fax-attribute", logAttribute)
					cell.append(faxData[logAttribute])
					tableRow.append(cell)
				})
				tableRow.data("recipients", faxData.recipientsData)
				$("#fax-log-table").find("tbody").append(tableRow)
			})
		},

		makeRecipientsClickable: function() {
			var recipientCells = $("#fax-log-table").find("td").filter(function() {
				return $(this).data("fax-attribute") === "recipients"
			})
			recipientCells.each(function() {
				var recipientCountStr = $(this).text()
				if (recipientCountStr === '-') {
					return
				}

				recipientCount = parseInt(recipientCountStr)
				recipientsDataLink = $("" + recipientCount + "")
				recipientsDataLink.on("click", phaxMachine.faxLogs.displayRecipientsDataModal)
				$(this).html(recipientsDataLink)
			})
		},

		displayRecipientsDataModal: function() {
			var tableRow = $(this).closest("tr")
			var recipientsData = tableRow.data("recipients")
			var modal = $("#recipientsDataModal")
			var recipientAttributes = [
				"bitrate", "completed_at", "number", "resolution", "status"
			]
			var recipientsTable = $("#recipientsDataTable")

			recipientsTable.find("tbody").find("tr").remove()

			recipientsData.forEach(function(recipientData) {
				var recipientRow = $("

")
				var recipientData = phaxMachine.faxLogs.processRecipientData(recipientData)

				recipientAttributes.forEach(function(recipientAttribute) {
					var cell = $("" + recipientData[recipientAttribute] + "	")
					recipientRow.append(cell)
				})

				recipientsTable.find("tbody").append(recipientRow)
			})
			modal.modal("show")
		},

		processRecipientData: function(recipientData) {
			return {
				"bitrate": recipientData.bitrate,
				"completed_at": phaxMachine.faxLogs.formatTimestamp(recipientData.completed_at),
				"number": recipientData.number,
				"resolution": recipientData.resolution,
				"status": phaxMachine.faxLogs.formatStatus(recipientData.status)
			}
		},

		processFaxData: function(faxData) {
			processedFaxData = {
				"id": faxData.id,
				"num_pages": faxData.num_pages,
				"cost": phaxMachine.faxLogs.formatMoney(faxData.cost),
				"direction": phaxMachine.faxLogs.capitalize(faxData.direction),
				"status": phaxMachine.faxLogs.formatStatus(faxData.status),
				"type": phaxMachine.faxLogs.formatType(faxData.is_test),
				"requested_at": phaxMachine.faxLogs.formatTimestamp(faxData.requested_at)
			}

			if (faxData.direction === 'sent') {
				processedFaxData.recipients = faxData.recipients.length
				processedFaxData.recipientsData = faxData.recipients
			}
			else {
				processedFaxData.recipients = '-'
			}

			return processedFaxData
		},

		formatMoney: function(valueInCents) {
			var valueString = String(valueInCents)
			while (valueString.length < 3)
				valueString = "0" + valueString
			var valueChars = valueString.split("")
			valueChars.splice(-2, 0, ".")
			return "$" + valueChars.join("")
		},

		capitalize: function(string) {
			chars = string.split('')
			chars[0] = chars[0].toUpperCase()
			return chars.join('')
		},

		formatStatus: function(statusStr) {
			var statusMap = {
				building:       ['Building',        'info'   ],
				pendingbatch:   ['Batching',        'info'   ],
				queued:         ['Queued',          'info'   ],
				inprogress:     ['In Progress',     'info'   ],
				ringing:        ['Ringing',         'info'   ],
				callactive:     ['Call Active',     'info'   ],
				success:        ['Success',         'success'],
				partialsuccess: ['Partial Success', 'warning'],
				willretry:      ['Will Retry',      'warning'],
				failure:        ['Failure',         'danger' ]
			}

			var [statusText, statusClass] = statusMap[statusStr]

			return "" + statusText + ""
		},

		formatType: function(isTest) {
			if (isTest) {
				return 'Test'
			}
			else {
				return 'Live'
			}
		},

		formatTimestamp: function(timeInSeconds) {
			// Value must be converted to milliseconds
			return String(new Date(timeInSeconds * 1000))
		}
	},

	sendFax: {
		render: function() {
			$("#sendFaxForm").on("submit", function(e) {
				$.ajax('/send', {
					type: 'POST',
					data: new FormData(this),
					cache: false,
					contentType: false,
					processData: false,
					xhr: function() {
						var jqXhr = $.ajaxSettings.xhr()

						if (jqXhr.upload) {
							jqXhr.upload.addEventListener('progress', function(e) {
								if (e.lengthComputable) {
									var percentStr = String(Math.floor(100 * (e.loaded / e.total)))
									$("#faxFileProgress").show().text(
										"Uploading file: " + percentStr + "%"
									)
								}
							},
							false)
						}

						return jqXhr
					}
				}).done(function(response, _textStatus, _jqXhr) {
					responseJson = JSON.parse(response)
					if (responseJson.success) {
						var message = "Fax #" + responseJson.faxId + " queued for sending."
						phaxMachine.createAlert("success", message)
					}
					else {
						phaxMachine.createAlert("danger", responseJson.message)
					}
				})

				e.preventDefault()
			})
		}
	},

	createAlert: function(type, message) {
		var alert = $("

")
		var closeAlertButton = $(
			'<button type="button" class="close" data-dismiss="alert" aria-label="Close">'
			+ '×'
			+ '</button>'
		)
		alert.append(closeAlertButton)
		alert.append(message)
		$("#alerts").append(alert)
	}
}

$(document).ready(function() {
	pageScript = phaxMachine[$("main").attr("id")]
	if (pageScript != null) {
		pageScript.render()
	}
})

<|endoftext|>


<commit_before>/*
 *      This file is part of GPaste.
 *
 *      Copyright 2014 Marc-Antoine Perennou <Marc-Antoine@Perennou.com>
 *
 *      GPaste is free software: you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation, either version 3 of the License, or
 *      (at your option) any later version.
 *
 *      GPaste is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with GPaste.  If not, see <http://www.gnu.org/licenses/>.
 */
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */

const Gettext = imports.gettext;
const Lang = imports.lang;

const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;

const Clutter = imports.gi.Clutter;

const GPaste = imports.gi.GPaste;

const _ = Gettext.domain('GPaste').gettext;

const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();

const AboutItem = Me.imports.aboutItem;
const DummyHistoryItem = Me.imports.dummyHistoryItem;
const EmptyHistoryItem = Me.imports.emptyHistoryItem;
const Item = Me.imports.item;
const PrefsItem = Me.imports.prefsItem;
const SearchItem = Me.imports.searchItem;
const StateSwitch = Me.imports.stateSwitch;
const StatusIcon = Me.imports.statusIcon;

const GPasteIndicator = new Lang.Class({
    Name: 'GPasteIndicator',
    Extends: PanelMenu.Button,

    _init: function() {
        this.parent(0.0, "GPaste");

        this.actor.add_child(new StatusIcon.GPasteStatusIcon());

        this._settings = new GPaste.Settings();

        this._headerSize = 0;
        this._postHeaderSize = 0;
        this._history = [];
        this._preFooterSize = 0;
        this._footerSize = 0;

        this._dummyHistoryItem = new DummyHistoryItem.GPasteDummyHistoryItem();

        this._searchItem = new SearchItem.GPasteSearchItem();
        this._searchItem.connect('text-changed', Lang.bind(this, this._onSearch));

        this._settingsSizeChangedId = this._settings.connect('changed::element-size', Lang.bind(this, this._resetEntrySize));
        this._resetEntrySize();
        this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));

        this._actions = new PopupMenu.PopupBaseMenuItem({
            reactive: false,
            can_focus: false
        });

        this._addToPostHeader(new PopupMenu.PopupSeparatorMenuItem());
        this._addToPostHeader(this._dummyHistoryItem);
        this._addToPreFooter(new PopupMenu.PopupSeparatorMenuItem());
        this._addToFooter(this._actions);

        GPaste.Client.new(Lang.bind(this, function (obj, result) {
            this._client = GPaste.Client.new_finish(result);

            this._dummyHistoryItem.update();
            this._prefsItem = new PrefsItem.GPastePrefsItem(this.menu);
            this._emptyHistoryItem = new EmptyHistoryItem.GPasteEmptyHistoryItem(this._client);

            this._addToHeader(new StateSwitch.GPasteStateSwitch(this._client));
            this._addToHeader(this._searchItem);
            this._actions.actor.add(this._prefsItem, { expand: true, x_fill: false });
            this._actions.actor.add(this._emptyHistoryItem, { expand: true, x_fill: false });
            this._actions.actor.add(new AboutItem.GPasteAboutItem(this._client, this.menu), { expand: true, x_fill: false });

            this._settingsMaxSizeChangedId = this._settings.connect('changed::max-displayed-history-size', Lang.bind(this, this._resetMaxDisplayedSize));
            this._resetMaxDisplayedSize();

            this._clientUpdateId = this._client.connect('update', Lang.bind(this, this._update));
            this._clientShowId = this._client.connect('show-history', Lang.bind(this, this._popup));

            this._onStateChanged (true);

            this.menu.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
            this.menu.actor.connect('key-release-event', Lang.bind(this, this._onKeyReleaseEvent));

            this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
        }));
    },

    shutdown: function() {
        this._onStateChanged (false);
        this.destroy();
    },

    _onKeyPressEvent: function(actor, event) {
        if (event.has_control_modifier()) {
            let nb = parseInt(event.get_key_unicode());
            if (nb != NaN && nb >= 0 && nb <= 9 && nb < this._history.length) {
                this._history[nb].activate();
            }
        } else {
            this._maybeUpdateIndexVisibility(event, true);
        }
    },

    _onKeyReleaseEvent: function(actor, event) {
        this._maybeUpdateIndexVisibility(event, false);
    },

    _maybeUpdateIndexVisibility: function(event, state) {
        let key = event.get_key_symbol();
        if (key == Clutter.KEY_Control_L || key == Clutter.KEY_Control_R) {
            this._updateIndexVisibility(state);
        }
    },

    _updateIndexVisibility: function(state) {
        for (let i = 0; i < 10 && i < this._history.length; ++i) {
            this._history[i].showIndex(state);
        }
    },

    _onSearch: function() {
        let search = this._searchItem.text.toLowerCase();
        /* FIXME: add back search */
    },

    _resetEntrySize: function() {
        this._searchItem.resetSize(this._settings.get_element_size()/2 + 3);
    },

    _setMaxDisplayedSize: function() {
    },

    _resetMaxDisplayedSize: function() {
        let oldSize = this._history.length;
        let newSize = this._settings.get_max_displayed_history_size();

        if (newSize > oldSize) {
            for (let index = oldSize; index < newSize; ++index) {
                let item = new Item.GPasteItem(this._client, this._settings, index);
                this.menu.addMenuItem(item, this._headerSize + this._postHeaderSize + index);
                this._history[index] = item;
            }
        } else {
            for (let i = newSize; i < oldSize; ++i) {
                this._history.pop().destroy();
            }
        }

        this._updateVisibility(newSize == 0);
    },

    _update: function(client, action, target, position) {
        switch (target) {
        case GPaste.UpdateTarget.ALL:
            this._refresh(0);
            break;
        case GPaste.UpdateTarget.POSITION:
            switch (action) {
            case GPaste.UpdateAction.REPLACE:
                this._history[position].refresh();
                break;
            case GPaste.UpdateAction.REMOVE:
                this._refresh(position);
                break;
            }
            break;
        }
    },

    _refresh: function(resetTextFrom) {
        this._client.get_history_size(Lang.bind(this, function(client, result) {
            let size = client.get_history_size_finish(result);
            let maxSize = this._history.length;

            if (size > maxSize)
                size = maxSize;

            for (let i = resetTextFrom; i < size; ++i) {
                this._history[i].setIndex(i);
            }
            for (let i = size ; i < maxSize; ++i) {
                this._history[i].setIndex(-1);
            }
        }));
    },

    _updateVisibility: function(empty) {
        if (empty) {
            this._dummyHistoryItem.actor.show();
            this._emptyHistoryItem.hide();
            this._searchItem.actor.hide();
        } else {
            this._dummyHistoryItem.actor.hide();
            this._emptyHistoryItem.show();
            this._searchItem.actor.show();
        }
    },

    _popup: function() {
        this.menu.open(true);
        this._selectSearch(true);
    },

    _selectSearch: function(active) {
        if (this._history.length > 0) {
            this._searchItem.setActive(active);
        }
    },

    _addToHeader: function(item) {
        this.menu.addMenuItem(item, this._headerSize++);
    },

    _addToPostHeader: function(item) {
        this.menu.addMenuItem(item, this._headerSize + this._postHeaderSize++);
    },

    _addToPreFooter: function(item) {
        this.menu.addMenuItem(item, this._headerSize + this._postHeaderSize + this._history.length + this._preFooterSize++);
    },

    _addToFooter: function(item) {
        this.menu.addMenuItem(item, this._headerSize + this._postHeaderSize + this._history.length + this._preFooterSize + this._footerSize++);
    },

    _onStateChanged: function(state) {
        this._client.on_extension_state_changed(state, null);
    },

    _onOpenStateChanged: function(menu, state) {
        if (state) {
            this._searchItem.reset();
        } else {
            this._updateIndexVisibility(false);
        }
    },

    _onDestroy: function() {
        this._client.disconnect(this._clientUpdateId);
        this._client.disconnect(this._clientShowId);
        this._settings.disconnect(this._settingsMaxSizeChangedId);
        this._settings.disconnect(this._settingsSizeChangedId);
    }
});

<commit_msg>gnome-shell: fix empty<commit_after>/*
 *      This file is part of GPaste.
 *
 *      Copyright 2014 Marc-Antoine Perennou <Marc-Antoine@Perennou.com>
 *
 *      GPaste is free software: you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation, either version 3 of the License, or
 *      (at your option) any later version.
 *
 *      GPaste is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with GPaste.  If not, see <http://www.gnu.org/licenses/>.
 */
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */

const Gettext = imports.gettext;
const Lang = imports.lang;

const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;

const Clutter = imports.gi.Clutter;

const GPaste = imports.gi.GPaste;

const _ = Gettext.domain('GPaste').gettext;

const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();

const AboutItem = Me.imports.aboutItem;
const DummyHistoryItem = Me.imports.dummyHistoryItem;
const EmptyHistoryItem = Me.imports.emptyHistoryItem;
const Item = Me.imports.item;
const PrefsItem = Me.imports.prefsItem;
const SearchItem = Me.imports.searchItem;
const StateSwitch = Me.imports.stateSwitch;
const StatusIcon = Me.imports.statusIcon;

const GPasteIndicator = new Lang.Class({
    Name: 'GPasteIndicator',
    Extends: PanelMenu.Button,

    _init: function() {
        this.parent(0.0, "GPaste");

        this.actor.add_child(new StatusIcon.GPasteStatusIcon());

        this._settings = new GPaste.Settings();

        this._headerSize = 0;
        this._postHeaderSize = 0;
        this._history = [];
        this._preFooterSize = 0;
        this._footerSize = 0;

        this._dummyHistoryItem = new DummyHistoryItem.GPasteDummyHistoryItem();

        this._searchItem = new SearchItem.GPasteSearchItem();
        this._searchItem.connect('text-changed', Lang.bind(this, this._onSearch));

        this._settingsSizeChangedId = this._settings.connect('changed::element-size', Lang.bind(this, this._resetEntrySize));
        this._resetEntrySize();
        this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));

        this._actions = new PopupMenu.PopupBaseMenuItem({
            reactive: false,
            can_focus: false
        });

        this._addToPostHeader(new PopupMenu.PopupSeparatorMenuItem());
        this._addToPostHeader(this._dummyHistoryItem);
        this._addToPreFooter(new PopupMenu.PopupSeparatorMenuItem());
        this._addToFooter(this._actions);

        GPaste.Client.new(Lang.bind(this, function (obj, result) {
            this._client = GPaste.Client.new_finish(result);

            this._dummyHistoryItem.update();
            this._prefsItem = new PrefsItem.GPastePrefsItem(this.menu);
            this._emptyHistoryItem = new EmptyHistoryItem.GPasteEmptyHistoryItem(this._client);

            this._addToHeader(new StateSwitch.GPasteStateSwitch(this._client));
            this._addToHeader(this._searchItem);
            this._actions.actor.add(this._prefsItem, { expand: true, x_fill: false });
            this._actions.actor.add(this._emptyHistoryItem, { expand: true, x_fill: false });
            this._actions.actor.add(new AboutItem.GPasteAboutItem(this._client, this.menu), { expand: true, x_fill: false });

            this._settingsMaxSizeChangedId = this._settings.connect('changed::max-displayed-history-size', Lang.bind(this, this._resetMaxDisplayedSize));
            this._resetMaxDisplayedSize();

            this._clientUpdateId = this._client.connect('update', Lang.bind(this, this._update));
            this._clientShowId = this._client.connect('show-history', Lang.bind(this, this._popup));

            this._onStateChanged (true);

            this.menu.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
            this.menu.actor.connect('key-release-event', Lang.bind(this, this._onKeyReleaseEvent));

            this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
        }));
    },

    shutdown: function() {
        this._onStateChanged (false);
        this.destroy();
    },

    _onKeyPressEvent: function(actor, event) {
        if (event.has_control_modifier()) {
            let nb = parseInt(event.get_key_unicode());
            if (nb != NaN && nb >= 0 && nb <= 9 && nb < this._history.length) {
                this._history[nb].activate();
            }
        } else {
            this._maybeUpdateIndexVisibility(event, true);
        }
    },

    _onKeyReleaseEvent: function(actor, event) {
        this._maybeUpdateIndexVisibility(event, false);
    },

    _maybeUpdateIndexVisibility: function(event, state) {
        let key = event.get_key_symbol();
        if (key == Clutter.KEY_Control_L || key == Clutter.KEY_Control_R) {
            this._updateIndexVisibility(state);
        }
    },

    _updateIndexVisibility: function(state) {
        for (let i = 0; i < 10 && i < this._history.length; ++i) {
            this._history[i].showIndex(state);
        }
    },

    _onSearch: function() {
        let search = this._searchItem.text.toLowerCase();
        /* FIXME: add back search */
    },

    _resetEntrySize: function() {
        this._searchItem.resetSize(this._settings.get_element_size()/2 + 3);
    },

    _setMaxDisplayedSize: function() {
    },

    _resetMaxDisplayedSize: function() {
        let oldSize = this._history.length;
        let newSize = this._settings.get_max_displayed_history_size();

        if (newSize > oldSize) {
            for (let index = oldSize; index < newSize; ++index) {
                let item = new Item.GPasteItem(this._client, this._settings, index);
                this.menu.addMenuItem(item, this._headerSize + this._postHeaderSize + index);
                this._history[index] = item;
            }
        } else {
            for (let i = newSize; i < oldSize; ++i) {
                this._history.pop().destroy();
            }
        }

        this._updateVisibility(newSize == 0);
    },

    _update: function(client, action, target, position) {
        switch (target) {
        case GPaste.UpdateTarget.ALL:
            this._refresh(0);
            break;
        case GPaste.UpdateTarget.POSITION:
            switch (action) {
            case GPaste.UpdateAction.REPLACE:
                this._history[position].refresh();
                break;
            case GPaste.UpdateAction.REMOVE:
                this._refresh(position);
                break;
            }
            break;
        }
    },

    _refresh: function(resetTextFrom) {
        this._client.get_history_size(Lang.bind(this, function(client, result) {
            let size = client.get_history_size_finish(result);
            let maxSize = this._history.length;

            if (size > maxSize)
                size = maxSize;

            for (let i = resetTextFrom; i < size; ++i) {
                this._history[i].setIndex(i);
            }
            for (let i = size ; i < maxSize; ++i) {
                this._history[i].setIndex(-1);
            }

            this._updateVisibility(size == 0);
        }));
    },

    _updateVisibility: function(empty) {
        if (empty) {
            this._dummyHistoryItem.actor.show();
            this._emptyHistoryItem.hide();
            this._searchItem.actor.hide();
        } else {
            this._dummyHistoryItem.actor.hide();
            this._emptyHistoryItem.show();
            this._searchItem.actor.show();
        }
    },

    _popup: function() {
        this.menu.open(true);
        this._selectSearch(true);
    },

    _selectSearch: function(active) {
        if (this._history.length > 0) {
            this._searchItem.setActive(active);
        }
    },

    _addToHeader: function(item) {
        this.menu.addMenuItem(item, this._headerSize++);
    },

    _addToPostHeader: function(item) {
        this.menu.addMenuItem(item, this._headerSize + this._postHeaderSize++);
    },

    _addToPreFooter: function(item) {
        this.menu.addMenuItem(item, this._headerSize + this._postHeaderSize + this._history.length + this._preFooterSize++);
    },

    _addToFooter: function(item) {
        this.menu.addMenuItem(item, this._headerSize + this._postHeaderSize + this._history.length + this._preFooterSize + this._footerSize++);
    },

    _onStateChanged: function(state) {
        this._client.on_extension_state_changed(state, null);
    },

    _onOpenStateChanged: function(menu, state) {
        if (state) {
            this._searchItem.reset();
        } else {
            this._updateIndexVisibility(false);
        }
    },

    _onDestroy: function() {
        this._client.disconnect(this._clientUpdateId);
        this._client.disconnect(this._clientShowId);
        this._settings.disconnect(this._settingsMaxSizeChangedId);
        this._settings.disconnect(this._settingsSizeChangedId);
    }
});

<|endoftext|>


<commit_before>#!/usr/bin/env node

var piphone = {};

piphone.mods = {};
piphone.mods.gpiobutton = require('gpiobutton');
piphone.mods.cp = require('child_process');

piphone.hook = new piphone.mods.gpiobutton.button({name:'hook', gpiono:22, DOWN:1});
piphone.dial = new piphone.mods.gpiobutton.button({name:'dial', gpiono:27});
piphone.rotary = new piphone.mods.gpiobutton.button({name:'rotary', gpiono:17, interval:30, DOWN:1});
piphone.onoff = new piphone.mods.gpiobutton.button({name:'switch', gpiono: 18});

piphone.code = {};
piphone.code.curr = [];

piphone.rotary.on('multipress', function(spec) {
  piphone.code.curr.push(spec.count);

  if (piphone.code.unlisten) {
    clearTimeout(piphone.code.unlisten);
  }

  var code = piphone.code.curr.join("");
  //console.error("CODE: %j %s", piphone.code.curr, code);

  switch (code) {
    case "1178":
      process.emit('shutdown_request');
      break;
    case "1165":
      process.emit('audible_status');
      break;
    case "11":
      piphone.rotary.code = true;
      process.emit('tts', {text:['okay','okay']});
      break;
  }

  piphone.code.unlisten = setTimeout(function() {
    //console.error("UNLISTEN");
    piphone.code.curr = [];
    piphone.rotary.code = false;
    delete piphone.code.unlisten;
  }, 4000);
});

piphone.onoff.on('buttonup', function() {
  piphone.onoff.enabled = true;
});
piphone.onoff.on('longpress', function() {
  if (! piphone.onoff.enabled) { return; }
  process.emit('shutdown_request');
});

process.on('shutdown_request', function() {
  piphone.mods.cp.exec('mpc stop', function(err, stdout, stderr) {
    console.error("STOP: %j", {err:err,stdout:stdout,stderr:stderr});
  });
  process.emit("tts", {text:['goodbye cruel world']});
  setTimeout(function() {
    piphone.mods.cp.exec('shutdown -h now', function(err, stdout, stderr) {
      console.error("SHUTDOWN: %j", {err:err,stdout:stdout,stderr:stderr});
    });
  }, 10000);
});

piphone.dial.on('buttondown', function() {
  piphone.rotary.activate();
});
piphone.dial.on('buttonup', function() {
  piphone.rotary.deactivate();
});

piphone.hook.on('longpress', function() {
  piphone.mods.cp.exec('mpc pause', function(err, stdout, stderr) {
    console.error("STOP: %j", {err:err,stdout:stdout,stderr:stderr});
  });
});

piphone.rotary.on('multipress', function(spec) {
  //console.error("ROTARY: " + spec.count);
  if (piphone.rotary.code) { return; }
  //console.error("ROTARY! " + spec.count);
  switch (spec.count) {
    case 1:
      process.emit("volume", {volume:60});
      process.emit("mpc", {cmd:'play'});
      break;
    case 2:
      process.emit("volume", {volume:100});
      process.emit("mpc", {cmd:'play'});
      break;
    case 3:
      process.emit("volume", {volume:60});
      process.emit("mpc", {cmd:'next'});
      break;
    case 4:
      process.emit("volume", {volume:100});
      process.emit("mpc", {cmd:'next'});
      break;
    case 5:
      process.emit("volume", {volume:60});
      process.emit("mpc", {cmd:'prev'});
      break;
    case 6:
      process.emit("volume", {volume:100});
      process.emit("mpc", {cmd:'prev'});
      break;
    case 7:
      process.emit("volume", {volume:100});
      process.emit("mpcq", {query:['guapo']});
      break;
    case 8:
      process.emit("volume", {volume:100});
      process.emit("mpcq", {query:['belafonte','matilda']});
      break;
    case 9:
      process.emit("volume", {volume:100});
      process.emit("mpcq", {query:['susanna','tanyas']});
      break;
    case 10:
      process.emit("volume", {volume:100});
      process.emit("mpcq", {query:['puff']});
      break;
    case 11:
      process.emit("tts", {text:['how much wood would a wood chuck chuck if a woodchuck would chuck wood?']});
      tts.stdin.end();
      break;
  }
});
piphone.rotary.on('buttonpress', function(spec) {
  piphone.rotary.emit('multipress', spec);
});

process.on('tts', function(spec) {
  var tts = piphone.mods.cp.spawn('/usr/bin/tts', spec.text);
  tts.stdout.pipe(process.stdout);
  tts.stderr.pipe(process.stderr);
  //tts.stdin.write(spec.text.concat(['\n']).join(" "));;
  //tts.stdin.end();
});

process.on('audible_status', function(spec) {
  var stat = piphone.mods.cp.spawn('bash', ['-c', 'mpc | head -1 | tts']);

  stat.stdout.pipe(process.stderr);
  stat.stderr.pipe(process.stderr);
  //tts.stdin.write(spec.text.concat(['\n']).join(" "));;
  //tts.stdin.end();
});

process.on('mpcq', function(spec) {
    //process.emit('tts', {text:spec.query});
    var mpc = piphone.mods.cp.exec(['/usr/bin/mpc_query',spec.query.join(".*")].concat([
      '|',
      'xargs mpc play'
    ]).join(" "), function(err,stdout,stderr) {
    //console.error("DEMAND: %j", {err:err,stdout:stdout,stderr:stderr});
  });
});
process.on('mpc', function(spec) {
  piphone.mods.cp.exec(['mpc',spec.cmd].join(" "), function(err, stdout, stderr) {
    console.error("%s: %j", spec.cmd, {err:err,stdout:stdout,stderr:stderr});
  });
});
process.on('volume', function(spec) {
  piphone.mods.cp.exec(['mpc','volume',spec.volume].join(" "), function(err, stdout, stderr) {
    console.error("VOL: %j", {vol:spec.volume,err:err,stdout:stdout,stderr:stderr});
  });
});
<commit_msg>new codes<commit_after>#!/usr/bin/env node

var piphone = {};

piphone.mods = {};
piphone.mods.gpiobutton = require('gpiobutton');
piphone.mods.cp = require('child_process');

piphone.hook = new piphone.mods.gpiobutton.button({name:'hook', gpiono:22, DOWN:1});
piphone.dial = new piphone.mods.gpiobutton.button({name:'dial', gpiono:27, longTimeout: 3000});
piphone.rotary = new piphone.mods.gpiobutton.button({name:'rotary', gpiono:17, interval:30, DOWN:1});
piphone.onoff = new piphone.mods.gpiobutton.button({name:'switch', gpiono: 18});

piphone.code = {};
piphone.code.curr = [];

piphone.rotary.on('multipress', function(spec) {
  piphone.code.curr.push(spec.count % 10);

  if (piphone.code.unlisten) {
    clearTimeout(piphone.code.unlisten);
  }

  var code = piphone.code.curr.join("");
  console.error("CODE: %j %s", piphone.code.curr, code);

  switch (code) {
    case "1178":
      process.emit('shutdown_request');
      break;
    case "1165":
      process.emit('audible_trackid');
      break;
    case "1166":
      process.emit('mpc', {cmd:['repeat', 'on']});
      process.emit('audible_status');
      break;
    case "1186":
      process.emit('mpc', {cmd:['repeat', 'off']});
      process.emit('audible_status');
      break;
    case "1160":
      process.emit('mpc', {cmd:['single', 'on']});
      process.emit('audible_status');
      break;
    case "1180":
      process.emit('mpc', {cmd:['single', 'off']});
      process.emit('audible_status');
      break;
    case "1161":
      process.emit('mpc', {cmd:['random', 'on']});
      process.emit('audible_status');
      break;
    case "1181":
      process.emit('mpc', {cmd:['random', 'off']});
      process.emit('audible_status');
      break;
    case "11":
      piphone.rotary.code = true;
      process.emit('tts', {text:['okay','okay']});
      break;
  }

  piphone.code.unlisten = setTimeout(function() {
    //console.error("UNLISTEN");
    piphone.code.curr = [];
    piphone.rotary.code = false;
    delete piphone.code.unlisten;
  }, 4000);
});

piphone.onoff.on('buttonup', function() {
  piphone.onoff.enabled = true;
});
piphone.onoff.on('longpress', function() {
  if (! piphone.onoff.enabled) { return; }
  process.emit('shutdown_request');
});

process.on('shutdown_request', function() {
  piphone.mods.cp.exec('mpc stop', function(err, stdout, stderr) {
    console.error("STOP: %j", {err:err,stdout:stdout,stderr:stderr});
  });
  process.emit("tts", {text:['goodbye cruel world']});
  setTimeout(function() {
    piphone.mods.cp.exec('shutdown -h now', function(err, stdout, stderr) {
      console.error("SHUTDOWN: %j", {err:err,stdout:stdout,stderr:stderr});
    });
  }, 10000);
});

piphone.dial.on('buttondown', function() {
  piphone.rotary.activate();
});
piphone.dial.on('buttonup', function() {
  piphone.rotary.deactivate();
});

piphone.dial.on('longpress', function() {
  //process.emit('tts', {text:['okay','okay']});
});

piphone.dial.on('multipress', function() {
  //process.emit('tts', {text:['what', 'what']});
});

piphone.hook.on('multipress', function() {
  //process.emit('tts', {text:['what', 'what']});
});

piphone.hook.on('longpress', function() {
  piphone.mods.cp.exec('mpc pause', function(err, stdout, stderr) {
    console.error("STOP: %j", {err:err,stdout:stdout,stderr:stderr});
  });
});

piphone.rotary.on('multipress', function(spec) {
  //console.error("ROTARY: " + spec.count);
  if (piphone.rotary.code) { return; }
  //console.error("ROTARY! " + spec.count);
  switch (spec.count) {
    case 1:
      process.emit("volume", {volume:60});
      process.emit("mpc", {cmd:'play'});
      break;
    case 2:
      process.emit("volume", {volume:100});
      process.emit("mpc", {cmd:'play'});
      break;
    case 3:
      process.emit("volume", {volume:60});
      process.emit("mpc", {cmd:'next'});
      break;
    case 4:
      process.emit("volume", {volume:100});
      process.emit("mpc", {cmd:'next'});
      break;
    case 5:
      process.emit("volume", {volume:60});
      process.emit("mpc", {cmd:'prev'});
      break;
    case 6:
      process.emit("volume", {volume:100});
      process.emit("mpc", {cmd:'prev'});
      break;
    case 7:
      process.emit("volume", {volume:100});
      process.emit("mpcq", {query:['guapo']});
      break;
    case 8:
      process.emit("volume", {volume:100});
      process.emit("mpcq", {query:['belafonte','matilda']});
      break;
    case 9:
      process.emit("volume", {volume:100});
      process.emit("mpcq", {query:['susanna','tanyas']});
      break;
    case 10:
      process.emit("volume", {volume:100});
      process.emit("mpcq", {query:['puff']});
      break;
    case 11:
      process.emit("tts", {text:['how much wood would a wood chuck chuck if a woodchuck would chuck wood?']});
      tts.stdin.end();
      break;
  }
});
piphone.rotary.on('buttonpress', function(spec) {
  piphone.rotary.emit('multipress', spec);
});

process.on('tts', function(spec) {
  var tts = piphone.mods.cp.spawn('/usr/bin/tts', spec.text);
  tts.stdout.pipe(process.stdout);
  tts.stderr.pipe(process.stderr);
  //tts.stdin.write(spec.text.concat(['\n']).join(" "));;
  //tts.stdin.end();
});

process.on('audible_trackid', function(spec) {
  var stat = piphone.mods.cp.spawn('bash', ['-c', 'mpc current | tts']);

  stat.stdout.pipe(process.stderr);
  stat.stderr.pipe(process.stderr);
  //tts.stdin.write(spec.text.concat(['\n']).join(" "));;
  //tts.stdin.end();
});

process.on('audible_status', function(spec) {
  var stat = piphone.mods.cp.spawn('bash', ['-c', 'mpc | tail -1 | tts']);

  stat.stdout.pipe(process.stderr);
  stat.stderr.pipe(process.stderr);
  //tts.stdin.write(spec.text.concat(['\n']).join(" "));;
  //tts.stdin.end();
});

process.on('mpcq', function(spec) {
    //process.emit('tts', {text:spec.query});
    var mpc = piphone.mods.cp.exec(['/usr/bin/mpc_query',spec.query.join(".*")].concat([
      '|',
      'xargs mpc play'
    ]).join(" "), function(err,stdout,stderr) {
    //console.error("DEMAND: %j", {err:err,stdout:stdout,stderr:stderr});
  });
});
process.on('mpc', function(spec) {
  piphone.mods.cp.exec(['mpc'].concat(spec.cmd).join(" "), function(err, stdout, stderr) {
    console.error("%s: %j", spec.cmd, {err:err,stdout:stdout,stderr:stderr});
  });
});
process.on('volume', function(spec) {
  piphone.mods.cp.exec(['mpc','volume',spec.volume].join(" "), function(err, stdout, stderr) {
    console.error("VOL: %j", {vol:spec.volume,err:err,stdout:stdout,stderr:stderr});
  });
});
<|endoftext|>