Giter VIP home page Giter VIP logo

working_hours's Introduction

WorkingHours

build

A modern ruby gem allowing to do time calculation with working hours.

Compatible and tested with:

  • Ruby 2.7, 3.0, 3.1, 3.2, 3.3, JRuby 9.4
  • ActiveSupport 5.x, 6.x, 7.x

Installation

Gemfile:

gem 'working_hours'

Usage

require 'working_hours'

# Move forward
1.working.day.from_now
2.working.hours.from_now
15.working.minutes.from_now

# Move backward
1.working.day.ago
2.working.hours.ago
15.working.minutes.ago

# Start from custom Date or Time
Date.new(2014, 12, 31) + 8.working.days # => Mon, 12 Jan 2015
Time.utc(2014, 8, 4, 8, 32) - 4.working.hours # => 2014-08-01 13:00:00

# Compute working days between two dates
friday = Date.new(2014, 10, 17)
monday = Date.new(2014, 10, 20)
friday.working_days_until(monday) # => 1
# Time is considered at end of day, so:
# - friday to saturday = 0 working days
# - sunday to monday = 1 working days

# Compute working duration (in seconds) between two times
from = Time.utc(2014, 8, 3, 8, 32) # sunday 8:32am
to = Time.utc(2014, 8, 4, 10, 32) # monday 10:32am
from.working_time_until(to) # => 5520 (1.hour + 32.minutes)

# Know if a day is worked
Date.new(2014, 12, 28).working_day? # => false

# Know if a time is worked
Time.utc(2014, 8, 4, 7, 16).in_working_hours? # => false

# Advance to next working time
WorkingHours.advance_to_working_time(Time.utc(2014, 8, 4, 7, 16)) # => Mon, 04 Aug 2014 09:00:00 UTC +00:00

# Advance to next closing time
WorkingHours.advance_to_closing_time(Time.utc(2014, 8, 4, 7, 16)) # => Mon, 04 Aug 2014 17:00:00 UTC +00:00
WorkingHours.advance_to_closing_time(Time.utc(2014, 8, 4, 10, 16)) # => Mon, 04 Aug 2014 17:00:00 UTC +00:00
WorkingHours.advance_to_closing_time(Time.utc(2014, 8, 4, 18, 16)) # => Tue, 05 Aug 2014 17:00:00 UTC +00:00

# Next working time
sunday = Time.utc(2014, 8, 3)
monday = WorkingHours.next_working_time(sunday) # => Mon, 04 Aug 2014 09:00:00 UTC +00:00
tuesday = WorkingHours.next_working_time(monday) # => Tue, 05 Aug 2014 09:00:00 UTC +00:00

# Return to previous working time
WorkingHours.return_to_working_time(Time.utc(2014, 8, 4, 7, 16)) # => Fri, 01 Aug 2014 17:00:00 UTC +00:00

Configuration

The working hours configuration is thread safe and consists of a hash defining working periods for each day, a time zone and a list of days off. You can set it once, for example in a initializer for rails:

# Configure working hours
WorkingHours::Config.working_hours = {
  :tue => {'09:00' => '12:00', '13:00' => '17:00'},
  :wed => {'09:00' => '12:00', '13:00' => '17:00'},
  :thu => {'09:00' => '12:00', '13:00' => '17:00'},
  :fri => {'09:00' => '12:00', '13:00' => '17:05:30'},
  :sat => {'19:00' => '24:00'}
}

# Configure timezone (uses activesupport, defaults to UTC)
WorkingHours::Config.time_zone = 'Paris'

# Configure holidays
WorkingHours::Config.holidays = [Date.new(2014, 12, 31)]

Or you can set it for the duration of a block with the with_config method, this is particularly useful with around_filter:

WorkingHours::Config.with_config(working_hours: {mon:{'09:00' => '18:00'}}, holidays: [], time_zone: 'Paris') do
  # Intense calculations
end

with_config uses keyword arguments, you can pass all or some of the supported arguments :

  • working_hours
  • holidays
  • time_zone

Holiday hours

Sometimes you need to configure different working hours as a one-off, e.g. the working day might end earlier on Christmas Eve.

You can configure this with the holiday_hours option, either as an override on the existing working hours, or as a set of hours that are being worked on a holiday day.

If any hours are set for a calendar day in holiday_hours, then the working_hours for that day will be ignored, and only the entries in holiday_hours taken into consideration.

# Configure holiday hours
WorkingHours::Config.holiday_hours = {Date.new(2020, 12, 24) => {'09:00' => '12:00', '13:00' => '15:00'}}

Handling errors

If the configuration is erroneous, an WorkingHours::InvalidConfiguration exception will be raised containing the appropriate error message.

You can also access the error code in case you want to implement custom behavior or changing one specific message, e.g:

rescue WorkingHours::InvalidConfiguration => e
  if e.error_code == :empty
    raise StandardError.new "Config is required"
  end
  raise e
end

No core extensions / monkey patching

Core extensions (monkey patching to add methods on Time, Date, Numbers, etc.) are handy but not appreciated by everyone. WorkingHours can also be used without any monkey patching:

require 'working_hours/module'

# Move forward
WorkingHours::Duration.new(1, :days).from_now
WorkingHours::Duration.new(2, :hours).from_now
WorkingHours::Duration.new(15, :minutes).from_now

# Move backward
WorkingHours::Duration.new(1, :days).ago
WorkingHours::Duration.new(2, :hours).ago
WorkingHours::Duration.new(15, :minutes).ago

# Start from custom Date or Time
WorkingHours::Duration.new(8, :days).since(Date.new(2014, 12, 31)) # => Mon, 12 Jan 2015
WorkingHours::Duration.new(4, :hours).until(Time.utc(2014, 8, 4, 8, 32)) # => 2014-08-01 13:00:00

# Compute working days between two dates
friday = Date.new(2014, 10, 17)
monday = Date.new(2014, 10, 20)
WorkingHours.working_days_between(friday, monday) # => 1
# Time is considered at end of day, so:
# - friday to saturday = 0 working days
# - sunday to monday = 1 working days

# Compute working duration (in seconds) between two times
from = Time.utc(2014, 8, 3, 8, 32) # sunday 8:32am
to = Time.utc(2014, 8, 4, 10, 32) # monday 10:32am
WorkingHours.working_time_between(from, to) # => 5520 (1.hour + 32.minutes)

# Know if a day is worked
WorkingHours.working_day?(Date.new(2014, 12, 28)) # => false

# Know if a time is worked
WorkingHours.in_working_hours?(Time.utc(2014, 8, 4, 7, 16)) # => false

Use in your class/module

If you want to use working hours only inside a specific class or module, you can include its computation methods like this:

require 'working_hours/module'

class Order
  include WorkingHours

  def shipping_date_estimate
    Duration.new(2, :days).since(payment_received_at)
  end

  def payment_delay
    working_days_between(created_at, payment_received_at)
  end
end

Timezones

This gem uses a simple but efficient approach in dealing with timezones. When you define your working hours you have to choose a timezone associated with it (in the config example, the working hours are in Paris time). Then, any time used in calculation will be converted to this timezone first, so you don't have to worry if your times are local or UTC as long as they are correct :)

Alternatives

There is a gem called business_time already available to do this kind of computation and it was of great help to us. But we decided to start another one because business_time is suffering from a few bugs and inconsistencies. It also lacks essential features to us (like working minutes computation).

Another gem called biz was released after working_hours to bring some alternative.

Contributing

  1. Fork it ( http://github.com/intrepidd/working_hours/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

working_hours's People

Contributors

aymebou avatar cedricbm avatar craiglittle avatar edwinwills avatar intrepidd avatar jarthod avatar mgka avatar raindog avatar seanhussey avatar stevschmid avatar watsonbox avatar wurde 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  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

working_hours's Issues

Inconsistency with business_time gem

I'm trying to migrate from business_time gem to working_hours gem, but testing gives inconsistent results between the 2 gems.

Time.utc(2014, 8, 4, 8, 32) + 4.working.hours
=> Mon, 04 Aug 2014 13:00:00.000000000 UTC +00:00
4.business_hours.after(Time.utc(2014, 8, 4, 8, 32))
=> 2014-08-04 12:32:00 UTC

Time.now + 20.working.hours
=> Thu, 25 Jan 2024 15:33:24.000000000 UTC +00:00
20.business_hours.after(Time.now)
=> 2024-01-24 07:33:13.448023076 +0000

Am I doing something wrong here?
Has anyone done such migration?

Since business_time https://github.com/bokmann/business_time was mentioned in the documentation, I assumed it would be a straight forward migration.
I'm kinda stuck, any help would be greatly appreciated.
Thanks

0.5sec precision issue caused by excessive rounding

Two times separated by 612ms, rounding the result means 1sec:

irb(main):290:0> from = Time.at(1611931545.518)
=> "2021-01-29T15:45:45.517+01:00"
irb(main):292:0> to = Time.at(1611931546.13)
=> "2021-01-29T15:45:46.130+01:00"
irb(main):293:0> (to - from)
=> 0.6120002269744873
irb(main):296:0> (to - from).round
=> 1

Despite rounding the result too, WH returns 0 here:

irb(main):295:0> WorkingHours.working_time_between(from, to)
=> 0

This is not good because it means during simple case (inside working day and that's it), the result does not correspond to the real value which is easy to compute and compare (even after rounding).

This is because during the process it first rounds up the from time in advance_to_working_time:

irb(main):281:0> from.iso8601(6)
=> "2021-01-29T15:45:45.518000+01:00"
irb(main):282:0> WorkingHours.advance_to_working_time(from).iso8601(6)
=> "2021-01-29T14:45:46.000000Z"

(The to is also rounded in in_config_zone(to, config: config).round)

I know we introduced some round as a workaround to the midnight hack (returning 999999 usec so it stays on the previous day) but we should try to round only at the end the computing to avoid loosing precision inside.

We shall try to reduce the number of intermediary round to fix this but be careful of side-effects (like a time being considered the previous days whereas with the round it was considered the next).

I may have a look a this later ;)
cc @Intrepidd

ruby 3 gives raises error wrong number of arguments (given 1, expected 0) on with_config

Getting an error when running on ruby 3 ...

ArgumentError: wrong number of arguments (given 1, expected 0)

def work_time(start_time, finish_time, units="hour")
  seconds = WorkingHours::Config.with_config(working_hours_config) do
    start_time.working_time_until(finish_time)
  end
end

See write-up on use of keyword arguments in ruby 3

I believe it just requires an additional double splat argument at the end of the method def ...

def with_config(working_hours: nil, holiday_hours: nil, holidays: nil, time_zone: nil, **)

Add block syntax for configuration

Let's allow something like this :

  WorkingHours.with_config(config) do 
    # Fun stuff
  end

Could be cool for rails, in an around filter for example. Or for use in middlewares.

This is more like a question for dynamic entering

Would it be possible for the days to be dynamic? I'm gonna make the admin the setter for the dates working hours and holidays. Here is a snippet of my code: inside config/initializers/working_hours.rb

`

Configure working hours

WorkingHours::Config.working_hours = {
sun: { '22:00' => '24:00', '00:00' => '06:00' },
mon: { '22:00' => '24:00', '00:00' => '06:00' },
tue: { '22:00' => '24:00', '00:00' => '06:00' },
wed: { '22:00' => '24:00', '00:00' => '06:00' },
thu: { '22:00' => '24:00', '00:00' => '06:00' },
fri: { '22:00' => '24:00', '00:00' => '06:00' },
sat: { '22:00' => '24:00', '00:00' => '06:00' }
}

Configure timezone (uses activesupport, defaults to UTC)

WorkingHours::Config.time_zone = 'Asia/Manila'

Configure holidays

arr_of_dates = []
holidates = [{ day: 10, month: 11, year: 2020 },
{ day: 24, month: 12, year: 2020 },
{ day: 25, month: 12, year: 2020 },
{ day: 30, month: 12, year: 2020 },
{ day: 31, month: 12, year: 2020 }]

holidates.each do |d|
arr_of_dates << Date.new(d[:year], d[:month], d[:day])
end

WorkingHours::Config.holidays = arr_of_dates
`

Thanks in advance

1.working.days.from_now if Date.current is holiday

if date.current is holiday or weekend (Date.current.working_day? returned false) then when calculating 1.working.days.from_now the calculation is still made from the current day.
For example:
puts DateTime.current

Tue, 14 Apr 2020 14:35:05

WorkingHours::Config.working_hours = { mon: { '09:00' => '18:00' }, tue: { '09:00' => '18:00' }, wed: { '09:00' => '18:00' }, thu: { '09:00' => '18:00' }, fri: { '09:00' => '18:00' } }
WorkingHours::Config.holidays = ["14 Apr 2020"]

puts 1.working.day.from_now

Tue, 15 Apr 2020 14:35:05

is this a bug? I believe that the calculation should start at 9:00 on the first business day and puts 1.working.day.from_now should returned Wen, 16 Apr 2020 09:00:00. if not then what is the difference between (1.working.days.from_now and 1.days.from_now)

Problems using with JRuby 1.7.15

Even using the 2.0 compat mode is giving me issues, which I've narrowed down to the use of Module#prepend in the lib/working_hours/core_ext files.

My question is if we changed

class ActiveSupport::TimeWithZone
  prepend WorkingHours::CoreExt::DateAndTime
end

to

class ActiveSupport::TimeWithZone
  include WorkingHours::CoreExt::DateAndTime
end

would that break anything?

server git:(master) ✗ export | grep JRUBY
JRUBY_OPTS=--2.0

server git:(master) ✗ ruby -v
jruby 1.7.15 (2.0.0p195) 2014-09-03 82b5cc3 on Java HotSpot(TM) 64-Bit Server VM 1.6.0_65-b14-462-11M4609 +jit [darwin-x86_64]

Add operators and methods on Time/Date and related classes

Could you please add support for this kind of syntax:

Date.new(1989, 12, 31) + 8.working.days
Time.new(1969, 8, 4, 8, 32) - 4.working.hours
time1.business_time_until(time2)
Date.new(1989, 12, 31).working_day?
Time.new(1969, 8, 4, 8, 32).in_working_hours?

We need a generic way to monkey patch time related classes, like ActiveSupport does.

How to do that specific day to change working hours when I calculate time ?

Hello,

First of all, thanks for this gem !! 👍

Here I created a plugin of redmine ( that I coding now ) where I need to calculate SLA of time response and I found this gem useful for me, but I have a situation here that I would like that a day working hour will be different Like a holiday I need to calculate spend time using diferente working hour. Let me show the code to clarify my need :

# Configure working hours for all normaly days
WorkingHours::Config.working_hours = {
  :mon => {'09:00' => '12:00', '13:00' => '18:00'},
  :tue => {'09:00' => '12:00', '13:00' => '17:00'},
  :wed => {'09:00' => '12:00', '13:00' => '17:00'},
  :thu => {'09:00' => '12:00', '13:00' => '17:00'},
  :fri => {'09:00' => '12:00', '13:00' => '17:05:30'},
  :sat => {'19:00' => '24:00'},
  #Here my suggest to I need - this data is monday but I would like to change working hours
  '2017-05-01' => {'10:00' => '12:00', '14:00' => '16:00'} 
}

# Configure timezone (uses activesupport, defaults to UTC)
WorkingHours::Config.time_zone = 'Paris'

# Configure holidays
WorkingHours::Config.holidays = [Date.new(2014, 12, 31)]

# here I can get hours of work considering a Day diferente of others days.. 

Is there a form to get this behavior with this gem ?

Do not set the configuration in Rails

Rails 4.1.5

# config/initializers/working_hours.rb
WorkingHours::Config.time_zone = 'St. Petersburg'
$ bin/rails c 
> WorkingHours::Config.time_zone
=> #<ActiveSupport::TimeZone:0x0000000692f5d0 @name="St. Petersburg", @utc_offset=nil, @tzinfo=#<TZInfo::TimezoneProxy: Europe/Moscow>, @current_period=#<TZInfo::TimezonePeriod: #<TZInfo::TimezoneTransitionDefinition: #<TZInfo::TimeOrDateTime: 1301180400>,#<TZInfo::TimezoneOffset: 14400,0,MSK>>,nil>>

But

$ bin/rails s

in action (I'm use binding.pry)

> WorkingHours::Config.time_zone
=> #<ActiveSupport::TimeZone:0x000000055e6ff0 @name="UTC", @utc_offset=nil, @tzinfo=#<TZInfo::TimezoneProxy: Etc/UTC>, @current_period=#<TZInfo::TimezonePeriod: nil,nil,#<TZInfo::TimezoneOffset: 0,0,UTC>>>>

Why?

Global configuration at startup not possible currently

Tried to create

 /config/initializers/working_hours.rb
module WorkingHours

  WorkingHours::Config.working_hours = {
    mon: {'10:00' => '19:00'},
    tue: {'10:00' => '19:00'},
    wed: {'10:00' => '19:00'},
    thu: {'10:00' => '19:00'},
    fri: {'10:00' => '19:00'},
    sat: {'10:00' => '14:00'}
   }

end

But, this approach to configure Working Hours doesn't works.
And I need to include this code in my ActiveRecord model, but I'm not sure that this is good idea.

Tell me please, how to make global Working Hours configuration in Rails?

Support for time shifts?

While working on #44 and seing our code changing times by adding seconds I thought: how does this work during time-shifts?

Short answer: it doesn't.

I didn't dig much into this as it's not a problem for the moment but I took the time to write some starting specs (to at least confirm that my changes were not breaking this):

describe WorkingHours::Computation do
  include WorkingHours::Computation

  describe '#advance_to_working_time' do
    it 'returns correct hour during positive time shifts' do
      WorkingHours::Config.working_hours = {sun: {'09:00' => '17:00'}}
      WorkingHours::Config.time_zone = 'Paris'
      from = Time.new(2020, 3, 29, 0, 0, 0)
      expect(from.zone).to eq("CET")
      res = advance_to_working_time(from)
      expect(res).to eq(Time.new(2020, 3, 29, 9, 0, 0))
      expect(res.zone).to eq("CEST")
    end

    it 'returns correct hour during negative time shifts' do
      WorkingHours::Config.working_hours = {sun: {'09:00' => '17:00'}}
      WorkingHours::Config.time_zone = 'Paris'
      from = Time.new(2020, 10, 25, 0, 0, 0)
      expect(from.zone).to eq("CEST")
      res = advance_to_working_time(from)
      expect(res).to eq(Time.new(2020, 10, 25, 9, 0, 0))
      expect(res.zone).to eq("CET")
    end
  end
end

The problem here is that if we use advance_to_working_time for example, with an opening hour at 9am, on the day of the timeshift, we'll end-up with either 10am or 8am... If somebody wants to write a PR for that feel free ;)

The inverse of Holidays

Let's say you configured that your work_hours that on sunday's you are always closed. It would be nice to to inform that an specific date, like november 9th from 09:00 to 12:00 it's an open period. Just like Holidays but "inverse".

Thread Safety

I know the docs say this gem is thread-safe, but I just want to make sure...

If I'm using working_hours in Sidekiq and I'm using different configs would it still be thread-safe?

I would expect to pass the config into functions, instead of maintaining state in an initializer... maybe that's what the block is for?

WorkingHours.return_to_working_time() doesn't pass `.in_working_hours?`

When one returns a time to working time, it would seem sensible that the time actually passes the .in_working_hours? test in all cases.

However, if the time passed to return_to_working_time was outside working hours to start with, then WorkingHours.return_to_working_time will return a time that does not pass the .in_working_hours? predicate (because it returns the exact closing time).

See for example:

2.2.2 :006 > Time.now.in_working_hours?
=> false
2.2.2 :007 > WorkingHours.return_to_working_time(Time.now).in_working_hours? 
=> false
2.2.2 :008 > (WorkingHours.return_to_working_time(Time.now) - 1.second).in_working_hours?
=> true

Keep getting NoMethodError for method ‘to_local’ when trying to call .in_working_hours?

I keep getting the following error when trying to use the in_working_hours function:

NoMethodError
  5260     undefined method `to_local' for #<TZInfo::TransitionsTimezonePeriod:0x00007fc81095f008>
  5260       /Users/xxx/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/activesupport-3.2.22.5/lib/active_support/time_with_zone.rb:52:in `time'
  5260       /Users/xxx/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/activesupport-3.2.22.5/lib/active_support/time_with_zone.rb:268:in `wday'
  5260       /Users/xxx/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/working_hours-1.2.0/lib/working_hours/computation.rb:147:in `working_day?'
  5260       /Users/xxx/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/working_hours-1.2.0/lib/working_hours/computation.rb:153:in `in_working_hours?'
  5260       /Users/xxx/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/working_hours-1.2.0/lib/working_hours/core_ext/date_and_time.rb:46:in `in_working_hours?'

Any ideas? I’ve tried to install/update activesupport with no result.

Find windows in working time...

I need to find contiguous time slots within working our over a period of time. I'm putting together a pull request for it, but wanted your opinion on the proposed syntax.

To find all the contiguous 2 hour slots from Time.utc(2014, 8, 4, 8, 30) until Time.utc(2014, 8, 11) I was thinking of this;

WorkingHours::Duration.new(2, :hours).between(Time.utc(2014, 8, 4, 8, 30), Time.utc(2014, 8, 11))

Returning an array. See any problems with this, or a preferred syntax?

about working day

hey there.
I am a chinese developer and our team are using your gem . thanks your guys make this!

and now we found a problem about working day. the config is only can set working day to holidays . but can not set holidays to working days. chinese holidays is really complicated. so can you guys can add this feature? thanks a lot!

Advancing out of Daylight Savings Time

On Sunday, November 1, 2015 at 2:00 a.m (Eastern Time) the US clocks jump out of Daylight Savings time.

Given this config

      WorkingHours::Config.time_zone = 'America/New_York'
      WorkingHours::Config.working_hours = {
        sat: {'02:00' => '17:00'},
        sun: {'02:00' => '17:00'},
        tue: {'02:00' => '17:00'}
      }

How would you expect

advance_to_working_time(Time.new(2015, 11, 1, 1, 59, 30, '-04:00'))

To behave? I would think that it should return;

Time.new(2015, 11, 1, 2, 0, 0, '-05:00')

As that is the new 02:00, 5 hours behind UTC. Currently we are getting;

Time.new(2015, 11, 1, 1, 0, 0, '-05:00')

Before doing anything about this I wanted to check if this is how you'd expect to handle 'Jump back' events?

I'd also make the same assumption about 'Spring forward'.

Go back to opening time

For example, on Monday at 10:00, the closest opening time is 9:00. Is there a quick way to go back to that opening time? If not, I could submit a PR (if that feature is relevant).

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.