• This document and some tools for foonyah are under construction. However, the product foonyah is growing forcefully. Please contact us tied up with your interest! - Liberty Technology

      foonyah is an architecture for cloud-based computer system in a network. Agile oriented although 3-tier application architecture can be utilized in common sense, needless to have special conscious of it. The most individual point of foonyah is the module import function. Very simple, very easy and amazingly flexible.

      • 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.
          • http / ws (ssl also)
          • javascript, JSON native
          • cloud and distributed servers
        • pugin technology

          on foonyah, you can use all plugin very simply and object oriented.
          • simple plugin call
            you can import modules only call jqyin.prepare function.
              jqyin.prepare('tablify');
            jqyin is an namespace for using foonyah system.
            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= jqyin.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 plugin technology

          • default modules
        • core modules

          • DOMWindow
          • Socket Perser
          • GridFS
          • ClusterSession
        • 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.10.2 ( compressed ) , 2.0.3 ( compressed ) ,
          • xjQuery
            xjQuery is a code name which means "eXtend event engine for jQuery with foonyah".
            Source is opened at github with MIT Licenced.
            See detail on xjQuery document.
      • bench mark

        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)

      • patent & 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

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

          [ practical source ]
          /***/
          /* project "sample" start.js */
          var path = require('path');
          // set project root;
          var prjroot = path.resolve(__dirname, '..');
          var foonyah = require('foonyah');
          // import configuration files and launch service
          var confdir = path.join(prjroot, 'configure');
          foonyah.start(prjroot, {
          server: require(path.join(confdir, 'server')),
          cluster: require(path.join(confdir, 'cluster'))
          });
          • explain
            module "foonyah" have only a method "start()".
            You SHOULD give project root directory ( "prjroot" above. ) for the first argument.
            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: true,
          clusterhub: true,
          database: true
          };
          return conf;
          }
          • explain
        • server.js

          [ practical source ]
          /***/
          var path = require('path');
          /* server configuration for project "libtech" */
          var excepts = ['libtech', 'cloudplus\\.me', 'szblog', 'initializr',
          'resizeWrapper', 'jqCanvo', 'jquery-pjax', 'EasySvg', 'HybridPrint',
          'FileTree', 'RGraph', 'unittests', '_trunk-synquery-base'];
          module.exports = serverConfig;
          function serverConfig() {
          var rootdir = path.resolve('..'), conf = {};
          var basic = {
          http: [httpSet(80, false, true), httpSet(443, true, false)],
          dbfs: '127.0.0.1:27017',
          options: {
          paths: {
          jQuery: path.resolve(rootdir, 'jQuery'),
          xjQuery: path.resolve(rootdir, 'xjQuery'),
          libs: 'node-jquery-libs',
          dbfs: 'node-gridfs',
          clst: 'node-cluster-session',
          mongodb: 'node-mongodb-native',
          websockets: 'node-websockets'
          }
          }
          };
          ['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) {
          if('cloudplus.me' == mtc[1]
          && /Mongo|ElasticCloudBuilder/.test(mtc[2]))
          return furl.replace(/^http:/, 'https:');
          }
          },
          },
          alias: {
          localhost: {
          regexp: /https?:\/\/(localhost|192.168.|10.1.2.|127.0.0.1)[^\/]*\//,
          replace: ['', '/libtech'],
          except: new RegExp('\\\/\\\/[^\\\/]+\\\/(' + excepts.join("|") + ')')
          },
          libtech: {
          regexp: /https?:\/\/liberty-technology\.biz\//,
          replace: ['', '/libtech'],
          except: new RegExp('\\\/\\\/[^\\\/]+\\\/(' + excepts.join("|") + ')')
          },
          cloudplus: {
          regexp: /https?:\/\/cloudplus\.me\//,
          replace: ['', '/cloudplus.me'],
          except: new RegExp('\\\/\\\/[^\\\/]+\\\/(' + excepts.join("|") + ')')
          },
          szblog: {
          regexp: /https?:\/\/singen-zaregoto\.com\//,
          replace: ['', '/szblog'],
          except: new RegExp('\\\/\\\/[^\\\/]+\\\/(' + excepts.join("|") + ')')
          },
          OurAlbum: {
          regexp: /https:\/\/ouralbum\.cloudplus\.me\//,
          replace: ['', '/cloudplus.me/OurAlbum'],
          except: new RegExp('\\\/\\\/[^\\\/]+\\\/(' + excepts.join("|") + ')')
          }
          },
          // TODO
          notfound: {
          allurl: {
          regexp: /https?:\/\/([^\/]+)\//,
          redirect: function(furl, mtc) {
          return 'http://' + mtc[1].replace('app', 'www') + '/NotFound/';
          }
          }
          },
          websocket: ws,
          fork: false
          };
          if(process.env.ISLOCAL)
          base.doc_root = rootdir, base.doc_sbin = rootdir;
          var path_to_ssl = null;
          if(ssl === true) {
          if(process.env.ISLOCAL) {
          path_to_ssl = function(type) {
          return path.resolve(__dirname, '..', '..', 'cloudplus.me', 'ssl')
          + '/RapidSSL2013.' + type;
          };
          base.ssl = {
          key: path_to_ssl('key'),
          ca: path_to_ssl('ca'),
          cert: path_to_ssl('cer')
          };
          } else {
          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