• Concept and Superiority

        foonyah relies on module-oriented thinking. Application can construct as a cluster of modules which is made on 3-tier application architecture.

      • Architectrue

        • Base Technology

          foonyah is using node.js and mongodb as a core technology.
          but you never be asserted this environment. Any database, any language or any system can join to foonyah.
          • Secure Http and WebSocket support
          • Java Script, JSON native
          • Cloud and cluster
        • Pugin Technology

          on foonyah, you can use all plugin very simply and object oriented.
          • Simple import and call
            you can import modules only call app.prepare function.
              app.prepare('tablify');
            app is an foonyah object. (see more in "practical sample")
            tablify is a preserved module to make table dom structure easily.

            you can retrieve APIs in tablify module not only on browser, but also on server.
              var tablify= foonyah.use('tablify');

            and you can make table dom structure easily.
              var table = tablify(4,5);
            table.find('td').each(function(i){
            $(this).text(i);
            });
            $('body').append(table);

          • Powerful inherit, extend

          • Offered modules
        • Core Engine

          • DOMWindow
          • Socket Perser
          • GridFS
          • Cluster Session
        • Core Library

          • foonyah
            foonyah is not only the code name of this project but also a namespace for your scripting. In addition, foonyah has many module to implement the idea , foonyah.
          • jQuery
            jQuery is a very popular library and foonyah server preloads this library. Default load version is the latest which can be get from http://jquery.com/. Now, the version is 2.0.3.

            To get/link to original source, access to "http://code.jquery.com/jquery-x.x.x[.min].js" .
            e.g. 1.12.1 ( compressed ) , 2.2.1 ( compressed ) ,
          • xjQuery
            xjQuery is a code name which means "eXtend event engine for jQuery with foonyah".
            Source is published at github with MIT Licenced.
            See detail on xjQuery document.
      • Benchmark

        Response Test by httperf

        Total: connections 10 requests 100 replies 100 test-duration 1.039 s

        Connection rate: 9.6 conn/s (103.9 ms/conn, <=10 concurrent connections)
        Connection time [ms]: min 967.6 avg 1003.5 max 1029.7 median 1000.5 stddev 20.9
        Connection time [ms]: connect 0.1
        Connection length [replies/conn]: 10.000

        Request rate: 96.3 req/s (10.4 ms/req)
        Request size [B]: 62.0

        Reply rate [replies/s]: min 0.0 avg 0.0 max 0.0 stddev 0.0 (0 samples)
        Reply time [ms]: response 100.3 transfer 0.0
        Reply size [B]: header 156.0 content 10224.0 footer 2.0 (total 10382.0)
        Reply status: 1xx=0 2xx=100 3xx=0 4xx=0 5xx=0

        CPU time [s]: user 0.09 system 0.92 (user 8.6% system 89.0% total 97.6%)
        Net I/O: 981.5 KB/s (8.0*10^6 bps)

      • Trademarks, patents and essay

        Japan Patent Office Application
        - 2011-102203 (12.04.2011)
        - 2011-223375 (20.09.2011)
        - 2011-223376 (20.09.2011)
        - 2011-223377 (20.09.2011)
        - 2012-130242 (22.05.2012) [Priority Target]
        - 2012-289435 (21.12.2012)

        Japan Patent Office Trademark
        - 2012- 44775 (20.11.2012)

        Patent Cooperation Treaty Application
        - PCT/JP2012/084267
      • Copyright, Licences

        All sources and plugins are LICENSED by Liberty Technology.
        • start.js

          [ practical source ]
          /***/
          // import configuration files and launch service
          foonyah.start({
          server: require( './configure/server'),
          cluster: require('./configure/cluster')
          });
          • explain
            module "foonyah" have a method "start()".
            Project root directory should be given for the first argument, if you are not execute node process in the root of your system project.
            At the second argument, foonyah accepts setting file to change server and cluster condition.
        • cluster.js

          [ practical source ]
          module.exports = clusterConfig;
          function clusterConfig() {
          var conf = {}, secret_key = '/Users/ystk_skm/.ssh/id_rsa';
          conf.jpcloud = {
          regexp: {
          hostname: /MacBook-Air|GMO-Cloud/,
          },
          forwarded: {
          user: 'jp-admin',
          secret_key: secret_key
          },
          facade: [{
          exp: 'US',
          type: 'encloud'
          }],
          clusterhub: true,
          database: true,
          starts: [{
          ip: '',
          type: 'encloud'
          }]
          };
          conf.encloud = {
          regexp: {
          hostname: /Rackspace-Cloud/,
          },
          forwarded: {
          user: 'us-admin',
          secret_key: secret_key
          },
          facade: [{
          exp: '!US',
          type: 'jpcloud'
          }],
          clusterhub: true,
          database: true
          };
          return conf;
          }
          • explain
        • server.js

          [ practical source ]
          /***/
          var path = require('path');
          /* server configuration for project "sample" */
          module.exports = serverConfig;
          function serverConfig() {
          var rootdir = path.resolve('..'), conf = {};
          var basic = {
          http: [httpSet(80, false, true), httpSet(443, true, false)],
          };
          ['jpcloud', 'encloud'].forEach(function(k) {
          conf[k] = basic;
          });
          return conf;
          }
          function httpSet(port, ssl, ws) {
          var rootdir = path.resolve('..');
          var base = {
          port: port,
          redirect: {
          http2https: {
          regexp: /http:\/\/([^\/]+)\/([^\/]+)\//,
          redirect: function(furl, mtc) {
          return furl.replace(/^http:/, 'https:');
          }
          },
          },
          alias: {
          cloudplus: {
          regexp: /https?:\/\/cloudplus\.me\//,
          replace: ['', '/cloudplus.me'],
          except: new RegExp('\\\/\\\/[^\\\/]+\\\/(' + excepts.join("|") + ')')
          }
          },
          websocket: ws,
          fork: false
          };
          var path_to_ssl = null;
          if(ssl === true) {
          path_to_ssl = function(type) {
          return '/home/appadmin/ssl/RapidSSL2013.' + type;
          };
          base.ssl = {
          key: path_to_ssl('key'),
          ca: path_to_ssl('ca'),
          cert: path_to_ssl('cer')
          };
          }
          } else
          delete base.ssl;
          return base;
          };
          • explain
        • setting.js

          [ L1-L4 ]
          It defines some variable for pathname fixing.
          In this sample case, root path ("http://cloudplus.me/") should call file in "(document_root)/coudplus.me" directry.
          In addition, there is no aware of the corresponding OS file system and foonyah grid-fs.
          /***/
          //common
          var name = 'PirtyGoods', pfix = '/cloudplus.me', fix = '/PirtyGoods';
          [ L5-L17 ] Application parameters is defined in this area.
          These parameters ups on memory when application first call (=first launch) or refresh call (=url with "?refresh" query).
          Application
          It will set "foonyah.Application" name space and it also means of MongoDB database name for this application.
          PathnameAdjuster
          It will set for calculate foonyah's internal pathname for dynamic application calling.
          See detail explain below ( [L18-L27] )
          StreamUrlChanger
          It will set for calculate foonyah's internal stream call for save memory use and response improvement.
          See detail explain below ( [L28-L35] )
          CacheTime
          It defines cache time for heavy access to particular url.
          In this time, foonyah outputs same data stream for cacheOut mode.
          //create application
          var app = foonyah({
          Application: name,
          PathnameAdjuster: adjuster,
          CacheTime: 5000,
          ShowDebug: '%_ShowDebug_%',
          Stdout: '%_Stdout_%',
          Stream: '%_Stream_%',
          DbPlugins: false,
          ReleaseDt: '%_ReleaseDt_%'//'2011/09/30 19:40'
          }, opt);
          // pathname adjuster
          function adjuster(pn) {
          if(~pn.indexOf(pfix))
          pn = pn.replace(pfix, '');
          return pn.replace(fix, '');
          }
          //install modules
          var alw = 'htmlgen tablify bootstrap'.split(" ");
          app.prepare('*', alw.concat({
          name: 'Cloudplus_GoogleAnalytics',
          type: 'googleanalytics',
          pack: {
          Default: {
          account: 'UA-17879446-6',
          domain_name: 'cloudplus.me'
          }
          }
          }));
          //titles
          var c = 'Party Goods + me.', Titles = {
          home: {
          en: c + ' ~ Lets\'s get pirty goods!',
          ja: c + ' ~ パーティーゲームで会を盛り上げよう!'
          }
          };
          var keywords = ['Party Goods', 'game', 'party', 'plus', 'me', 'cloud'], descriptions = {
          en: 'Variety of party goods and games for free!',
          ja: 'パーティーグッズ + me で無料の盛り上げツールが手に入る!'
          };
          var lnOrEn = function(tgt, ln) {
          return tgt[ln] || tgt['en'];
          };
          //pages
          var Pages = {
          home: {
          path: '/',
          title: function(ln) {
          return lnOrEn(Titles.home, ln);
          }
          },
          rp: {
          path: '/rp/',
          title: function(ln) {
          return lnOrEn(Titles.home, ln);
          }
          }
          };
          //setting function
          function opt() {
          return {
          '*': {
          // html: ['', ''],
          title: getTitle,
          meta: getMeta,
          rel: getRel,
          css: getCss,
          body: getBody,
          svrjs: getSvrjs,
          wssjs: null,
          fstjs: null,
          bwsjs: getBwsjs,
          //nojs: false,
          cacheKey: getCacheKey,
          // stack: undefined,
          // contentType: 'text/html',
          // charset: null,
          // convert: false
          }
          };
          };
          //title
          function getTitle(res, loc, nav) {
          if(pfix && loc.host.indexOf(pfix.substr(1)) == -1)
          fix = pfix + fix, pfix = '';
          foonyah.simplePages.call(this, Pages, {
          prefix: pfix,
          fix: fix
          });
          return foonyah.simpleTitle.call(this, loc, nav);
          }
          //meta
          function getMeta(res, loc, nav) {
          var ln = nav.language, dev = nav.Device;
          var com = ', initial-scale=1.0, minimum-scale=1.0';
          // meta
          var meta = {
          'http-equiv': [["Cache-Control", "public"]],
          'name': [["robots", "INDEX,FOLLOW"], ["keyword", keywords.join(',')],
          ["description", lnOrEn(descriptions, ln)]]
          };
          // device view port
          if(dev == 'tablet' || dev == 'mobile')
          meta.name.push(["viewport", "width=device-width" + com]);
          return meta;
          }
          //rel
          function getRel(res, loc, nav) {
          var rel = {
          src: {
          'css/images/': [['shortcut icon', 'icon.png', 'image/ico'],
          ['apple-touch-icon', 'icon.png', 'image/png']]
          }
          };
          return rel;
          }
          //css
          function getCss(res, loc, nav) {
          return foonyah.simpleSourceHash.call(this, loc, nav, 'css');
          };
          //body
          function getBody(res, loc, nav) {
          var c = 'class="' + (nav.Compatibility === true ? '': 'no-') + 'html5' + '"';
          return [''];
          }
          //server-side js
          function getSvrjs(res, loc, nav) {
          return foonyah.simpleSourceHash.call(this, loc, nav, 'svrjs');
          };
          //browser-side js
          function getBwsjs(res, loc, nav) {
          var jq = '/jQuery/jquery-';
          var fn = function(key, box, dir, def_fn) {
          box.src[jq] = ['easing.1.3', 'gestures.1.0.1'];
          var jss = key == 'rp' ? ['index-rp']: [];
          def_fn(jss.concat('index'));
          };
          return foonyah.simpleSourceHash.call(this, loc, nav, 'bwsjs', fn);
          }
          //cache
          function getCacheKey(loc, nav) {
          var ck = loc._pathname + ':' + nav.Device + ':'
          + (loc.query.ln || nav.language);
          return foonyah.debug('Use cache key: ' + ck), ck;
          }
          • explain