<commit_before>/**
 * Copyright 2015 The AMP HTML Authors. 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.
 */

/**
 * The entry point for AMP Runtime (v0.js) when AMP Runtime = AMP Doc.
 */

// src/polyfills.js must be the first import.
import './polyfills';

import {installAutoLightboxExtension} from './auto-lightbox';
import {startupChunk} from './chunk';
import {TickLabel} from './core/constants/enums';
import {installErrorReporting} from './error-reporting';
import {fontStylesheetTimeout} from './font-stylesheet-timeout';
import {maybeTrackImpression} from './impression';
import {internalRuntimeVersion} from './internal-version';
import {getMode} from './mode';
import {preconnectToOrigin} from './preconnect';
import {installPullToRefreshBlocker} from './pull-to-refresh';
import {adoptWithMultidocDeps} from './runtime';
import {Services} from './service';
import {installDocService} from './service/ampdoc-impl';
import {
  installAmpdocServices,
  installBuiltinElements,
  installRuntimeServices,
} from './service/core-services';
import {stubElementsForDoc} from './service/custom-element-registry';
import {installPerformanceService} from './service/performance-impl';
import {installPlatformService} from './service/platform-impl';
import {installStandaloneExtension} from './standalone';
import {
  installStylesForDoc,
  makeBodyVisible,
  makeBodyVisibleRecovery,
} from './style-installer';
import {maybeValidate} from './validator-integration';

import {cssText as ampDocCss} from '../build/ampdoc.css';
import {cssText as ampSharedCss} from '../build/ampshared.css';

/**
 * Execute the bootstrap
 * @param {!./service/ampdoc-impl.AmpDoc} ampdoc
 * @param {!./service/performance-impl.Performance} perf
 */
function bootstrap(ampdoc, perf) {
  startupChunk(self.document, function services() {
    // Core services.
    installRuntimeServices(self);
    installAmpdocServices(ampdoc);
    // We need the core services (viewer/resources) to start instrumenting
    perf.coreServicesAvailable();
    maybeTrackImpression(self);
  });
  startupChunk(self.document, function adoptWindow() {
    adoptWithMultidocDeps(self);
  });
  startupChunk(self.document, function builtins() {
    // Builtins.
    installBuiltinElements(self);
  });
  startupChunk(self.document, function stub() {
    // Pre-stub already known elements.
    stubElementsForDoc(ampdoc);
  });
  startupChunk(
    self.document,
    function final() {
      if (!IS_SXG) {
        installPullToRefreshBlocker(self);
      }
      installAutoLightboxExtension(ampdoc);
      installStandaloneExtension(ampdoc);
      maybeValidate(self);
      makeBodyVisible(self.document);
      preconnectToOrigin(self.document);
    },
    /* makes the body visible */ true
  );
  startupChunk(self.document, function finalTick() {
    perf.tick(TickLabel.END_INSTALL_STYLES);
    Services.resourcesForDoc(ampdoc).ampInitComplete();
    // TODO(erwinm): move invocation of the `flush` method when we have the
    // new ticks in place to batch the ticks properly.
    perf.flush();
  });
}

// Store the originalHash as early as possible. Trying to debug:
// https://github.com/ampproject/amphtml/issues/6070
if (self.location) {
  self.location['originalHash'] = self.location.hash;
}

/** @type {!./service/ampdoc-impl.AmpDocService} */
let ampdocService;
// We must under all circumstances call makeBodyVisible.
// It is much better to have AMP tags not rendered than having
// a completely blank page.
try {
  // Should happen first.
  installErrorReporting(self); // Also calls makeBodyVisibleRecovery on errors.

  // Declare that this runtime will support a single root doc. Should happen
  // as early as possible.
  installDocService(self, /* isSingleDoc */ true);
  ampdocService = Services.ampdocServiceFor(self);
} catch (e) {
  // In case of an error call this.
  makeBodyVisibleRecovery(self.document);
  throw e;
}
startupChunk(self.document, function initial() {
  /** @const {!./service/ampdoc-impl.AmpDoc} */
  const ampdoc = ampdocService.getAmpDoc(self.document);
  installPlatformService(self);
  installPerformanceService(self);
  /** @const {!./service/performance-impl.Performance} */
  const perf = Services.performanceFor(self);
  if (self.document.documentElement.hasAttribute('i-amphtml-no-boilerplate')) {
    perf.addEnabledExperiment('no-boilerplate');
  }
  if (IS_ESM) {
    perf.addEnabledExperiment('esm');
  }
  fontStylesheetTimeout(self);
  perf.tick(TickLabel.INSTALL_STYLES);
  if (IS_ESM) {
    bootstrap(ampdoc, perf);
  } else {
    installStylesForDoc(
      ampdoc,
      ampDocCss + ampSharedCss,
      () => bootstrap(ampdoc, perf),
      /* opt_isRuntimeCss */ true,
      /* opt_ext */ 'amp-runtime'
    );
  }
});

// Output a message to the console and add an attribute to the <html>
// tag to give some information that can be used in error reports.
// (At least by sophisticated users).
if (self.console) {
  (console.info || console.log).call(
    console,
    `Powered by AMP ⚡ HTML – Version ${internalRuntimeVersion()}`,
    self.location.href
  );
}
// This code is eleminated in prod build through a babel transformer.
if (getMode().localDev) {
  self.document.documentElement.setAttribute('esm', IS_ESM ? 1 : 0);
}
self.document.documentElement.setAttribute(
  'amp-version',
  internalRuntimeVersion()
);
<commit_msg>Message announcing IE11 deprecation (#35240)<commit_after>/**
 * Copyright 2015 The AMP HTML Authors. 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.
 */

/**
 * The entry point for AMP Runtime (v0.js) when AMP Runtime = AMP Doc.
 */

// src/polyfills.js must be the first import.
import './polyfills';

import {installAutoLightboxExtension} from './auto-lightbox';
import {startupChunk} from './chunk';
import {TickLabel} from './core/constants/enums';
import {installErrorReporting} from './error-reporting';
import {fontStylesheetTimeout} from './font-stylesheet-timeout';
import {maybeTrackImpression} from './impression';
import {internalRuntimeVersion} from './internal-version';
import {getMode} from './mode';
import {preconnectToOrigin} from './preconnect';
import {installPullToRefreshBlocker} from './pull-to-refresh';
import {adoptWithMultidocDeps} from './runtime';
import {Services} from './service';
import {installDocService} from './service/ampdoc-impl';
import {
  installAmpdocServices,
  installBuiltinElements,
  installRuntimeServices,
} from './service/core-services';
import {stubElementsForDoc} from './service/custom-element-registry';
import {installPerformanceService} from './service/performance-impl';
import {installPlatformService} from './service/platform-impl';
import {installStandaloneExtension} from './standalone';
import {
  installStylesForDoc,
  makeBodyVisible,
  makeBodyVisibleRecovery,
} from './style-installer';
import {maybeValidate} from './validator-integration';

import {cssText as ampDocCss} from '../build/ampdoc.css';
import {cssText as ampSharedCss} from '../build/ampshared.css';

/**
 * Execute the bootstrap
 * @param {!./service/ampdoc-impl.AmpDoc} ampdoc
 * @param {!./service/performance-impl.Performance} perf
 */
function bootstrap(ampdoc, perf) {
  startupChunk(self.document, function services() {
    // Core services.
    installRuntimeServices(self);
    installAmpdocServices(ampdoc);
    // We need the core services (viewer/resources) to start instrumenting
    perf.coreServicesAvailable();
    maybeTrackImpression(self);
  });
  startupChunk(self.document, function adoptWindow() {
    adoptWithMultidocDeps(self);
  });
  startupChunk(self.document, function builtins() {
    // Builtins.
    installBuiltinElements(self);
  });
  startupChunk(self.document, function stub() {
    // Pre-stub already known elements.
    stubElementsForDoc(ampdoc);
  });
  startupChunk(
    self.document,
    function final() {
      if (!IS_SXG) {
        installPullToRefreshBlocker(self);
      }
      installAutoLightboxExtension(ampdoc);
      installStandaloneExtension(ampdoc);
      maybeValidate(self);
      makeBodyVisible(self.document);
      preconnectToOrigin(self.document);
    },
    /* makes the body visible */ true
  );
  startupChunk(self.document, function finalTick() {
    perf.tick(TickLabel.END_INSTALL_STYLES);
    Services.resourcesForDoc(ampdoc).ampInitComplete();
    // TODO(erwinm): move invocation of the `flush` method when we have the
    // new ticks in place to batch the ticks properly.
    perf.flush();
  });
}

// Store the originalHash as early as possible. Trying to debug:
// https://github.com/ampproject/amphtml/issues/6070
if (self.location) {
  self.location['originalHash'] = self.location.hash;
}

/** @type {!./service/ampdoc-impl.AmpDocService} */
let ampdocService;
// We must under all circumstances call makeBodyVisible.
// It is much better to have AMP tags not rendered than having
// a completely blank page.
try {
  // Should happen first.
  installErrorReporting(self); // Also calls makeBodyVisibleRecovery on errors.

  // Declare that this runtime will support a single root doc. Should happen
  // as early as possible.
  installDocService(self, /* isSingleDoc */ true);
  ampdocService = Services.ampdocServiceFor(self);
} catch (e) {
  // In case of an error call this.
  makeBodyVisibleRecovery(self.document);
  throw e;
}
startupChunk(self.document, function initial() {
  /** @const {!./service/ampdoc-impl.AmpDoc} */
  const ampdoc = ampdocService.getAmpDoc(self.document);
  installPlatformService(self);
  installPerformanceService(self);
  /** @const {!./service/performance-impl.Performance} */
  const perf = Services.performanceFor(self);
  if (self.document.documentElement.hasAttribute('i-amphtml-no-boilerplate')) {
    perf.addEnabledExperiment('no-boilerplate');
  }
  if (IS_ESM) {
    perf.addEnabledExperiment('esm');
  }
  fontStylesheetTimeout(self);
  perf.tick(TickLabel.INSTALL_STYLES);
  if (IS_ESM) {
    bootstrap(ampdoc, perf);
  } else {
    installStylesForDoc(
      ampdoc,
      ampDocCss + ampSharedCss,
      () => bootstrap(ampdoc, perf),
      /* opt_isRuntimeCss */ true,
      /* opt_ext */ 'amp-runtime'
    );
    // TODO(kbax) Remove this IE deprecation warning on 26 August 2021.
    if (Services.platformFor(self).isIe() && self.console) {
      (console.info || console.log).call(
        console,
        'IE Support is being deprecated, in September 2021 IE will no longer be supported. See https://github.com/ampproject/amphtml/issues/34453 for more details.'
      );
    }
  }
});

// Output a message to the console and add an attribute to the <html>
// tag to give some information that can be used in error reports.
// (At least by sophisticated users).
if (self.console) {
  (console.info || console.log).call(
    console,
    `Powered by AMP ⚡ HTML – Version ${internalRuntimeVersion()}`,
    self.location.href
  );
}
// This code is eleminated in prod build through a babel transformer.
if (getMode().localDev) {
  self.document.documentElement.setAttribute('esm', IS_ESM ? 1 : 0);
}
self.document.documentElement.setAttribute(
  'amp-version',
  internalRuntimeVersion()
);
<|endoftext|>


<commit_before>function Ant(a_board) {
    this.row(5);
    this.column(5);
    this.direction('up');
    this.board(a_board);
}

accessor(Ant, "row");
accessor(Ant, "column");
accessor(Ant, "direction");
accessor(Ant, "board");

Ant.prototype.color= function(new_value) {
    return this.board().cell_color(this.row(), this.column(), new_value);
};

Ant.prototype.flip_color= function() {
    if (this.color() === 'white')
	this.color('black');
    else
	this.color('white');
};

Ant.prototype.turn_left= function() {
    switch(this.direction()) {
    case 'up':
	this.direction('left');
	break;
    case 'left':
	this.direction('down');
	break;
    case 'down':
	this.direction('right');
	break;
    case 'right':
	this.direction('up');
	break;
    }
};

Ant.prototype.turn_right= function() {
    switch(this.direction()) {
    case 'up':
	this.direction('right');
	break;
    case 'left':
	this.direction('up');
	break;
    case 'down':
	this.direction('left');
	break;
    case 'right':
	this.direction('down');
	break;
    }
};

Ant.prototype.move_forward= function() {
    switch(this.direction()) {
    case 'up':
	this.row(this.row() - 1);
	break;
    case 'left':
	this.column(this.column() - 1);
	break;
    case 'down':
	this.row(this.row() + 1);
	break;
    case 'right':
	this.column(this.column() + 1);
	break;
    }
};

Ant.prototype.turn= function() {
    if (this.color() === 'white')
	this.turn_left();
    else
	this.turn_right();
}

Ant.prototype.step= function() {
    this.flip_color();
    this.turn();
    this.move_forward();
};
<commit_msg>Refactoring: replaced switches on ant direction with table lookups<commit_after>function Ant(a_board) {
    this.row(5);
    this.column(5);
    this.direction('up');
    this.board(a_board);
}

accessor(Ant, "row");
accessor(Ant, "column");
accessor(Ant, "direction");
accessor(Ant, "board");

Ant.prototype.directions=
    {
	up:    {turn_left: 'left',  turn_right: 'right', row_increment: -1, column_increment: 0},
	left:  {turn_left: 'down',  turn_right: 'up',    row_increment:  0, column_increment: -1},
	down:  {turn_left: 'right', turn_right: 'left',  row_increment:  1, column_increment: 0},
	right: {turn_left: 'up',    turn_right: 'down',  row_increment:  0, column_increment: 1}
    };

Ant.prototype.color= function(new_value) {
    return this.board().cell_color(this.row(), this.column(), new_value);
};

Ant.prototype.flip_color= function() {
    if (this.color() === 'white')
	this.color('black');
    else
	this.color('white');
};

Ant.prototype.turn_left= function() {
    this.direction(this.directions[this.direction()].turn_left);
};

Ant.prototype.turn_right= function() {
    this.direction(this.directions[this.direction()].turn_right);
};

Ant.prototype.move_forward= function() {
    this.row(this.row() + this.directions[this.direction()].row_increment);
    this.column(this.column() + this.directions[this.direction()].column_increment);
};

Ant.prototype.turn= function() {
    if (this.color() === 'white')
	this.turn_left();
    else
	this.turn_right();
}

Ant.prototype.step= function() {
    this.flip_color();
    this.turn();
    this.move_forward();
};
<|endoftext|>


<commit_before>import createRouter from 'router';
import debug from 'debug';
import fs from 'fs';

// routes
import authenticate from './routes/authenticate';
import playlist from './routes/playlists';
import waitlist from './routes/waitlist';
import search from './routes/search';
import booth from './routes/booth';
import users from './routes/users';
import staff from './routes/staff';
import chat from './routes/chat';
import now from './routes/now';

// middleware
import authenticator from './middleware/authenticator';
import WSServer from './sockets';

const log = debug('uwave:api:v1');

/**
 * creates a router for version 1 of the api
 *
 * @param {Object} options - router config, for more information see {@link http://expressjs.com/4x/api.html#router}
 **/
export default class V1 {
  constructor(config = {}) {
    this.router = createRouter(config.router);
    this.cert = '';
    this.wsserver = null;

    this.setCert(config.cert);

    this.router.use(authenticator(this));

    authenticate(this, this.router);
    playlist(this.router);
    waitlist(this.router);
    search(this.router);
    booth(this.router);
    users(this.router);
    staff(this.router);
    chat(this.router);
    now(this.router);
  }

  getRouter() {
    return this.router;
  }

  setCert(filepath) {
    fs.readFile(filepath, 'UTF8', (err, content) => {
      if (err) return log(`couldn't load cert. Error: ${err}`);
      this.cert = content;
    });
  }

  getCert() {
    return this.cert;
  }

  registerWSServer(uwave) {
    if (!this.wsserver) {
      this.wsserver = new WSServer(this, uwave, uwave.getConfig());
    } else {
      this.log('wsserver is already registered');
    }
  }

  destroy() {
    this.wsserver.destroy();
    this.wsserver = null;
    this.router = null;
  }
}
<commit_msg>api: create socket server immediately, remove "registerWSServer"<commit_after>import createRouter from 'router';
import debug from 'debug';
import fs from 'fs';

// routes
import authenticate from './routes/authenticate';
import playlist from './routes/playlists';
import waitlist from './routes/waitlist';
import search from './routes/search';
import booth from './routes/booth';
import users from './routes/users';
import staff from './routes/staff';
import chat from './routes/chat';
import now from './routes/now';

// middleware
import authenticator from './middleware/authenticator';
import WSServer from './sockets';

const log = debug('uwave:api:v1');

/**
 * creates a router for version 1 of the api
 *
 * @param {Object} options - router config, for more information see {@link http://expressjs.com/4x/api.html#router}
 **/
export default class V1 {
  constructor(uw, config = {}) {
    if (!uw || !('mongo' in uw)) {
      throw new Error(`
        Expected a u-wave-core instance in the first parameter. If you are
        developing, you may have to upgrade your u-wave-* modules.
      `.replace(/\s+/g, ' ').trim());
    }

    this.uw = uw;
    this.router = createRouter(config.router);
    this.cert = '';
    this.sockets = new WSServer(this, uw, config);

    this.setCert(config.cert);

    this.router.use(authenticator(this));

    authenticate(this, this.router);
    playlist(this.router);
    waitlist(this.router);
    search(this.router);
    booth(this.router);
    users(this.router);
    staff(this.router);
    chat(this.router);
    now(this.router);
  }

  getRouter() {
    return this.router;
  }

  setCert(filepath) {
    fs.readFile(filepath, 'UTF8', (err, content) => {
      if (err) return log(`couldn't load cert. Error: ${err}`);
      this.cert = content;
    });
  }

  getCert() {
    return this.cert;
  }

  destroy() {
    this.sockets.destroy();
    this.sockets = null;
    this.router = null;
  }
}
<|endoftext|>


<commit_before>$(document).ready(function(){
    app.c.init();
});

///////////////////////////////////////////////////////
///////////////////////////////////////////////////////

var app={};
app.m={};
app.v={};
app.c={};
app.t={};

///////////////////////////////////////////////////////
///////////////////////////////////////////////////////

app.m.bounds=false;
app.m.paper=false;
app.m.appName="LongNow Chalk";

///////////////////////////////////////////////////////
///////////////////////////////////////////////////////begin controllers

app.c.init=function(){
  app.v.init();
  app.v.listeners();
};

///////////////////////////////////////////////////////end controllers
///////////////////////////////////////////////////////begin views

app.v.init=function(){
    //app.m.bounds=app.v.initBounds();
    zi.css();
    $("body").html(app.t.layout() );
    app.m.paper=app.v.initPaper();
    app.v.initialReveal();
};

app.v.initBounds=function(){
	var w = window,
    d = document,
    e = d.documentElement,
    g = d.getElementsByTagName('body')[0],
    x = w.innerWidth || e.clientWidth || g.clientWidth,
    y = w.innerHeight|| e.clientHeight|| g.clientHeight;
  var b={};
  b.right=x-20;
  b.left=0;
  b.top=0;
  b.bottom=y;
  b.centerX=b.right/2;
  b.centerY=b.bottom/2;
  b.width=b.right-b.left;
  b.height=b.bottom-b.top;

  return b;
};

app.v.initialReveal=function(){
};

app.v.initPaper=function(){
  var canvas = document.getElementById('paper');
  var d=new Date();
  var chnc = new Chance(d.toDateString() );
	// Create an empty project and a view for the canvas:
	paper.setup(canvas);

	// Now I'll create a circle function that takes an x, y, and r
	var circle=function(x,y,r){
		var path = new paper.Path.Circle({
    	//center: paper.view.center,
    	center:[x,y],
    	radius: r,
    	strokeColor:"#fff",
    	strokeWidth:2
    });

	};

  var orbits=24;
  var r=0;
  var planets=60;
  var theta_interval=360/planets;
  for (var i=0;i<orbits;i++){
    r+=20;
    var planetRadius=chnc.integer({min:2,max:30});
    for (var j=0;j<planets;j++){
      var theta=j*theta_interval;
      var position=geo.getPoint(paper.view.bounds.centerX,paper.view.bounds.centerY,r,theta)
      circle(position.x2,position.y2,planetRadius);
    }
  }

	// Draw the view now:
	paper.view.draw();
};

app.v.listeners=function(){

};

///////////////////////////////////////////////////////end views
///////////////////////////////////////////////////////begin templates

app.t.layout=function(){
  var d="";
  d+="<canvas id='paper' data-paper-resize='true'></canvas>";
  return d;
};

///////////////////////////////////////////////////////end templates
///////////////////////////////////////////////////////begin css

zi={};
zi.config=function(){
    var css={
      "body":{
        "padding":"0",
        "margin":"0",
        "border":"0",
        "background":"#555"
      },
      "canvas":{
        "margin":"0",
        "padding":"0",
        "border":"0",
        "position":"fixed"
      }
    };
    return css;
};
zi.transform=function(css){
    var c="";
    for (var selector in css){
        c+=selector+"{";
        for (var property in css[selector]){
            c+=property+" : "+css[selector][property]+";";
        }
        c+="}";
    }
    return c;
};
zi.css=function(){
    if ($("head#zi").length<1){
        $("head").append("");
    }
    $("head style#zi").html( this.transform( this.config() ) );
};
/////////////////////////////////////////////////////// end css section
///////////////////////////////////////////////////////<commit_msg>added a petal shape and a diamond (not sure I like the diamond)<commit_after>$(document).ready(function(){
    app.c.init();
});

///////////////////////////////////////////////////////
///////////////////////////////////////////////////////

var app={};
app.m={};
app.v={};
app.c={};
app.t={};

///////////////////////////////////////////////////////
///////////////////////////////////////////////////////

app.m.bounds=false;
app.m.paper=false;
app.m.appName="LongNow Chalk";

///////////////////////////////////////////////////////
///////////////////////////////////////////////////////begin controllers

app.c.init=function(){
  app.v.init();
  app.v.listeners();
};

///////////////////////////////////////////////////////end controllers
///////////////////////////////////////////////////////begin views

app.v.init=function(){
    //app.m.bounds=app.v.initBounds();
    zi.css();
    $("body").html(app.t.layout() );
    app.m.paper=app.v.initPaper();
    app.v.initialReveal();
};

app.v.initBounds=function(){
	var w = window,
    d = document,
    e = d.documentElement,
    g = d.getElementsByTagName('body')[0],
    x = w.innerWidth || e.clientWidth || g.clientWidth,
    y = w.innerHeight|| e.clientHeight|| g.clientHeight;
  var b={};
  b.right=x-20;
  b.left=0;
  b.top=0;
  b.bottom=y;
  b.centerX=b.right/2;
  b.centerY=b.bottom/2;
  b.width=b.right-b.left;
  b.height=b.bottom-b.top;

  return b;
};

app.v.initialReveal=function(){
};

app.v.initPaper=function(){
  var canvas = document.getElementById('paper');
  var d=new Date();
  var chnc = new Chance(d.toDateString() );
  //var chnc = new Chance();
	// Create an empty project and a view for the canvas:
	paper.setup(canvas);

	// Now I'll create a circle function that takes an x, y, and r
	var circle=function(x,y,r){
		var path = new paper.Path.Circle({
    	//center: paper.view.center,
    	center:[x,y],
    	radius: r,
    	strokeColor:"#fff",
    	strokeWidth:2
    });

	};

	var diamond=function(x,y,l,w1,w2){
    var p=new paper.Path;
    p.strokeColor="#fff";
    p.add([x,y]);
    p.add([x+(l/2),y-(l/2)]);
    p.add([x+l,y]);
    p.add([x+(l/2),y+(l/2)]);
    p.add([x,y]);
    return p;
	};

	var petal=function(x,y,l,w1,w2){
    var p=new paper.Path;
    var w1=w1||2;
    p.add([x+l,y]);
    p.add(new paper.Segment(
      new paper.Point([x,y]),
      new paper.Point([0,-l/w1]),
      new paper.Point([0,l/w1])
      )
    );
    p.add([x+l,y]);
    p.strokeColor="#fff";
    return p;
	};

  var orbits=24;
  var r=0;
  var planets=60;
  var theta_interval=360/planets;
  for (var i=0;i<orbits;i++){
    r+=20;
    var planetRadius=chnc.integer({min:2,max:30});
    var w1=chnc.integer({min:1,max:3});
    var ringType=chnc.pick(["petal","petal","circle","diamond"]);
    for (var j=0;j<planets;j++){
      var theta=j*theta_interval;
      var position=geo.getPoint(paper.view.bounds.centerX,paper.view.bounds.centerY,r,theta);
      if (ringType=="circle"){
        circle(position.x2,position.y2,planetRadius);
      }else if (ringType=="diamond"){
        diamond(
          paper.view.bounds.centerX+r,
          paper.view.bounds.centerY,
          planetRadius,
          w1
          ).rotate(theta,paper.view.center);

      }else{
        petal(
          paper.view.bounds.centerX+r,
          paper.view.bounds.centerY,
          planetRadius,
          w1
          ).rotate(theta,paper.view.center);
      }
    }
  }

	// Draw the view now:
	paper.view.draw();
};

app.v.listeners=function(){

};

///////////////////////////////////////////////////////end views
///////////////////////////////////////////////////////begin templates

app.t.layout=function(){
  var d="";
  //d+="
Yesterday's Mandalla Clock
";
  //d+="
Tomorrow's Mandalla Clock
";
  d+="<canvas id='paper' data-paper-resize='true'></canvas>";
  return d;
};

///////////////////////////////////////////////////////end templates
///////////////////////////////////////////////////////begin css

zi={};
zi.config=function(){
    var css={
      "body":{
        "padding":"0",
        "margin":"0",
        "border":"0",
        "background":"#555"
      },
      "canvas":{
        "margin":"0",
        "padding":"0",
        "border":"0",
        "position":"fixed"
      },
      "canvas#paper":{
        "z-index":"-1"
      },
    };
    return css;
};
zi.transform=function(css){
    var c="";
    for (var selector in css){
        c+=selector+"{";
        for (var property in css[selector]){
            c+=property+" : "+css[selector][property]+";";
        }
        c+="}";
    }
    return c;
};
zi.css=function(){
    if ($("head#zi").length<1){
        $("head").append("");
    }
    $("head style#zi").html( this.transform( this.config() ) );
};
/////////////////////////////////////////////////////// end css section
///////////////////////////////////////////////////////<|endoftext|>


<commit_before>//
// Styles
//
require('bootstrap-sass/assets/stylesheets/_bootstrap.scss');
require('./styles/main.scss');

//
// Scripts
//
window._ = require('lodash');
window.$ = window.jQuery = require('jquery');

require('bootstrap-sass');

require('./scripts/onload');

window.models = require('./models/index');
<commit_msg>refer to 'font-awesome'<commit_after>//
// Styles
//
require('bootstrap-sass/assets/stylesheets/_bootstrap.scss');
require('font-awesome/scss/font-awesome.scss')
require('./styles/main.scss');

//
// Scripts
//
window._ = require('lodash');
window.$ = window.jQuery = require('jquery');

require('bootstrap-sass');

require('./scripts/onload');

window.models = require('./models/index');
<|endoftext|>


<commit_before>/* Magic Mirror
 * Node Helper Superclass
 *
 * By Michael Teeuw http://michaelteeuw.nl
 * MIT Licensed.
 */

var Class = require("../../../js/class.js");
var express = require("express");
var path = require("path");

NodeHelper = Class.extend({
	init: function() {
		console.log("Initializing new module helper ...");
	},

	loaded: function(callback) {
		console.log("Module helper loaded: " + this.name);
		callback();
	},

	start: function() {
		console.log("Starting module helper: " + this.name);
	},

	/* socketNotificationReceived(notification, payload)
	 * This method is called when a socket notification arrives.
	 *
	 * argument notification string - The identifier of the notification.
	 * argument payload mixed - The payload of the notification.
	 */
	socketNotificationReceived: function(notification, payload) {
		console.log(this.name + " received a socket notification: " + notification + " - Payload: " + payload);
	},

	/* setName(name)
	 * Set the module name.
	 *
	 * argument name string - Module name.
	 */
	setName: function(name) {
		this.name = name;
	},

	/* setPath(path)
	 * Set the module path.
	 *
	 * argument path string - Module path.
	 */
	setPath: function(path) {
		this.path = path;
	},

	/* sendSocketNotification(notification, payload)
	 * Send a socket notification to the node helper.
	 *
	 * argument notification string - The identifier of the notification.
	 * argument payload mixed - The payload of the notification.
	 */
	sendSocketNotification: function(notification, payload) {
		this.io.of(this.name).emit(notification, payload);
	},

	/* setExpressApp(app)
	 * Sets the express app object for this module.
	 * This allows you to host files from the created webserver.
	 *
	 * argument app Express app - The Express app object.
	 */
	setExpressApp: function(app) {
		this.expressApp = app;

		var publicPath = this.path + "/public";
		app.use("/" + this.name, express.static(publicPath));
	},

	/* setSocketIO(io)
	 * Sets the socket io object for this module.
	 * Binds message receiver.
	 *
	 * argument io Socket.io - The Socket io object.
	 */
	setSocketIO: function(io) {
		var self = this;
		self.io = io;

		console.log("Connecting socket for: " + this.name);
		var namespace = this.name;
		io.of(namespace).on("connection", function(socket) {
			// add a catch all event.
			var onevent = socket.onevent;
			socket.onevent = function(packet) {
				var args = packet.data || [];
				onevent.call(this, packet);    // original call
				packet.data = ["*"].concat(args);
				onevent.call(this, packet);      // additional call to catch-all
			};

			// register catch all.
			socket.on("*", function(notification, payload) {
				if (notification !== "*") {
					//console.log('received message in namespace: ' + namespace);
					self.socketNotificationReceived(notification, payload);
				}
			});
		});

	}
});

NodeHelper.create = function(moduleDefinition) {
	return NodeHelper.extend(moduleDefinition);
};

module.exports = NodeHelper;
<commit_msg>Added default implementation of stop() function.<commit_after>/* Magic Mirror
 * Node Helper Superclass
 *
 * By Michael Teeuw http://michaelteeuw.nl
 * MIT Licensed.
 */

var Class = require("../../../js/class.js");
var express = require("express");
var path = require("path");

NodeHelper = Class.extend({
	init: function() {
		console.log("Initializing new module helper ...");
	},

	loaded: function(callback) {
		console.log("Module helper loaded: " + this.name);
		callback();
	},

	start: function() {
		console.log("Starting module helper: " + this.name);
	},

	/* stop()
	 * Called when the MagicMirror server receives a `SIGINT`
	 * Close any open connections, stop any sub-processes and
	 * gracefully exit the module.
	 *
	 */
	stop: function() {
		console.log("Stopping module helper: " + this.name);
	},

	/* socketNotificationReceived(notification, payload)
	 * This method is called when a socket notification arrives.
	 *
	 * argument notification string - The identifier of the notification.
	 * argument payload mixed - The payload of the notification.
	 */
	socketNotificationReceived: function(notification, payload) {
		console.log(this.name + " received a socket notification: " + notification + " - Payload: " + payload);
	},

	/* setName(name)
	 * Set the module name.
	 *
	 * argument name string - Module name.
	 */
	setName: function(name) {
		this.name = name;
	},

	/* setPath(path)
	 * Set the module path.
	 *
	 * argument path string - Module path.
	 */
	setPath: function(path) {
		this.path = path;
	},

	/* sendSocketNotification(notification, payload)
	 * Send a socket notification to the node helper.
	 *
	 * argument notification string - The identifier of the notification.
	 * argument payload mixed - The payload of the notification.
	 */
	sendSocketNotification: function(notification, payload) {
		this.io.of(this.name).emit(notification, payload);
	},

	/* setExpressApp(app)
	 * Sets the express app object for this module.
	 * This allows you to host files from the created webserver.
	 *
	 * argument app Express app - The Express app object.
	 */
	setExpressApp: function(app) {
		this.expressApp = app;

		var publicPath = this.path + "/public";
		app.use("/" + this.name, express.static(publicPath));
	},

	/* setSocketIO(io)
	 * Sets the socket io object for this module.
	 * Binds message receiver.
	 *
	 * argument io Socket.io - The Socket io object.
	 */
	setSocketIO: function(io) {
		var self = this;
		self.io = io;

		console.log("Connecting socket for: " + this.name);
		var namespace = this.name;
		io.of(namespace).on("connection", function(socket) {
			// add a catch all event.
			var onevent = socket.onevent;
			socket.onevent = function(packet) {
				var args = packet.data || [];
				onevent.call(this, packet);    // original call
				packet.data = ["*"].concat(args);
				onevent.call(this, packet);      // additional call to catch-all
			};

			// register catch all.
			socket.on("*", function(notification, payload) {
				if (notification !== "*") {
					//console.log('received message in namespace: ' + namespace);
					self.socketNotificationReceived(notification, payload);
				}
			});
		});

	}
});

NodeHelper.create = function(moduleDefinition) {
	return NodeHelper.extend(moduleDefinition);
};

module.exports = NodeHelper;
<|endoftext|>


<commit_before>// Use new ES6 modules syntax for everything.
import { remote } from 'electron'; // native electron module
import jetpack from 'fs-jetpack'; // module loaded from npm
import './polyfills';
import fh from './helpers/fileHelpers.js';
import env from './env';
import xelib from './xelib.js';
import settingsService from './Services/settingsService.js';
import xelibService from './Services/xelibService.js';
import profileService from './Services/profileService.js';
import formUtils from './Services/formUtils.js';
import layoutService from './Services/layoutService.js';
import styleSheetService from './Services/stylesheetService.js';
import columnsService from './Services/columnsService.js';
import viewFactory from './Factories/viewFactory.js';
import mainTreeViewFactory from './Factories/mainTreeViewFactory.js';
import recordTreeViewFactory from './Factories/recordTreeViewFactory.js';
import spinnerFactory from './Factories/spinnerFactory.js';
import listViewFactory from './Factories/listViewFactory.js';
import profilesModal from './Directives/profilesModal.js';
import loadOrderModal from './Directives/loadOrderModal.js';
import pane from './Directives/pane.js';
import splitBar from './Directives/splitBar.js';
import settingsModal from './Directives/settingsModal.js';
import hexFilter from './Filters/hexFilter.js';
import profileValidFilter from './Filters/profileValidFilter.js';
import baseView from './Views/base.js';
import startView from './Views/start.js';
import mainView from './Views/main.js';

// set up helpers
var fileHelpers = fh(remote, jetpack);

// initialize xelib when application starts
xelib.Initialize();

// set up angular application
var ngapp = angular.module('application', [
    'ui.router', 'ct.ui.router.extras', 'angularSpinner', 'vs-repeat'
]);

//this allows urls with and without trailing slashes to go to the same state
ngapp.config(function ($urlMatcherFactoryProvider) {
    $urlMatcherFactoryProvider.strictMode(false);
});

// state redirects
ngapp.run(['$rootScope', '$state', function ($rootScope, $state) {
    $rootScope.$on('$stateChangeStart', function (evt, toState, params, fromState) {
        if (toState.redirectTo) {
            evt.preventDefault();
            $state.go(toState.redirectTo, params, {location: 'replace'});
        }
    });
}]);

// SERVICES
xelibService(ngapp, xelib);
profileService(ngapp, xelib, fileHelpers);
formUtils(ngapp);
settingsService(ngapp, fileHelpers);
layoutService(ngapp, fileHelpers);
styleSheetService(ngapp);
columnsService(ngapp, fileHelpers, xelib);

// FACTORIES
viewFactory(ngapp);
mainTreeViewFactory(ngapp, xelib);
recordTreeViewFactory(ngapp, xelib);
spinnerFactory(ngapp);
listViewFactory(ngapp);

// FILTERS
hexFilter(ngapp);
profileValidFilter(ngapp);

// DIRECTIVES
profilesModal(ngapp, fileHelpers);
loadOrderModal(ngapp, xelib);
settingsModal(ngapp, fileHelpers);
pane(ngapp);
splitBar(ngapp);

// VIEWS
baseView(ngapp, remote);
startView(ngapp, xelib, fileHelpers);
mainView(ngapp, xelib, remote);<commit_msg>added editColumnsModal to angular app<commit_after>// Use new ES6 modules syntax for everything.
import { remote } from 'electron'; // native electron module
import jetpack from 'fs-jetpack'; // module loaded from npm
import './polyfills';
import fh from './helpers/fileHelpers.js';
import env from './env';
import xelib from './xelib.js';
import settingsService from './Services/settingsService.js';
import xelibService from './Services/xelibService.js';
import profileService from './Services/profileService.js';
import formUtils from './Services/formUtils.js';
import layoutService from './Services/layoutService.js';
import styleSheetService from './Services/stylesheetService.js';
import columnsService from './Services/columnsService.js';
import viewFactory from './Factories/viewFactory.js';
import mainTreeViewFactory from './Factories/mainTreeViewFactory.js';
import recordTreeViewFactory from './Factories/recordTreeViewFactory.js';
import spinnerFactory from './Factories/spinnerFactory.js';
import listViewFactory from './Factories/listViewFactory.js';
import profilesModal from './Directives/profilesModal.js';
import loadOrderModal from './Directives/loadOrderModal.js';
import pane from './Directives/pane.js';
import splitBar from './Directives/splitBar.js';
import settingsModal from './Directives/settingsModal.js';
import editColumnsModal from './Directives/editColumnsModal.js';
import hexFilter from './Filters/hexFilter.js';
import profileValidFilter from './Filters/profileValidFilter.js';
import baseView from './Views/base.js';
import startView from './Views/start.js';
import mainView from './Views/main.js';

// set up helpers
var fileHelpers = fh(remote, jetpack);

// initialize xelib when application starts
xelib.Initialize();

// set up angular application
var ngapp = angular.module('application', [
    'ui.router', 'ct.ui.router.extras', 'angularSpinner', 'vs-repeat'
]);

//this allows urls with and without trailing slashes to go to the same state
ngapp.config(function ($urlMatcherFactoryProvider) {
    $urlMatcherFactoryProvider.strictMode(false);
});

// state redirects
ngapp.run(['$rootScope', '$state', function ($rootScope, $state) {
    $rootScope.$on('$stateChangeStart', function (evt, toState, params, fromState) {
        if (toState.redirectTo) {
            evt.preventDefault();
            $state.go(toState.redirectTo, params, {location: 'replace'});
        }
    });
}]);

// SERVICES
xelibService(ngapp, xelib);
profileService(ngapp, xelib, fileHelpers);
formUtils(ngapp);
settingsService(ngapp, fileHelpers);
layoutService(ngapp, fileHelpers);
styleSheetService(ngapp);
columnsService(ngapp, fileHelpers, xelib);

// FACTORIES
viewFactory(ngapp);
mainTreeViewFactory(ngapp, xelib);
recordTreeViewFactory(ngapp, xelib);
spinnerFactory(ngapp);
listViewFactory(ngapp);

// FILTERS
hexFilter(ngapp);
profileValidFilter(ngapp);

// DIRECTIVES
profilesModal(ngapp, fileHelpers);
loadOrderModal(ngapp, xelib);
settingsModal(ngapp, fileHelpers);
pane(ngapp);
splitBar(ngapp);
editColumnsModal(ngapp, xelib);

// VIEWS
baseView(ngapp, remote);
startView(ngapp, xelib, fileHelpers);
mainView(ngapp, xelib, remote);<|endoftext|>


<commit_before>import request from 'request'

const apiUrl = 'https://graph.facebook.com/v2.6/'

/** Class representing a Facebook Messenger App. */
class Messenger {
  /**
   * Create a Messenger.
   *
   * @param {string} [token=null] - The Facebook Page Access Token.
   * @param {string} [notificationType=REGULAR] - The default message notification type.
   */
  constructor (token = null, notificationType = 'REGULAR') {
    this.token = token
    this.notificationType = notificationType

    if (!this.token) throw new Error('Facebook Page access token is missing.')
  }

  /**
  * This method will subscribe App via API
  *
  * @callback [cb] - The callback function
  */
  subscribeApp (cb) {
    const req = {
      url: `${apiUrl}me/subscribed_apps`,
      qs: {
        access_token: this.token
      },
      method: 'POST',
      json: true
    }
    sendRequest(req, cb)
  }

  /**
  * This method will send a plain Text Message.
  *
  * @param {string} recipient - The user id that will receive the message
  * @param {string} text - The text message (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendTextMessage (recipient, text, notificationType, cb) {
    const message = { text: message }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a Quick Replies Message.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object[]} quickReplies - The quick replies to be sent with messages
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendQuickMessage (recipient, quickReplies, notificationType, cb) {
    const message = { quick_replies: quickReplies }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Attachment Message.
  *
  * @param {string} recipient - The user id that will receive the message
  * @param {string} type - The attachment type
  * @param {object} payload - The attachment payload
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendAttachmentMessage (recipient, type, payload, notificationType, cb) {
    const message = {
      attachment: {
        type: type, // image, audio, video, file, location, template
        payload: payload
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a file attachment. The file type must be image, audio, video or file).
  * Image supported formats [jpg, png and gifs]
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} type - The file type ['image', 'audio', 'video' or 'file']
  * @param {string} fileUrl - The file url where it is hosted (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendFileMessage (recipient, type, fileUrl, notificationType, cb) {
    const payload = { url: fileUrl }
    this.sendAttachmentMessage(recipient, type, payload, notificationType, cb)
  }

  /**
  * This method will send a text and buttons attachment to request input from the user.
  * The buttons can open a URL, or make a back-end call to your webhook.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} text - The head text of the button message
  * @param {object[]} buttons - The Set of call-to-action buttons
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendButtonMessage (recipient, text, buttons, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: {
          template_type: 'button',
          text: text,
          buttons: buttons
        }
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a Structured Generic Message, to send a horizontal scrollable carousel of items,
  * each composed of an image attachment, short description and buttons to request input from the user.
  * The buttons can open a URL, or make a back-end call to your webhook.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object[]} elements - The Data for each bubble in message
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendGenericMessage (recipient, elements, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: {
          template_type: 'generic',
          elements: elements
        }
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a Receipt Message, to send a order confirmation,
  * with the transaction summary and description for each item.
  *
  * @param {string} recipient - The receipient user id.
  * @param {object} receipt - The Receipt Template
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendReceiptMessage (recipient, receipt, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: receipt
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Airplane Itinerary Message, that contains the itinerary and receipt.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} itinerary - The payload of itinerary template (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendItineraryMessage (recipient, itinerary, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: itinerary
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Airplane Check-In Reminder Message.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} checkin - The payload of checkin template (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendCheckinMessage (recipient, checkin, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: checkin
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Airplane Boarding Pass Message, that contains boarding
  * passes for one or more flights or one more passengers
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} boardingpass - The payload of boarding pass template (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendBoardingpassMessage (recipient, boardingpass, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: boardingpass
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Airplane Flight Update Message.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} flightupdate - The payload of flight update template (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendFlightupdateMessage (recipient, flightupdate, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: flightupdate
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a message to the user.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} message - The message object (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendApiMessage (recipient, message, notificationType, cb) {
    if (typeof notificationType === 'function') {
      cb = notificationType
      notificationType = this.notificationType
    }
    const req = {
      url: `${apiUrl}me/messages`,
      qs: {
        access_token: this.token
      },
      method: 'POST',
      json: {
        recipient: {
          id: recipient
        },
        message: message,
        notification_type: notificationType
      }
    }
    sendRequest(req, cb)
  }

  /**
  * This method will send Sender Actions, this are typing indicators or send read receipts,
  * to let the user know you are processing their request
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} senderAction - The action typing indicator (required)
  * @callback [cb] - The callback function
  */
  sendSenderAction (recipient, senderAction, cb) {
    const req = {
      url: `${apiUrl}me/messages`,
      qs: {
        access_token: this.token
      },
      method: 'POST',
      json: {
        recipient: {
          id: recipient
        },
        sender_action: senderAction
      }
    }
    sendRequest(req, cb)
  }

  /**
  * This method will set a Greeting Text.
  *
  * @param {(object|string)} text - The greeting text
  * @callback [cb] - The callback function
  */
  setGreetingText (text, cb) {
    if (typeof text === 'string') {
      text = {text: text}
    }
    const method = 'POST'
    const params = {
      setting_type: 'greeting',
      greeting: text
    }
    this.sendThreadSettingsRequest(method, params, cb)
  }

  /**
  * This method will set a Get Started Button, in the welcome screen.
  *
  * @param {(object[]|string)} payload - The string payloads
  * @callback [cb] - The callback function
  */
  setGetStartedButton (payload, cb) {
    if (typeof payload === 'string') {  // Case a string is entered
      payload = [{
        payload: payload
      }]
    }
    const method = 'POST'
    const params = {
      setting_type: 'call_to_actions',
      thread_state: 'new_thread',
      call_to_actions: payload // max 1
    }
    this.sendThreadSettingsRequest(method, params, cb)
  }

  /**
  * This method will set a Persistent Menu, always available to the user.
  *
  * @param {object[]} menuItems - The menu items in the menu
  * @callback [cb] - The callback function
  */
  setPersistentMenu (menuItems, cb) {
    const method = 'POST'
    const params = {
      setting_type: 'call_to_actions',
      thread_state: 'existing_thread',
      call_to_actions: menuItems
    }
    this.sendThreadSettingsRequest(method, params, cb)
  }

  /**
  * This method will delete a Thread Setting. Get Started Button('new_thread')
  * or Persistent Menu('existing_thread')
  *
  * @param {string} threadType - The thread type to be deleted
  * @callback [cb] - The callback function
  */
  deleteThreadSetting (threadType, cb) {
    const method = 'DELETE'
    const params = {
      setting_type: 'call_to_actions',
      thread_state: threadType
    }
    this.sendThreadSettingsRequest(method, params, cb)
  }

  /**
  * This method will Configure the Thread Setting on Messenger.
  *
  * @param {string} method - The call request (POST or DELETE)
  * @param {object} params - The configuration parameters
  * @callback [cb] - The callback function
  */
  sendThreadSettingsRequest (method, params, cb) {
    const req = {
      url: `${apiUrl}me/thread_settings`,
      qs: {
        access_token: this.token
      },
      method: method,
      json: params
    }
    sendRequest(req, cb)
  }

  /**
  * This method will send an account linking call-2-action to the user.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} title - The title of the account linking CTA
  * @param {string} imageUrl - The URL of the image in the account linking CTA
  * @param {string} authUrl - The Authentication callback URL
  * @callback [cb] - The callback function
  */
  sendAccountLinkingMessage (recipient, title, imageUrl, authUrl, cb) {
    const message = {
      attachment: {
        type: 'tempalte',
        payload: {
          template_type: 'generic',
          elements: [{
            title: title,
            image_url: imageUrl,
            buttons: [{
              type: 'account_link',
              url: authUrl
            }]
          }]
        }
      }
    }
    this.sendApiMessage(recipient, message, cb)
  }

  /**
  * This method will retrieve the user page-scoped ID (PSID) using the account
  * linking endpoint.
  *
  * @param {string} token - The account linking token
  * @callback [cb] - The callback function
  */
  getUserPsid (token, cb) {
    const req = {
      url: `${apiUrl}me`,
      qs: {
        access_token: this.token,
        fields: 'recipient',
        account_linking_token: token
      },
      method: 'GET',
      json: true
    }
    sendRequest(req, cb)
  }

  /**
  * This method will send an account unlinking call-2-action to the user.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} title - The title of the account linking CTA
  * @param {string} imageUrl - The URL of the image in the account linking CTA
  * @callback [cb] - The callback function
  */
  sendAccountUnlinkingMessage (recipient, title, imageUrl, cb) {
    const message = {
      attachment: {
        type: 'tempalte',
        payload: {
          template_type: 'generic',
          elements: [{
            title: title,
            image_url: imageUrl,
            buttons: [{
              type: 'account_unlink'
            }]
          }]
        }
      }
    }
    this.sendApiMessage(recipient, message, cb)
  }

  /**
  * This method will unlink the user account.
  *
  * @param {string} psid - A valid page-scoped ID (PSID)
  * @callback [cb] - The callback function
  */
  unlinkAccount (psid, cb) {
    const req = {
      url: `${apiUrl}me/unlink_accounts`,
      qs: {
        access_token: this.token
      },
      method: 'POST',
      json: {
        psid: psid
      }
    }
    sendRequest(req, cb)
  }

  /**
  * This method will get the User Profile, used to query more information about
  * the user, and personalize the experience further.
  *
  * @param {string} userId - The user id
  * @callback [cb] - The callback function
  */
  getUserProfile (userId, cb) {
    const req = {
      url: `${apiUrl}${userId}`,
      qs: {
        access_token: this.token,
        fields: 'first_name,last_name,profile_pic,locale,timezone,gender'
      },
      method: 'GET',
      json: true
    }
    sendRequest(req, cb)
  }
}

/**
* This method will send a Request to the Send API.
*
* @param {object} req - The request being send
* @callback [cb] - The callback function
*/
const sendRequest = (req, cb) => {
  request(req, (error, response, body) => {
    if (!cb) return
    if (error) return cb(error)
    if (response.body.error) return cb(response.body.error)
    cb(null, response.body)
  })
}

export default Messenger
<commit_msg>docs(src/app.js): refactored comment in sendAttachmentMessage<commit_after>import request from 'request'

const apiUrl = 'https://graph.facebook.com/v2.6/'

/** Class representing a Facebook Messenger App. */
class Messenger {
  /**
   * Create a Messenger.
   *
   * @param {string} [token=null] - The Facebook Page Access Token.
   * @param {string} [notificationType=REGULAR] - The default message notification type.
   */
  constructor (token = null, notificationType = 'REGULAR') {
    this.token = token
    this.notificationType = notificationType

    if (!this.token) throw new Error('Facebook Page access token is missing.')
  }

  /**
  * This method will subscribe App via API
  *
  * @callback [cb] - The callback function
  */
  subscribeApp (cb) {
    const req = {
      url: `${apiUrl}me/subscribed_apps`,
      qs: {
        access_token: this.token
      },
      method: 'POST',
      json: true
    }
    sendRequest(req, cb)
  }

  /**
  * This method will send a plain Text Message.
  *
  * @param {string} recipient - The user id that will receive the message
  * @param {string} text - The text message (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendTextMessage (recipient, text, notificationType, cb) {
    const message = { text: message }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a Quick Replies Message.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object[]} quickReplies - The quick replies to be sent with messages
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendQuickMessage (recipient, quickReplies, notificationType, cb) {
    const message = { quick_replies: quickReplies }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Attachment Message.
  *
  * @param {string} recipient - The user id that will receive the message
  * @param {string} type - The attachment type [image, audio, video, file, location, template]
  * @param {object} payload - The attachment payload
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendAttachmentMessage (recipient, type, payload, notificationType, cb) {
    const message = {
      attachment: {
        type: type,
        payload: payload
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a file attachment. The file type must be image, audio, video or file).
  * Image supported formats [jpg, png and gifs]
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} type - The file type ['image', 'audio', 'video' or 'file']
  * @param {string} fileUrl - The file url where it is hosted (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendFileMessage (recipient, type, fileUrl, notificationType, cb) {
    const payload = { url: fileUrl }
    this.sendAttachmentMessage(recipient, type, payload, notificationType, cb)
  }

  /**
  * This method will send a text and buttons attachment to request input from the user.
  * The buttons can open a URL, or make a back-end call to your webhook.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} text - The head text of the button message
  * @param {object[]} buttons - The Set of call-to-action buttons
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendButtonMessage (recipient, text, buttons, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: {
          template_type: 'button',
          text: text,
          buttons: buttons
        }
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a Structured Generic Message, to send a horizontal scrollable carousel of items,
  * each composed of an image attachment, short description and buttons to request input from the user.
  * The buttons can open a URL, or make a back-end call to your webhook.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object[]} elements - The Data for each bubble in message
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendGenericMessage (recipient, elements, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: {
          template_type: 'generic',
          elements: elements
        }
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a Receipt Message, to send a order confirmation,
  * with the transaction summary and description for each item.
  *
  * @param {string} recipient - The receipient user id.
  * @param {object} receipt - The Receipt Template
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendReceiptMessage (recipient, receipt, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: receipt
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Airplane Itinerary Message, that contains the itinerary and receipt.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} itinerary - The payload of itinerary template (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendItineraryMessage (recipient, itinerary, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: itinerary
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Airplane Check-In Reminder Message.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} checkin - The payload of checkin template (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendCheckinMessage (recipient, checkin, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: checkin
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Airplane Boarding Pass Message, that contains boarding
  * passes for one or more flights or one more passengers
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} boardingpass - The payload of boarding pass template (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendBoardingpassMessage (recipient, boardingpass, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: boardingpass
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Airplane Flight Update Message.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} flightupdate - The payload of flight update template (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendFlightupdateMessage (recipient, flightupdate, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: flightupdate
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a message to the user.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} message - The message object (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendApiMessage (recipient, message, notificationType, cb) {
    if (typeof notificationType === 'function') {
      cb = notificationType
      notificationType = this.notificationType
    }
    const req = {
      url: `${apiUrl}me/messages`,
      qs: {
        access_token: this.token
      },
      method: 'POST',
      json: {
        recipient: {
          id: recipient
        },
        message: message,
        notification_type: notificationType
      }
    }
    sendRequest(req, cb)
  }

  /**
  * This method will send Sender Actions, this are typing indicators or send read receipts,
  * to let the user know you are processing their request
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} senderAction - The action typing indicator (required)
  * @callback [cb] - The callback function
  */
  sendSenderAction (recipient, senderAction, cb) {
    const req = {
      url: `${apiUrl}me/messages`,
      qs: {
        access_token: this.token
      },
      method: 'POST',
      json: {
        recipient: {
          id: recipient
        },
        sender_action: senderAction
      }
    }
    sendRequest(req, cb)
  }

  /**
  * This method will set a Greeting Text.
  *
  * @param {(object|string)} text - The greeting text
  * @callback [cb] - The callback function
  */
  setGreetingText (text, cb) {
    if (typeof text === 'string') {
      text = {text: text}
    }
    const method = 'POST'
    const params = {
      setting_type: 'greeting',
      greeting: text
    }
    this.sendThreadSettingsRequest(method, params, cb)
  }

  /**
  * This method will set a Get Started Button, in the welcome screen.
  *
  * @param {(object[]|string)} payload - The string payloads
  * @callback [cb] - The callback function
  */
  setGetStartedButton (payload, cb) {
    if (typeof payload === 'string') {  // Case a string is entered
      payload = [{
        payload: payload
      }]
    }
    const method = 'POST'
    const params = {
      setting_type: 'call_to_actions',
      thread_state: 'new_thread',
      call_to_actions: payload // max 1
    }
    this.sendThreadSettingsRequest(method, params, cb)
  }

  /**
  * This method will set a Persistent Menu, always available to the user.
  *
  * @param {object[]} menuItems - The menu items in the menu
  * @callback [cb] - The callback function
  */
  setPersistentMenu (menuItems, cb) {
    const method = 'POST'
    const params = {
      setting_type: 'call_to_actions',
      thread_state: 'existing_thread',
      call_to_actions: menuItems
    }
    this.sendThreadSettingsRequest(method, params, cb)
  }

  /**
  * This method will delete a Thread Setting. Get Started Button('new_thread')
  * or Persistent Menu('existing_thread')
  *
  * @param {string} threadType - The thread type to be deleted
  * @callback [cb] - The callback function
  */
  deleteThreadSetting (threadType, cb) {
    const method = 'DELETE'
    const params = {
      setting_type: 'call_to_actions',
      thread_state: threadType
    }
    this.sendThreadSettingsRequest(method, params, cb)
  }

  /**
  * This method will Configure the Thread Setting on Messenger.
  *
  * @param {string} method - The call request (POST or DELETE)
  * @param {object} params - The configuration parameters
  * @callback [cb] - The callback function
  */
  sendThreadSettingsRequest (method, params, cb) {
    const req = {
      url: `${apiUrl}me/thread_settings`,
      qs: {
        access_token: this.token
      },
      method: method,
      json: params
    }
    sendRequest(req, cb)
  }

  /**
  * This method will send an account linking call-2-action to the user.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} title - The title of the account linking CTA
  * @param {string} imageUrl - The URL of the image in the account linking CTA
  * @param {string} authUrl - The Authentication callback URL
  * @callback [cb] - The callback function
  */
  sendAccountLinkingMessage (recipient, title, imageUrl, authUrl, cb) {
    const message = {
      attachment: {
        type: 'tempalte',
        payload: {
          template_type: 'generic',
          elements: [{
            title: title,
            image_url: imageUrl,
            buttons: [{
              type: 'account_link',
              url: authUrl
            }]
          }]
        }
      }
    }
    this.sendApiMessage(recipient, message, cb)
  }

  /**
  * This method will retrieve the user page-scoped ID (PSID) using the account
  * linking endpoint.
  *
  * @param {string} token - The account linking token
  * @callback [cb] - The callback function
  */
  getUserPsid (token, cb) {
    const req = {
      url: `${apiUrl}me`,
      qs: {
        access_token: this.token,
        fields: 'recipient',
        account_linking_token: token
      },
      method: 'GET',
      json: true
    }
    sendRequest(req, cb)
  }

  /**
  * This method will send an account unlinking call-2-action to the user.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} title - The title of the account linking CTA
  * @param {string} imageUrl - The URL of the image in the account linking CTA
  * @callback [cb] - The callback function
  */
  sendAccountUnlinkingMessage (recipient, title, imageUrl, cb) {
    const message = {
      attachment: {
        type: 'tempalte',
        payload: {
          template_type: 'generic',
          elements: [{
            title: title,
            image_url: imageUrl,
            buttons: [{
              type: 'account_unlink'
            }]
          }]
        }
      }
    }
    this.sendApiMessage(recipient, message, cb)
  }

  /**
  * This method will unlink the user account.
  *
  * @param {string} psid - A valid page-scoped ID (PSID)
  * @callback [cb] - The callback function
  */
  unlinkAccount (psid, cb) {
    const req = {
      url: `${apiUrl}me/unlink_accounts`,
      qs: {
        access_token: this.token
      },
      method: 'POST',
      json: {
        psid: psid
      }
    }
    sendRequest(req, cb)
  }

  /**
  * This method will get the User Profile, used to query more information about
  * the user, and personalize the experience further.
  *
  * @param {string} userId - The user id
  * @callback [cb] - The callback function
  */
  getUserProfile (userId, cb) {
    const req = {
      url: `${apiUrl}${userId}`,
      qs: {
        access_token: this.token,
        fields: 'first_name,last_name,profile_pic,locale,timezone,gender'
      },
      method: 'GET',
      json: true
    }
    sendRequest(req, cb)
  }
}

/**
* This method will send a Request to the Send API.
*
* @param {object} req - The request being send
* @callback [cb] - The callback function
*/
const sendRequest = (req, cb) => {
  request(req, (error, response, body) => {
    if (!cb) return
    if (error) return cb(error)
    if (response.body.error) return cb(response.body.error)
    cb(null, response.body)
  })
}

export default Messenger
<|endoftext|>


<commit_before>define(function(require, exports, module) {
    main.consumes = [
        "Plugin", "remote", "watcher", "fs"
    ];
    main.provides = ["CSSDocument"];
    return main;

    function main(options, imports, register) {
        var Plugin = imports.Plugin;
        var remote = imports.remote;
        var watcher = imports.watcher;
        var fs = imports.fs;

        var style = document.createElement("style");
        document.documentElement.appendChild(style);

        function CSSDocument(path) {
            var exists = remote.findDocument(path);
            if (exists) return exists;

            /***** Initialization *****/

            var plugin = new Plugin("Ajax.org", main.consumes);
            // var emit = plugin.getEmitter();

            var transports = [];
            var tab, doc;

            var loaded = false;
            function load() {
                if (loaded) return false;
                loaded = true;

                remote.register(plugin);
            }

            /***** Methods *****/

            function addTransport(transport) {
                if (transports.indexOf(transport) == -1) {
                    transports.push(transport);

                    transport.addOther(function(){
                        var idx = transports.indexOf(transport);
                        if (~idx) {
                            transports.splice(idx, 1);

                            if (transports.length === 0)
                                plugin.unload();
                        }
                    });
                }

                if (tab && tab.isActive())
                    updateHighlight(true);

                if (doc && doc.changed)
                    update();

                return plugin;
            }

            function initTab(t) {
                if (!t) {
                    doc = null;
                    if (tab) {
                        fs.readFile(path, function(err, data) {
                            update(null, data);
                        });
                    }
                    tab = null;
                    return;
                }

                tab = t;
                doc = tab.document;

                tab.on("activate", function(){ updateHighlight(); }, plugin);
                tab.on("deactivate", function(){ updateHighlight(false); }, plugin);

                var c9session = doc.getSession();
                c9session.once("init", function(e) {
                    // Listen for change in the document
                    e.session.on("change", function(e){ update(e.data); });

                    // Listen for cursor position change
                    e.session.selection.on("changeCursor", updateHighlight);
                });

                // Listen for a tab close event
                tab.on("close", function(){ watcher.watch(path); }, plugin);
            }

            var lastQuery;
            var reCssQuery = /(^|.*\})(.*)\{|\}/;
            function updateHighlight(e) {
                var query;

                if (tab && e !== false) {
                    var session = doc.getSession().session;
                    if (!session) return;

                    var lines = session.doc.$lines;
                    var cursor = session.selection.lead;

                    if (!lines[cursor.row]) {
                        return; //@todo
                    }

                    var line = lines[cursor.row].substr(0, cursor.column);

                    var started = false;
                    if (line.match(reCssQuery)) {
                        query = RegExp.$2;
                        started = true;
                    }

                    if (!started || query) {
                        for (var i = cursor.row - 1; i >= 0; i--) {
                            if (started) {
                                if (lines[i].match(/[\}\;]/))
                                    break;
                                else
                                    query = lines[i] + " " + query;
                            }
                            else if (lines[i].match(reCssQuery)) {
                                query = RegExp.$2;
                                if (!query) break;
                                started = true;
                            }
                        }
                    }
                }
                else {
                    query = false;
                }

                var rules = style.sheet.cssRules || style.sheet.rules;
                if (query && rules.length) {
                    style.textContent = query + "{}";
                    query = rules[0].selectorText;
                }

                // Remember the last query
                lastQuery = query;

                // Send the highlight command
                transports.forEach(function(transport) {
                    transport.highlightCSSQuery(query, e === true);
                });
            }

            function remove(){
                transports.forEach(function(transport) {
                    transport.deleteStyleSheet(path);
                });
            }

            // var timer, lastValue;
            // function updateDelayed(changes, value) {
            //     if (!timer) {
            //         timer = setTimeout(function(){
            //             timer = null;
            //             update(null, lastValue);
            //         }, 30);
            //     }
            //     else {
            //         lastValue = value;
            //     }
            // }

            function update(changes, value) {
                // single line
                // {
                // action: "insertText" | "removeText"
                // text: "string"
                // range: {start, end}
                // }
                // multiline
                // {
                // action: "insertLines" | "removeLines"
                // lines: ["string", ...]
                // range: {start, end}
                // }

                var range = changes && changes.range;
                if (changes && lastQuery && changes.text && range.start.row == range.end.row
                  && (changes.text != "insertText" || changes.text.indexOf(";") == -1)) {
                    var session = doc.getSession().session;
                    var line = session.doc.$lines[range.end.row];
                    var section = changes.action == "insertText"
                        ? line.substr(range.start.column, range.end.column - range.start.column) //changes.text
                        : "";
                    var idx = section.indexOf(";");

                    // Only allow a single rule edit
                    if (idx == -1 || idx == section.length - 1) {
                        var char;
                        if (idx == -1) {
                            for (var i = range.end.column; i < line.length; i++) {
                                char = line.charAt(i);
                                if (char == ";") break;
                                section += char;
                            }
                        }
                        var start = range.start.column - 1
                            + (changes.action == "removeText" ? changes.text.length : 0);
                        for (var i = start; i >= 0; i--) {
                            char = line.charAt(i);
                            if (char == ";") break;
                            section = char + section;
                        }

                        var parts = section.split(":");
                        var key = parts[0].trim();
                        var css = (parts[1] || "").trim();
                        if (key) {
                            var rule = {
                                selector: lastQuery,
                                key: key,
                                value: css
                            };

                            transports.forEach(function(transport) {
                                transport.updateStyleRule(path, rule);
                            });

                            return;
                        }
                    }
                }

                transports.forEach(function(transport) {
                    transport.updateStyleSheet(path, value || doc.value);
                });
            }

            /***** Lifecycle *****/

            plugin.on("load", function() {
                load();
            });
            plugin.on("enable", function() {

            });
            plugin.on("disable", function() {

            });
            plugin.on("unload", function() {
                loaded = false;
            });

            /***** Register and define API *****/

            /**
             *
             **/
            plugin.freezePublicAPI({
                /**
                 *
                 */
                get path(){ return path; },

                /**
                 *
                 */
                get tab(){ return tab; },

                /**
                 *
                 */
                set tab(tab){ initTab(tab); },

                _events: [
                    /**
                     * @event draw
                     */
                    "draw"
                ],

                /**
                 *
                 */
                addTransport: addTransport,

                /**
                 *
                 */
                remove: remove,

                /**
                 *
                 */
                update: update
            });

            plugin.load(null, "cssdocument");

            return plugin;
        }

        register(null, {
            CSSDocument: CSSDocument
        });
    }
});<commit_msg>fix Cannot read property 'value' of null<commit_after>define(function(require, exports, module) {
    main.consumes = [
        "Plugin", "remote", "watcher", "fs"
    ];
    main.provides = ["CSSDocument"];
    return main;

    function main(options, imports, register) {
        var Plugin = imports.Plugin;
        var remote = imports.remote;
        var watcher = imports.watcher;
        var fs = imports.fs;

        var style = document.createElement("style");
        document.documentElement.appendChild(style);

        function CSSDocument(path) {
            var exists = remote.findDocument(path);
            if (exists) return exists;

            /***** Initialization *****/

            var plugin = new Plugin("Ajax.org", main.consumes);
            // var emit = plugin.getEmitter();

            var transports = [];
            var tab, doc;

            var loaded = false;
            function load() {
                if (loaded) return false;
                loaded = true;

                remote.register(plugin);
            }

            /***** Methods *****/

            function addTransport(transport) {
                if (transports.indexOf(transport) == -1) {
                    transports.push(transport);

                    transport.addOther(function(){
                        var idx = transports.indexOf(transport);
                        if (~idx) {
                            transports.splice(idx, 1);

                            if (transports.length === 0)
                                plugin.unload();
                        }
                    });
                }

                if (tab && tab.isActive())
                    updateHighlight(true);

                if (doc && doc.changed)
                    update();

                return plugin;
            }

            function initTab(t) {
                if (!t) {
                    doc = null;
                    if (tab) {
                        fs.readFile(path, function(err, data) {
                            update(null, data);
                        });
                    }
                    tab = null;
                    return;
                }

                tab = t;
                doc = tab.document;

                tab.on("activate", function(){ updateHighlight(); }, plugin);
                tab.on("deactivate", function(){ updateHighlight(false); }, plugin);

                var c9session = doc.getSession();
                c9session.once("init", function(e) {
                    // Listen for change in the document
                    e.session.on("change", function(e){ update(e.data); });

                    // Listen for cursor position change
                    e.session.selection.on("changeCursor", updateHighlight);
                });

                // Listen for a tab close event
                tab.on("close", function(){ watcher.watch(path); }, plugin);
            }

            var lastQuery;
            var reCssQuery = /(^|.*\})(.*)\{|\}/;
            function updateHighlight(e) {
                var query;

                if (tab && e !== false) {
                    var session = doc.getSession().session;
                    if (!session) return;

                    var lines = session.doc.$lines;
                    var cursor = session.selection.lead;

                    if (!lines[cursor.row]) {
                        return; //@todo
                    }

                    var line = lines[cursor.row].substr(0, cursor.column);

                    var started = false;
                    if (line.match(reCssQuery)) {
                        query = RegExp.$2;
                        started = true;
                    }

                    if (!started || query) {
                        for (var i = cursor.row - 1; i >= 0; i--) {
                            if (started) {
                                if (lines[i].match(/[\}\;]/))
                                    break;
                                else
                                    query = lines[i] + " " + query;
                            }
                            else if (lines[i].match(reCssQuery)) {
                                query = RegExp.$2;
                                if (!query) break;
                                started = true;
                            }
                        }
                    }
                }
                else {
                    query = false;
                }

                var rules = style.sheet.cssRules || style.sheet.rules;
                if (query && rules.length) {
                    style.textContent = query + "{}";
                    query = rules[0].selectorText;
                }

                // Remember the last query
                lastQuery = query;

                // Send the highlight command
                transports.forEach(function(transport) {
                    transport.highlightCSSQuery(query, e === true);
                });
            }

            function remove(){
                transports.forEach(function(transport) {
                    transport.deleteStyleSheet(path);
                });
            }

            // var timer, lastValue;
            // function updateDelayed(changes, value) {
            //     if (!timer) {
            //         timer = setTimeout(function(){
            //             timer = null;
            //             update(null, lastValue);
            //         }, 30);
            //     }
            //     else {
            //         lastValue = value;
            //     }
            // }

            function update(changes, value) {
                // single line
                // {
                // action: "insertText" | "removeText"
                // text: "string"
                // range: {start, end}
                // }
                // multiline
                // {
                // action: "insertLines" | "removeLines"
                // lines: ["string", ...]
                // range: {start, end}
                // }

                var range = changes && changes.range;
                if (changes && lastQuery && changes.text && range.start.row == range.end.row
                  && (changes.text != "insertText" || changes.text.indexOf(";") == -1)) {
                    var session = doc.getSession().session;
                    var line = session.doc.$lines[range.end.row];
                    var section = changes.action == "insertText"
                        ? line.substr(range.start.column, range.end.column - range.start.column) //changes.text
                        : "";
                    var idx = section.indexOf(";");

                    // Only allow a single rule edit
                    if (idx == -1 || idx == section.length - 1) {
                        var char;
                        if (idx == -1) {
                            for (var i = range.end.column; i < line.length; i++) {
                                char = line.charAt(i);
                                if (char == ";") break;
                                section += char;
                            }
                        }
                        var start = range.start.column - 1
                            + (changes.action == "removeText" ? changes.text.length : 0);
                        for (var i = start; i >= 0; i--) {
                            char = line.charAt(i);
                            if (char == ";") break;
                            section = char + section;
                        }

                        var parts = section.split(":");
                        var key = parts[0].trim();
                        var css = (parts[1] || "").trim();
                        if (key) {
                            var rule = {
                                selector: lastQuery,
                                key: key,
                                value: css
                            };

                            transports.forEach(function(transport) {
                                transport.updateStyleRule(path, rule);
                            });

                            return;
                        }
                    }
                }

                if (value == undefined)
                    value = doc && doc.value || "";
                transports.forEach(function(transport) {
                    transport.updateStyleSheet(path, value);
                });
            }

            /***** Lifecycle *****/

            plugin.on("load", function() {
                load();
            });
            plugin.on("enable", function() {

            });
            plugin.on("disable", function() {

            });
            plugin.on("unload", function() {
                loaded = false;
            });

            /***** Register and define API *****/

            /**
             *
             **/
            plugin.freezePublicAPI({
                /**
                 *
                 */
                get path(){ return path; },

                /**
                 *
                 */
                get tab(){ return tab; },

                /**
                 *
                 */
                set tab(tab){ initTab(tab); },

                _events: [
                    /**
                     * @event draw
                     */
                    "draw"
                ],

                /**
                 *
                 */
                addTransport: addTransport,

                /**
                 *
                 */
                remove: remove,

                /**
                 *
                 */
                update: update
            });

            plugin.load(null, "cssdocument");

            return plugin;
        }

        register(null, {
            CSSDocument: CSSDocument
        });
    }
});<|endoftext|>


<commit_before>'use strict';

const apiai = require('apiai');
const express = require('express');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const request = require('request');

const REST_PORT = (process.env.PORT || 5000);
const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN;
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;

const apiAiService = apiai(APIAI_ACCESS_TOKEN, "deprecated", {});
const sessionIds = new Map();

function sendFBMessage(sender, messageData) {
    request({
        url: 'https://graph.facebook.com/v2.6/me/messages',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            recipient: {id: sender},
            message: messageData
        }
    }, function (error, response, body) {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }
    });
}

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

const app = express();
app.use(bodyParser.json());
app.all('*', function (req, res, next) {
    // res.header("Access-Control-Allow-Origin", '*');
    // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, content-type, accept");
    next();
});

app.get('/webhook/', function (req, res) {
    if (req.query['hub.verify_token'] == FB_VERIFY_TOKEN) {
        res.send(req.query['hub.challenge']);
    } else {
        res.send('Error, wrong validation token');
    }
});

function processEvent(event) {
    var sender = event.sender.id;

    if (event.message && event.message.text) {
        var text = event.message.text;
        // Handle a text message from this sender

        if (!sessionIds.has(sender)) {
            sessionIds.set(sender, uuid.v1());
        }

        console.log("Text", text);

        let apiaiRequest = apiAiService.textRequest(text,
            {
                sessionId: sessionIds.get(sender)
            });

        apiaiRequest.on('response', (response) => {
            if (isDefined(response.result)) {
                let responseText = response.result.fulfillment.speech;
                let responseData = response.result.data;
                let action = response.result.action;

                if (isDefined(responseData)) {
                    try {
                        let responseObject = JSON.parse(responseData);
                        sendFBMessage(sender, responseObject.facebook);
                    } catch (err) {
                        sendFBMessage(sender, err.message);
                    }
                } else if (isDefined(responseText)) {
                    sendFBMessage(sender, {text: responseText});
                }

            }
        });

        apiaiRequest.on('error', (error) => console.error(error));
        apiaiRequest.end();
    }
}

app.post('/webhook/', function (req, res) {
    var messaging_events = req.body.entry[0].messaging;
    for (var i = 0; i < messaging_events.length; i++) {
        var event = req.body.entry[0].messaging[i];
        processEvent(event);
    }
    res.sendStatus(200);
});

app.listen(REST_PORT, function () {
    console.log('Rest service ready on port ' + REST_PORT);
});<commit_msg>Structural changes<commit_after>'use strict';

const apiai = require('apiai');
const express = require('express');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const request = require('request');

const REST_PORT = (process.env.PORT || 5000);
const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN;
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;

const apiAiService = apiai(APIAI_ACCESS_TOKEN, "deprecated", {});
const sessionIds = new Map();

function processEvent(event) {
    var sender = event.sender.id;

    if (event.message && event.message.text) {
        var text = event.message.text;
        // Handle a text message from this sender

        if (!sessionIds.has(sender)) {
            sessionIds.set(sender, uuid.v1());
        }

        console.log("Text", text);

        let apiaiRequest = apiAiService.textRequest(text,
            {
                sessionId: sessionIds.get(sender)
            });

        apiaiRequest.on('response', (response) => {
            if (isDefined(response.result)) {
                let responseText = response.result.fulfillment.speech;
                let responseData = response.result.data;
                let action = response.result.action;

                if (isDefined(responseData)) {
                    try {
                        let responseObject = JSON.parse(responseData);
                        sendFBMessage(sender, responseObject.facebook);
                    } catch (err) {
                        sendFBMessage(sender, err.message);
                    }
                } else if (isDefined(responseText)) {
                    sendFBMessage(sender, {text: responseText});
                }

            }
        });

        apiaiRequest.on('error', (error) => console.error(error));
        apiaiRequest.end();
    }
}

function sendFBMessage(sender, messageData) {
    request({
        url: 'https://graph.facebook.com/v2.6/me/messages',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            recipient: {id: sender},
            message: messageData
        }
    }, function (error, response, body) {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }
    });
}

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

const app = express();
app.use(bodyParser.json());
app.all('*', function (req, res, next) {
    // res.header("Access-Control-Allow-Origin", '*');
    // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, content-type, accept");
    next();
});

app.get('/webhook/', function (req, res) {
    if (req.query['hub.verify_token'] == FB_VERIFY_TOKEN) {
        res.send(req.query['hub.challenge']);
    } else {
        res.send('Error, wrong validation token');
    }
});

app.post('/webhook/', function (req, res) {
    try{
        var messaging_events = req.body.entry[0].messaging;
        for (var i = 0; i < messaging_events.length; i++) {
            var event = req.body.entry[0].messaging[i];
            processEvent(event);
        }
        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

app.listen(REST_PORT, function () {
    console.log('Rest service ready on port ' + REST_PORT);
});<|endoftext|>