GithubHelp home page GithubHelp logo

hapjs-platform / hap-toolkit Goto Github PK

View Code? Open in Web Editor NEW
35.0 2.0 21.0 5.38 MB

Quickapp command line tools to support project creation, compilation, debugging support, etc.

License: Apache License 2.0

JavaScript 99.64% CSS 0.14% HTML 0.17% Shell 0.01% Less 0.03% CoffeeScript 0.01% SCSS 0.02%

hap-toolkit's Introduction

开发指南

准备

必须需要使用 yarn 安装依赖

yarn install --registry https://registry.npmmirror.com/

cd examples/sample
yarn install --registry https://registry.npmmirror.com/

构建

基本

npm run build
# 推荐使用 npx (须在根目录执行)
npx gulp
# 查看所有任务
npx gulp --tasks

构建指定模块

# 构建全部
npx gulp # npm run build
npx gulp toolkit # npm run build -- toolkit
npx gulp toolkit packager # npm run build -- toolkit packager
npx gulp build # 不包含测试

开发和测试

以下满足大部分开发测试需求(希望),如果特殊需求,可自行修改 gulpfiles.

跳过minify

执行 gulpgulp {toolkit, debugger, packager, build} 这几个命令时,传入 --dev 将跳过 minify,方便开发时调试代码

watch 模式

监听文件,当文件修改时执行任务。

npx gulp watch                            # 监听全部
npx gulp watch --modules toolkit          # 监听 toolkit
npx gulp watch --modules toolkit,packager # 监听 toolkit 和 packager
npx gulp watch -m t,p                     # 同上
npm run dev                               # gulp watch --dev

单元测试

npx gulp test

项目测试/调试

npx gulp # 构建项目
node packages/hap-toolkit/bin/index.js init <testapp> # 创建一个测试项目
cd <testapp> # 进入测试项目
node ../bin/index.js server --watch # 启动服务
node inspect ../bin/index.js server --watch # 调试

项目测试

使用npm link 命令创建软链接。 假设有测试项目 testapp,则可以通过下面的方式 创建软链接。

cd <hap-toolkit-root>
[sudo] npm link
cd <path-to-testapp>
npm link hap-toolkit

cd <path-to-testapp>
npm link <hap-toolkit-root>

创建软链接后,hap-toolkit 中的修改都会映射到 testapp 项目下的hap-toolkit

jest-snapshot

测试使用了[jest snapshot],避免人工编写预期结果的繁琐。测试修改时,应认真对比 snapshot,确保它是正确的,还要记得提交snapshot

使用 -u 参数更新snapshot:

npx jest ./server/__tests__/server.js -u

代码检查

使用eslint做代码检查,基于standard 规则。配置了huskylint-staged,提交 代码时会自动做一次检查并尝试矫正(fix)

hap-toolkit's People

Contributors

barats avatar caojuan1997 avatar chenwei-oppo avatar chunge66 avatar jayfate avatar oppoquickapp avatar xingfujiang avatar zhangyingchun-oppo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

hap-toolkit's Issues

mi--aiot toolkit 的参数需要加上透传

辛苦

build参数如下

  .option('--enable-e2e', 'inject test-suite for current project')
  .option('--stats', 'analyse time and size of webpack output files')
  .option('--devtool <value>', 'source map config')
  .option('--disable-subpackages', 'disable subpackages')
  .option('--disable-stream-pack', 'disable stream pack')
  .option('--disable-sign', 'disable signature')
  .option('--disable-script-v8-v65', 'disable compile script match with v8 version 6.5')
  .option('--optimize-desc-meta', 'optimize desc meta')
  .option('--optimize-css-attr', 'optimize css attr')
  .option('--optimize-template-attr', 'optimize template attr')
  .option('--optimize-style-page-level', 'optimize style in page')
  .option('--optimize-style-app-level', 'optimize style in app ')
  .option('--enable-lazy-component', 'lazy load component')
  .option('--optimize-unused-resource', 'remove unused resource')
  .option('--include-dsl-from-lib', 'bundle dsl to rpk')
  .option('--include-static-resources', 'bundle static resources to rpk')
  .option('--match-sourcemap', 'match sourcemap')
  .option('--enable-extract-css', 'extract css to json')
  .option('--enable-custom-component', 'explort entrys by function')
  .option('--enable-jsc', 'bundle to jsc if the projectType is vela')
  .option('--enable-ops-wrap', 'inject performance log in code')
  .option('--disable-build-rpk', 'disable build rpk')
  .option(
    '--split-chunks-mode <value>',
    'extract js module to single files',
    validateSplitChunksMode
  )
  .option('--remove-ux-style', 'remove style object in js')
  .option('--enable-istanbul', 'enable coverage for ux/js files')
  .option('--enable-performance-check', 'inject performance log in code')
  .option(
    '--enable-diagnosis [value]',
    'proxy console object, send log to server, write into project/logs'
  )
  .option(
    '--build-name-format <build-name-format>',
    'custom output rpk file name',
    validateBuildNameFormat
  )
  .option('--enable-protobuf', 'use protobuf gen binary.bin file')

参数名列表

--enable-e2e
--stats
--devtool
--disable-subpackages
--disable-stream-pack
--disable-sign
--disable-script-v8-v65
--optimize-desc-meta
--optimize-css-attr
--optimize-template-attr
--optimize-style-page-level
--optimize-style-app-level
--enable-lazy-component
--optimize-unused-resource
--include-dsl-from-lib
--include-static-resources
--match-sourcemap
--enable-extract-css
--enable-custom-component
--enable-jsc
--enable-ops-wrap
--disable-build-rpk
--split-chunks-mode
--remove-ux-style
--enable-istanbul
--enable-performance-check
--enable-diagnosis
--build-name-format
--enable-protobuf

完整代码如下

#!/usr/bin/env node

/*
 * Copyright (C) 2017, hapjs.org. All rights reserved.
 */

const program = require('commander')
const chalk = require('chalk')
const semver = require('semver')
const { colorconsole } = require('@aiot-toolkit/shared-utils')
const { compileOptionsMeta } = require('@aiot-toolkit/shared-utils/compilation-config')

// 最低支持的node版本
const NODE_MINIMUM_VERSION = '10.13.0'

function checkVersion() {
  const currentVersion = process.versions.node

  // 若当前版本小于支持版本
  if (semver.lt(currentVersion, NODE_MINIMUM_VERSION)) {
    colorconsole.warn(
      `It is detected that the current NodeJS version is too low, please upgrade to NodeJS version higher than ${NODE_MINIMUM_VERSION}`
    )
  }
}

checkVersion()

program.version(require('../package').version, '-v, --version').usage('<command> [options]')

program
  .command('init <app-name>')
  .option('--dsl <name>', 'init project by specific dsl template, eg: vue')
  .option('--web', 'init project by specific web template')
  .option('--mina-h5', 'init project by specific mina-h5 template')
  .option('--mina-tv', 'init project by specific mina-tv template')
  .option(
    '-d --deviceType <deviceTypeList>',
    'init project by specific device separated with comma "," eg: tv,car,watch'
  )
  .option(
    '-t --templateType <templateType>',
    'init project by specific template eg: maml; you should use this with -d'
  )
  .description('create a new project.')
  .action((name, options) => {
    const generate = require('../lib/commands/init')
    generate(name, options)
  })

program
  .command('build')
  .description('build the project')
  .option('--enable-e2e', 'inject test-suite for current project')
  .option('--stats', 'analyse time and size of webpack output files')
  .option('--devtool <value>', 'source map config')
  .option('--disable-subpackages', 'disable subpackages')
  .option('--disable-stream-pack', 'disable stream pack')
  .option('--disable-sign', 'disable signature')
  .option('--disable-script-v8-v65', 'disable compile script match with v8 version 6.5')
  .option('--optimize-desc-meta', 'optimize desc meta')
  .option('--optimize-css-attr', 'optimize css attr')
  .option('--optimize-template-attr', 'optimize template attr')
  .option('--optimize-style-page-level', 'optimize style in page')
  .option('--optimize-style-app-level', 'optimize style in app ')
  .option('--enable-lazy-component', 'lazy load component')
  .option('--optimize-unused-resource', 'remove unused resource')
  .option('--include-dsl-from-lib', 'bundle dsl to rpk')
  .option('--include-static-resources', 'bundle static resources to rpk')
  .option('--match-sourcemap', 'match sourcemap')
  .option('--enable-extract-css', 'extract css to json')
  .option('--enable-custom-component', 'explort entrys by function')
  .option('--enable-jsc', 'bundle to jsc if the projectType is vela')
  .option('--enable-ops-wrap', 'inject performance log in code')
  .option('--disable-build-rpk', 'disable build rpk')
  .option(
    '--split-chunks-mode <value>',
    'extract js module to single files',
    validateSplitChunksMode
  )
  .option('--remove-ux-style', 'remove style object in js')
  .option('--enable-istanbul', 'enable coverage for ux/js files')
  .option('--enable-performance-check', 'inject performance log in code')
  .option(
    '--enable-diagnosis [value]',
    'proxy console object, send log to server, write into project/logs'
  )
  .option(
    '--build-name-format <build-name-format>',
    'custom output rpk file name',
    validateBuildNameFormat
  )
  .option('--enable-protobuf', 'use protobuf gen binary.bin file')
  .action(options => {
    // 必备参数:当开发者不传递该参数时,要解析为默认
    const signModeTmp = options.disableSign && compileOptionsMeta.signModeEnum.NULL
    options.signMode = validateSignMode(signModeTmp, compileOptionsMeta.signModeEnum.BUILD)

    const { compile } = require('../lib/commands/compile')
    compile('native', 'dev', false, options)
  })

program
  .command('debug', { noHelp: true })
  .description('debug the project')
  .option('--open-browser', 'open QR code page in default browser')
  .action(options => {
    const { launchServer } = require('@aiot-toolkit/server')
    const { openBrowser } = options
    launchServer({
      modules: ['debugger'],
      port: 8081,
      openBrowser
    })
  })

program
  .command('server')
  .description('open server for project')
  .option('--port <port>', 'specified port')
  .option('--enable-e2e', 'inject test-suite for current project')
  .option('--watch', 'recompile project while file changes')
  .option('--devtool <value>', 'source map config')
  .option('--clear-records', 'clear device records')
  .option('--disable-adb', 'disable adb debug')
  .option('--chrome-path <chrome-path>', 'support for a user specified chrome path')
  .option('--open-browser', 'open QR code page in default browser')
  .option('--open-nuttx', 'open Nuttx in default emulator')
  .option('--include-dsl-from-lib', 'bundle dsl to rpk')
  .option('--include-static-resources', 'bundle static resources to rpk')
  .option('--enable-performance-check', 'inject performance log in code')
  .option('--enable-custom-component', 'explort entrys by function')
  .option('--enable-jsc', 'bundle to jsc if the projectType is vela')
  .option('--enable-ops-wrap', 'inject performance log in code')
  .option('--disable-build-rpk', 'disable build rpk')
  .option('--enable-protobuf', 'use protobuf gen binary.bin file')
  .option(
    '--build-name-format <build-name-format>',
    'custom output rpk file name',
    validateBuildNameFormat
  )
  .option(
    '--split-chunks-mode <value>',
    'extract js module to single files',
    validateSplitChunksMode
  )
  .action(options => {
    const { launchServer } = require('@aiot-toolkit/server')
    const { compile } = require('../lib/commands/compile')
    const { port, watch, clearRecords, chromePath, disableAdb, openBrowser } = options
    launchServer({
      port,
      watch,
      clearRecords,
      chromePath,
      disableADB: disableAdb,
      openBrowser
    })
    if (options.watch) {
      compile('native', 'dev', true, options)
    }
  })

program
  .command('watch')
  .description('recompile project while file changes')
  .option('--enable-e2e', 'inject test-suite for current project')
  .option('--devtool <value>', 'source map config')
  .option('--disable-subpackages', 'disable subpackages')
  .option('--disable-stream-pack', 'disable stream pack')
  .option('--disable-script-v8-v65', 'disable compile script match with v8 version 6.5')
  .option('--include-dsl-from-lib', 'bundle dsl to rpk')
  .option('--include-static-resources', 'bundle static resources to rpk')
  .option('--match-sourcemap', 'match sourcemap')
  .option('--open-nuttx', 'open Nuttx in default emulator')
  .option('--enable-extract-css', 'extract css to json')
  .option(
    '--split-chunks-mode <value>',
    'extract js module to single files',
    validateSplitChunksMode
  )
  .option('--remove-ux-style', 'remove style object in js')
  .option('--enable-istanbul', 'enable coverage for ux/js files')
  .option('--enable-performance-check', 'inject performance log in code')
  .option(
    '--enable-diagnosis [value]',
    'proxy console object, send log to server, write into project/logs'
  )
  .option(
    '--build-name-format <build-name-format>',
    'custom output rpk file name',
    validateBuildNameFormat
  )
  .action(options => {
    const { compile } = require('../lib/commands/compile')
    compile('native', 'dev', true, options)
  })

program
  .command('release')
  .description('release the project')
  .option('--enable-e2e', 'inject test-suite for current project')
  .option('--stats', 'analyse time and size of webpack output files')
  .option('--devtool <value>', 'source map config')
  .option('--disable-subpackages', 'disable subpackages')
  .option('--disable-stream-pack', 'disable stream pack')
  .option('--disable-sign', 'disable signature')
  .option('--disable-script-v8-v65', 'disable compile script match with v8 version 6.5')
  .option('--optimize-desc-meta', 'optimize desc meta')
  .option('--optimize-css-attr', 'optimize css attr')
  .option('--optimize-template-attr', 'optimize template attr')
  .option('--optimize-style-page-level', 'optimize style in page')
  .option('--optimize-style-app-level', 'optimize style in app ')
  .option('--enable-lazy-component', 'lazy load component')
  .option('--optimize-unused-resource', 'remove unused resource')
  .option('--include-dsl-from-lib', 'bundle dsl to rpk')
  .option('--include-static-resources', 'bundle static resources to rpk')
  .option('--match-sourcemap', 'match sourcemap')
  .option('--enable-extract-css', 'extract css to json')
  .option('--enable-jsc', 'bundle to jsc if the projectType is vela')
  .option('--enable-ops-wrap', 'inject performance log in code')
  .option('--disable-build-rpk', 'disable build rpk')
  .option('--enable-protobuf', 'use protobuf gen binary.bin file')
  .option(
    '--split-chunks-mode <value>',
    'extract js module to single files',
    validateSplitChunksMode
  )
  .option('--remove-ux-style', 'remove style object in js')
  .option('--enable-istanbul', 'enable coverage for ux/js files')
  .option('--enable-performance-check', 'inject performance log in code')
  .option(
    '--enable-diagnosis [value]',
    'proxy console object, send log to server, write into project/logs'
  )
  .option(
    '--build-name-format <build-name-format>',
    'custom output rpk file name',
    validateBuildNameFormat
  )
  .option('--enable-custom-component', 'explort entrys by function')
  .action(options => {
    // 必备参数:当开发者不传递该参数时,要解析为默认
    const signModeTmp = options.disableSign && compileOptionsMeta.signModeEnum.NULL
    options.signMode = validateSignMode(signModeTmp, compileOptionsMeta.signModeEnum.RELEASE)

    const { compile } = require('../lib/commands/compile')
    compile('native', 'prod', false, options)
  })

program
  .command('preview <target>')
  .description('preview app in your browser')
  .option('--port <port>', 'specified port', 8989)
  .action((target, options) => {
    const preview = require('../lib/commands/preview')
    preview(target, options)
  })

program
  .command('postinstall', { noHelp: true })
  .description('Transpiling async/await for nodejs<7.6.x, deprecated.')
  .action(() => {
    colorconsole.warn('Deprecated command!')
  })

// TODO
// Since we properly have all dependencies included,
// and if we make {babel, eslint}-configuration built-in,
// we won't need this `update` command anymore.
program
  .command('update')
  .description('update tools for project')
  .option('--force', 'force update tools for project')
  .option('--update-deps', 'update dependencies directly', { noHelp: true })
  .action(options => {
    const update = require('../lib/commands/update')
    colorconsole.warn('aiot-toolkit>=0.1.0 No longer need to run this command\n')
    update(options)
  })

program
  .command('report', { noHelp: true })
  .description('collect system information and create report.log')
  .action(() => {
    const report = require('../lib/commands/report')
    report()
  })

program
  .command('view <rpk-path>')
  .description('run server to view rpk')
  .option('--port <port>', 'specified port', 8000)
  .option('--open-browser', 'open QR code page in default browser')
  .action((rpkPath, options) => {
    const { launchServer } = require('@aiot-toolkit/server')
    const { port, openBrowser } = options
    launchServer({
      port,
      openBrowser,
      rpkPath
    })
  })

program
  .command('resign')
  .description('resign the rpk/rpks packages')
  .option('--sign <dir>', 'folder where your signature stored', 'sign/release')
  .option('--file <rpk-path>', 'rpk that need to be re-signed')
  .option('--origin <dir>', 'folder where unsigned rpk(s) stored', 'dist')
  .option('--dest <dir>', 'folder where re-signed rpk(s) stored', 'dest')
  .action(options => {
    const { resign } = require('../lib/commands/resign')
    resign(options)
  })

program
  .command('packages')
  .description('generate the rpk packages')
  .option('--file <dir>', 'folder where need to generate rpk', 'build')
  .option('--output <dir>', 'folder where generate rpk stored', 'dist')
  .action(options => {
    const { packages } = require('../lib/commands/packages')
    packages(options)
  })

program
  .command('installdbg')
  .description('install "org.hapjs.debugger"')
  .option('-I, --ip <value>', 'connect remote devices, eg: 127.0.0.1')
  .option('-P, --platform <value>', 'quickapp debugger platform, default: phone')
  .option('-V, --apkVersion <value>', 'debugger version, default: v1080')
  .option('-F, --force-install', 'overwrite install original debugger')
  .action(async options => {
    const { installdbg } = require('../lib/commands/debug')
    try {
      const successMessage = await installdbg(options)
      colorconsole.info(successMessage)
    } catch (error) {
      colorconsole.error(error.message)
    }
  })

program
  .command('installmkp')
  .description('install "org.hapjs.mockup"')
  .option('-I, --ip <value>', 'connect remote devices, eg: 127.0.0.1')
  .option('-P, --platform <value>', 'quickapp engine platform, default: phone')
  .option('-V, --apkVersion <value>', 'quickapp engine version, default: v1080')
  .option('-F, --force-install', 'overwrite install quickapp engine')
  .action(async options => {
    const { installmkp } = require('../lib/commands/debug')
    try {
      const successMessage = await installmkp(options)
      colorconsole.info(successMessage)
    } catch (error) {
      colorconsole.error(error.message)
    }
  })

// 运行rpk在所有已连接的设备
program
  .command('runapp')
  .description('run app on multiple devices')
  .option('-D, --debugMode', 'open chrome devtools')
  .option('-C, --cardMode', 'open cardMode')
  .option('--watch', 'recompile project while file changes')
  .option('--include-static-resources', 'bundle static resources to rpk')
  .action(async options => {
    const { runapp } = require('../lib/commands/debug')
    try {
      await runapp(options)
    } catch (error) {
      colorconsole.error(error.message)
    }
  })

program
  .command('installrun')
  .description('install quickapp background and run')
  .option('-I --ip <value>', 'connect remote devices, eg: 127.0.0.1')
  .option('-P --platform <value>', 'quickapp platform, default: phone')
  .option('-V --apkVersion <value>', 'quickapp version, default: v1080')
  .option('-F, --force-install', 'overwrite install debugger and engine')
  .option('-D, --debugMode', 'open chrome devtools')
  .option('-C, --cardMode', 'open cardMode')
  .action(async options => {
    const { installAndRun } = require('../lib/commands/debug')
    try {
      await installAndRun(options)
    } catch (error) {
      colorconsole.error(error.message)
    }
  })

// 获取设备上支持运行快应用的引擎包名(数组形式),主要供IDE使用
program
  .command('getPlatforms')
  .option('-I --ip <value>', 'device ip,eg 127.0.0.1')
  .option('-P --port <value>', 'device port,eg 39517')
  .option('-S --sn <value>', 'device sn,eg 2a75794a')
  .description('get available platform(s) on selected device')
  .action(async options => {
    const { getAvailablePlatform } = require('../lib/commands/debug')
    getAvailablePlatform(options)
  })

// 获取所有连接上的设备列表(数组形式),主要供IDE使用
program
  .command('getConnectedDevices')
  .description('get all connected devices')
  .action(async options => {
    const { getAllConnectedDevices } = require('../lib/commands/debug')
    try {
      const connectedDevices = await getAllConnectedDevices(options)
      colorconsole.info(`The connected devices are: ${connectedDevices.join(', ')}`)
    } catch (error) {
      colorconsole.error(error.message)
    }
  })

program.on('--help', () => {
  console.log()
  console.log(`Run ${chalk.cyan(`aiot <command> --help`)} for detailed usage of given command.`)
  console.log()
})

// 更改 NodeJS 10.1.0 上的 "fs.promise is Experiment" 日志输出位置
require('fs-extra')
setTimeout(() => {
  program.parse(process.argv)

  if (!process.argv.slice(2).length) {
    program.outputHelp()
  }
}, 0)

function validateSignMode(value, defaultValue) {
  // 无值则为空串
  if ([null, undefined].includes(value)) {
    value = defaultValue
  }

  // 转成枚举常量比较
  value = value.toUpperCase()

  let ret = value

  if (!compileOptionsMeta.signModeEnum[value]) {
    ret = defaultValue
    colorconsole.warn(
      `The current signMode parameter does not support: ${value} , change to default:${ret}`
    )
  }
  return ret
}

/**
 * 校验SplitChunkMode参数的有效值
 * @param value {string}
 * @return {string}
 */
function validateSplitChunksMode(value) {
  // 转成枚举常量比较
  value = value.toUpperCase()

  let ret = value

  if (!compileOptionsMeta.splitChunksModeEnum[value]) {
    ret = compileOptionsMeta.splitChunksModeEnum.REDUNDANCY
    colorconsole.warn(
      `The current splitChunksMode parameter does not support: ${value} , change to default:${ret}`
    )
  }
  return ret
}

/**
 * 校验buildNameFormat参数的有效值
 * @param value {string}
 * @return {string}
 */
function validateBuildNameFormat(value) {
  // 转成枚举常量比较
  value = value.toUpperCase()

  let ret = value

  if (!compileOptionsMeta.buildNameFormat[value]) {
    ret = compileOptionsMeta.buildNameFormat.DEFAULT
    colorconsole.warn(
      `The current buildNameFormat parameter does not support: ${value} , change to default:${ret}`
    )
  }
  return ret
}

将loader的调用方式由inline改成配置形式

"../../packages/hap-dsl-xvm/lib/loaders/script-loader.js!../../packages/hap-packager/lib/loaders/module-loader.js!../../node_modules/babel-loader/lib/index.js?cwd=/Users/111111/Documents/hhhhh/hap-toolkit/examples/sample&cacheDirectory&plugins[]=/Users/111111/Documents/hhhhh/hap-toolkit/packages/hap-dsl-xvm/lib/loaders/babel-plugin-jsx.js&comments=false&configFile=/Users/111111/Documents/hhhhh/hap-toolkit/examples/sample/babel.config.js!../../packages/hap-dsl-xvm/lib/loaders/access-loader.js!../../packages/hap-dsl-xvm/lib/loaders/fragment-loader.js?index=0&type=script!./src/home/index.ux?uxType=page"

建议:把环境变量传入webpack配置

这个地方能不能把环境变量传进来,这个可以根据环境来设置不同的插件配置。

可以判断webpack是否是函数,如果是函数,执行之后再赋值

if (customConf.webpack) {
  if (typeof customConf.webpack === 'function') {
    customConf = customConf.webpack(defaultsOptions.nodeConf)
  } else {
    customConf = customConf.webpack
  }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.