Giter VIP home page Giter VIP logo

node-google-dfp's Introduction

Code Climate Test Coverage Build Status

Google DFP API Client for NodeJS

Basics

Initialize the DFP Instance.

var Dfp = require('node-google-dfp'),
    dfpUser = new Dfp.User(NETWORK_CODE, APP_NAME, VERSION);

Next, setup your client settings and your user's OAUTH token information.

dfpUser.setSettings({
  client_id : "YOUR CLIENT ID",
  client_secret : "YOUR CLIENT SECRET",
  refresh_token : "A REFRESH TOKEN",
  redirect_url : "YOUR OAUTH REDIRECT URL"
});

You can instance any of DFP's API Services; https://developers.google.com/doubleclick-publishers/docs/start

dfpUser.getService('LineItemService', function (err, lineItemService) {
  if (err) {
    return console.error(err);
  }

  var statement = new DfpClass.Statement('WHERE id = 103207340');

  lineItemService.getLineItemsByStatement(statement, function (err, results) {
    console.log(results);
  });

});

Service accounts example

If you would like to use a Google Service Account to access DFP, you can do so by creating an instance of the JWT auth client.

var {JWT} = require('google-auth-library')

var jwtClient = new JWT(
  SERVICE_ACCOUNT_EMAIL,
  'path/to/key.pem',
  null,
  ['https://www.googleapis.com/auth/dfp']);

dfpUser.setClient(jwtClient)

=======

oAuth setup

This application requires a working oAuth refresh token to make requests. If you don't include a refresh token you will get an "No refresh token is set" error. If you include a bad token, you'll get an "illegal access" error. Service accounts are not supported.

To setup a refresh token manually, follow Google's instructions for using cURL. The main steps are included below.

  • Setup a oAuth "installed application" in the Google Developer Console.

  • Create a verification request using this installed application's client ID. (If you miss this step you'll get an authorization_pending error from Google on the next step.) Note that any slashes in a device_code will need to be escaped.

curl -d "client_id={YOUR_OAUTH_CLIENT_ID}&scope=https://www.googleapis.com/auth/dfp" https://accounts.google.com/o/oauth2/device/code

{
  "device_code" : "ABCD-EFGH4/MEiMYvOO1THXLV_fHGGN8obAgb5XFs1Uctj-QsyYsQk",
  "user_code" : "ABCD-EFGH",
  "verification_url" : "https://www.google.com/device",
  "expires_in" : 1800,
  "interval" : 5
}
  • Visit the verification_url contained in the verification request response (e.g. https://www.google.com/device) in a browser and type in the user_code provided in the verification response. A verification code will be given as a response.

  • Use the provided code and your client ID and secret from the Google oAuth application to create a refresh token.

curl -d "client_id={YOUR_OAUTH_CLIENT_ID}&client_secret={YOUR_OAUTH_CLIENT_SECRET}&code={YOUR_VERIFICATION_CODE}&grant_type=http://oauth.net/grant_type/device/1.0" https://accounts.google.com/o/oauth2/token

{
  "access_token" : "ya29.JAHynQpVpjBFhvg-7VKdQ7nmD0DkmCYoWTWo535TP8QsKa6j2rFOI1i0pdclFepv_GZo9A2SrN41dA",
  "token_type" : "Bearer",
  "expires_in" : 3600,
  "id_token" : "eyJhbGciOiJSUzI1NiIsImtpZCI6IjdjZmM3YTJhMDkwYWJjOGYxMDU5MjJmMzFiN2FjZGUzYzA2NmU1NTYifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiaWQiOiIxMTU2MjQxNzA0MjQ3NzA5NDYzNzgiLCJzdWIiOiIxMTU2MjQxNzA0MjQ3NzA5NDYzNzgiLCJhenAiOiI4MzQ3MDQ2OTI1ODItMzlwY3I2M2RmNjBlZjByY2E5ZTc1cDRicTlzbjhxOWUuYXBwcy5nb29nbyV1c2VyY29udGVudC5jb20iLCJlbWFpbCI6InRheWxvci5idWxleUBtY25hdWdodG9uLm1lZGlhIiwiYXRfaGFzaCI6Ikp2Sl9JUDlxUk9zX1JUNDBoY0FSWVEiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXVkIjoiODM0NzA0HjkyNTgyLTM5cGNyNjNkZjYwZWYwcmNhOWU3NXA0YnE5c244cTllLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiaGQiOiJtY25hdWdodG9uLm1lZGlhIiwidG9rZW5faGFzaCI6Ikp2Sl9JSDlxUk9zX1JUNDBoY0FSWVEiLCJ2ZXJpZmllZF9lbWFpbCI6dHJ1ZSwiY2lkIjoiODM0NzA0NjkyNTgyLTM5cGNyNjNkZjYwZWYwcmNhOWU3NXA0YnE5c244cTllLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiaWF0IjoxNDI0ODAwNDcwLCJleHAiOjE0MjQ4MDQzNzB9.T9mTcSl5bJLKrFhldXOd1L1CnGFfZHNF1eQOmJYyp7wR3vKbz8ATTNAfyo8_2hSGt9kGrHDBcdgaq_18RYS72Tt0MclNy020romjl6rYRjs6GH93S3ZMiwra3UI3kmDXym9kyntedMS5gIPgJWfcoh0J0CTDNPBisLNrZntJv7Y",
  "refresh_token" : "1/CGpCHgTgJ28PMnh84PgQBOgHHHaLCDbDQ_0ZiINmO_g"
}

You can use urn:ietf:wg:oauth:2.0:oob for the redirect URL of non-public apps.

Known Issues

  1. OAuth Support for more than just Refresh Token
  2. No unit tests

How to contribute

Follow Github's recommended workflow for contributing to this project.

  1. Fork it
  2. Create your feature branch (git checkout -b your-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin your-new-feature)
  5. Create new Pull Request

node-google-dfp's People

Contributors

ahaurw01 avatar ajsouza avatar boudlal avatar buley avatar combs avatar grevory avatar j0k3r avatar jnikles avatar justinrainbow avatar kevinkhuat avatar mvhirsch avatar ora-tv-dev avatar serratedserenade avatar xiaolinforce avatar zagraves 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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

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

node-google-dfp's Issues

Soap Logs

is there a way to get access to the soap logs somehow?

could you push to merge into `google/google-api-nodejs-client`

we want to write dfp applications in nodejs but they have limited client libraries support officially [1], only java, php, python, ruby not what we want;

this project looks good, but with 3rd party implementation my only concern is future maintainability, what if they break something and how soon can this library fix up? what if this library author becomes inactive and out of maintenance ? as I think, to provide more choices for developers for dfp should be google's responsibility, although the official Google DFP [2] is not doing, but there is [1] google api nodejs client can be seen as part of semi-official , could you try to push / merge into the project?

  1. https://github.com/google/google-api-nodejs-client
  2. https://developers.google.com/doubleclick-publishers/docs/clients

Extending the Date object

This is a very handy library. Thanks! One thing though: you really shouldn't extend the prototype of a native object.

Improve docs

Hi guys,

Can you guys give a full doc on how to save and stuff.

SOAP error only during reportService.getReportJobStatus

I get this error when running reportService.getReportJobStatus()

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><soap:Fault><faultcode>soap:Server</faultcode><faultstring>No binding operation info while invoking unknown method with params unknown.</faultstring></soap:Fault></soap:Body></soap:Envelope>

This error seems to be unique to getReportJobStatus() and doesn't occur when calling other reportService functions.

Any ideas? Thanks.

Vulnerabilities in dependency versions

┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Regular Expression Denial of Service                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ debug                                                        │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ >= 2.6.9 < 3.0.0 || >= 3.1.0                                 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ node-google-dfp                                              │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ node-google-dfp > soap > debug                               │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/534                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Prototype Pollution                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ lodash                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ >=4.17.5                                                     │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ node-google-dfp                                              │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ node-google-dfp > soap > lodash                              │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/577                       │
└───────────────┴──────────────────────────────────────────────────────────────┘

Code:502 error

Hello world!
First of all thanks to anyone involved for this.. It's an excellent tool that has helped me greatly.
Over the last couple of weeks I get an error with code 502, every now and then and need to restart my application. Has anyone noticed anything similar or knows of any workarounds?

Thanks again,
Stavros

DfpUser#getService callback does not follow errback style

There doesn't appear to be any way to catch errors originating from service lookups. The callback to DfpUser.prototype.getService is invoked only with the service after the lookup is successful. It does not follow the typical node "errback" style used elsewhere in the library.

Errors are thrown at https://github.com/ShinyAds/node-google-dfp/blob/master/lib/DfpUser.js#L60 and https://github.com/ShinyAds/node-google-dfp/blob/master/lib/DfpUser.js#L66. As far as I can tell, there is no way to catch these errors?

Release Version v0.2.3

Hi,

is there any chance to get the last (appr.) 20 commits into a new release?

Cheers,
Michael

Error undefined:undefined (update soap)

I've previously gotten an error with the status code undefined:undefined. This is a problem inside node-soap and they've addressed it in this commit, which we should get by updating to v0.11.0.

I'm not sure if updating will have any breaking changes, but I can research, try it out, and then submit a PR.

Problem using forecastService

Hi, I've problems using node-google-dfp. When I use service like InventoryService, all works well. But, I'm trying to use ForecastService (getAvailabilityForecast) that needs 2 params btw and doesn't work.
Here is some code:

const Dfp = require('node-google-dfp');
const dfpUser = new Dfp.User(MY_NETWORK_CODE, 'test pub', 'v201708');
const google = require('googleapis')
const ADVERTISER_ID = 'MY_ADVERTISER_ID'

const jwtClient = new google.auth.JWT(
    'MY_EMAIL',
    './cred.pem',
    null,
    ['https://www.googleapis.com/auth/dfp']);
dfpUser.setClient(jwtClient)

const endDatetime = moment().add(30, 'days').toISOString()

console.log('end_datetime ->', endDatetime)

const    lineItem = {
  targeting: {
    inventoryTargeting: {
      targetedAdUnits: [
        {
          adUnitId: 'MY_ADD_UNIT_ID',
          includeDescendants: true,
        }
      ]
    },
    geoTargeting: {
      targetedLocations: [
        {
          id: '9068897'
        }
      ]
    },
  },
  lineItemType: 'SPONSORSHIP',
  startDateTimeType: 'IMMEDIATELY',
  endDateTime: endDatetime,
  costType: 'CPM',
  primaryGoal: {
    units: '50',
    unitType: 'IMPRESSIONS',
    goalType: 'DAILY'
  },
  contractedUnitsBought: '100',
  creativeRotationType: 'EVEN'
}

const prospectiveLineItem = {
  'lineItem': lineItem,
  'advertiserId': ADVERTISER_ID
}

const    forecastOptions = {
  includeContendingLineItems: true,
  includeTargetingCriteriaBreakdown: true
}

dfpUser.getService('ForecastService', (err, service) => {
  console.log('service ->', service)
  /* LOG:
    service -> { getAvailabilityForecast: [Function],
    getAvailabilityForecastById: [Function],
    getDeliveryForecast: [Function],
    getDeliveryForecastByIds: [Function] }
  */
  service.getAvailabilityForecast({lineItem: prospectiveLineItem, forecastOptions: forecastOptions}, (err, result) => {
    console.log('err ->', err)
    // console.log('result ->', result)
  })
})

Here is my err output:

body: '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">soap:Bodysoap:Faultsoap:ClientUnmarshalling Error: cvc-complex-type.2.4.d: Invalid content was found starting with element 'geoTargeting'. No child element is expected at this point. </soap:Fault></soap:Body></soap:Envelope>' }

I don't understand this error since inventoryTargeting can have geoTargeting parameter. Do you have any idea why this call return this error ?
Thanks !! :)

rounding / float problems using Dfp.Money

we price things in cents, and so to use Dfp.Money, we need to divide by 100. On some values, the JS floats represents it in a value that's illegal to DFP. Like 250 became 2.49999999999, which became microAmount: 2499999.999. So it would be nice if Dfp.Money used Math.round.

Create Client Error

I'm receiving the following error:

Create Client Error Error: Invalid WSDL URL: https://ads.google.com/apis/ads/publisher/1/InventoryService?wsdl

I'm passing in all the required parameters for dfp.setSettings(). The issue occurs when I try to call a service, which in this case is

        dfpUser.getService('InventoryService', function (inventoryService) {

The following errors I receive are

Code: 404
Response Body: <html><body>No service was found.</body></html>

and

Error: Unable to get token

I believe I'm setting up my configurations correctly thought? Any help would be much appreciated.

makeTestNetwork

I want to create a blank network for testing purposes does anybody have any experiences doing this with this library?

cannot assign to readonly property targetNSAlias on node v0.12

After upgrading to node v0.12, I am getting an error. After som research I believe this is due to the version of node-soap being use. I noticed that the package.json for this module reqquires soap 0.5, wheras the latest versionis 0.9.3 and looking through the oull request/issue history on the soap module I see that a fix for this issue was submitted and merged some time ago. I think an update to this modules dependencies is needed, I have tried just a straight upgrade on a fork but I then get some soap errors. I was wondering if you could give me some pointers on fixing this or perhaps have a look yourself?

The error on node v0.12 using soap v0.5 is below:

Cannot assign to read only property 'targetNSAlias' of TeamAccessType|xsd:string|NONE,READ_ONLY,READ_WRITE date=Tue Jul 07 2015 10:59:45 GMT+0100 (BST), pid=39975, uid=501, gid=20, cwd=/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api, execPath=/usr/local/Cellar/node/0.12.0_1/bin/node, version=v0.12.0, argv=[node, /usr/local/bin/sails, lift], rss=183975936, heapTotal=153554176, heapUsed=116197872, loadavg=[2.75537109375, 2.11328125, 1.96044921875], uptime=700397, trace=[column=28, file=/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js, function=ElementElement.description, line=819, method=description, native=false, column=29, file=/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js, function=AllElement.description.SequenceElement.description [as description], line=858, method=description.SequenceElement.description [as description], native=false, column=20, file=/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js, function=ComplexTypeElement.description, line=765, method=description, native=false, column=46, file=/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js, function=ElementElement.description, line=817, method=description, native=false, column=29, file=/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js, function=AllElement.description.SequenceElement.description [as description], line=858, method=description.SequenceElement.description [as description], native=false, column=20, file=/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js, function=ComplexTypeElement.description, line=765, method=description, native=false, column=31, file=/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js, function=ElementElement.description, line=843, method=description, native=false, column=33, file=/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js, function=MessageElement.postProcess, line=500, method=postProcess, native=false, column=13, file=/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js, function=OperationElement.postProcess, line=602, method=postProcess, native=false, column=11, file=/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js, function=PortTypeElement.postProcess, line=622, method=postProcess, native=false, column=14, file=/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js, function=BindingElement.postProcess, line=636, method=postProcess, native=false, column=15, file=/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js, function=ServiceElement.postProcess, line=671, method=postProcess, native=false, column=26, file=/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js, function=null, line=971, method=null, native=false, column=12, file=/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js, function=WSDL._processNextInclude, line=1022, method=_processNextInclude, native=false, column=8, file=/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js, function=WSDL.processIncludes, line=1052, method=processIncludes, native=false, column=10, file=/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js, function=null, line=961, method=null, native=false], stack=[TypeError: Cannot assign to read only property 'targetNSAlias' of TeamAccessType|xsd:string|NONE,READ_ONLY,READ_WRITE, at ElementElement.description (/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js:819:28), at AllElement.description.SequenceElement.description as description, at ComplexTypeElement.description (/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js:765:20), at ElementElement.description (/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js:817:46), at AllElement.description.SequenceElement.description as description, at ComplexTypeElement.description (/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js:765:20), at ElementElement.description (/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js:843:31), at MessageElement.postProcess (/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js:500:33), at OperationElement.postProcess (/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js:602:13), at PortTypeElement.postProcess (/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js:622:11), at BindingElement.postProcess (/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js:636:14), at ServiceElement.postProcess (/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js:671:15), at /Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js:971:26, at WSDL._processNextInclude (/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js:1022:12), at WSDL.processIncludes (/Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js:1052:8), at /Users/Sam/Documents/Work/salesknowledge/sales-knowledge-api/node_modules/node-google-dfp/node_modules/soap/lib/wsdl.js:961:10]

Thanks

reuse access token to avoid some unnecessary round trips to google site

I have played with this library a few days it's working nicely while I noticed when my application need to talk to google for longer tasks, some part of this code is not caching and retrieving some resource again and again, for example google's oauth token has one hour validity by default, so within the hour we can reuse it, only need to refresh it until it's almost expiring,
I'm doing some code changes locally to cache and it works better, can make a PR if it's welcome.

btw, google's library says refreshAccessToken is deprecated [2], I have switched to use getRequestMetadata; that is less code because google-auth-library handles token expiry and refresh itself pretty well

  1. https://github.com/ShinyAds/node-google-dfp/blob/master/lib/DfpUser.js#L120
  2. https://github.com/google/google-auth-library-nodejs/blob/master/lib/auth/oauth2client.js#L189-L195

CustomTargetingService performCustomTargetingValueAction

I'm trying to use this action, but I can't find a way to handle the abstract customTargetingValueAction.
There I must set the xsi:type to DeleteCustomTargetingValues somehow.
Can someone help me with this or is it not possible to handle abstract elements?

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.