Code Monkey home page Code Monkey logo

cocoamarkdown's Introduction

CocoaMarkdown

Markdown parsing and rendering for iOS and macOS

CocoaMarkdown is a cross-platform framework for parsing and rendering Markdown, built on top of the C reference implementation of CommonMark.

Why?

CocoaMarkdown aims to solve two primary problems better than existing libraries:

  1. More flexibility. CocoaMarkdown allows you to define custom parsing hooks or even traverse the Markdown AST using the low-level API.
  2. Efficient NSAttributedString creation for easy rendering on iOS and macOS. Most existing libraries just generate HTML from the Markdown, which is not a convenient representation to work with in native apps.

Example app macOS

Example app iOS

Installation

First you will want to add this project as a submodule to your project:

git submodule add https://github.com/indragiek/CocoaMarkdown.git

Then, you need to pull down all of its dependencies.

cd CocoaMarkdown
git submodule update --init --recursive

Next, drag the .xcodeproj file from within CocoaMarkdown into your project. After that, click on the General tab of your target. Select the plus button under "Embedded Binaries" and select the CocoaMarkdown.framework.

API

Traversing the Markdown AST

CMNode and CMIterator wrap CommonMark's C types with an object-oriented interface for traversal of the Markdown AST.

let document = CMDocument(contentsOfFile: path, options: [])
document.rootNode.iterator().enumerateUsingBlock { (node, _, _) in
    print("String value: \(node.stringValue)")
}

Building Custom Renderers

The CMParser class isn't really a parser (it just traverses the AST), but it defines an NSXMLParser-style delegate API that provides handy callbacks for building your own renderers:

@protocol CMParserDelegate <NSObject>
@optional
- (void)parserDidStartDocument:(CMParser *)parser;
- (void)parserDidEndDocument:(CMParser *)parser;
...
- (void)parser:(CMParser *)parser foundText:(NSString *)text;
- (void)parserFoundHRule:(CMParser *)parser;
...
@end

CMAttributedStringRenderer is an example of a custom renderer that is built using this API.

Rendering Attributed Strings

CMAttributedStringRenderer is the high level API that will be useful to most apps. It creates an NSAttributedString directly from Markdown, skipping the step of converting it to HTML altogether.

Going from a Markdown document to rendering it on screen is as easy as:

let document = CMDocument(contentsOfFile: path, options: [])
let renderer = CMAttributedStringRenderer(document: document, attributes: CMTextAttributes())
textView.attributedText = renderer.render()

Or, using the convenience method on CMDocument:

textView.attributedText = CMDocument(contentsOfFile: path, options: []).attributedStringWithAttributes(CMTextAttributes())

HTML elements can be supported by implementing CMHTMLElementTransformer. The framework includes several transformers for commonly used tags:

Transformers can be registered with the renderer to use them:

let document = CMDocument(contentsOfFile: path, options: [])
let renderer = CMAttributedStringRenderer(document: document, attributes: CMTextAttributes())
renderer.registerHTMLElementTransformer(CMHTMLStrikethroughTransformer())
renderer.registerHTMLElementTransformer(CMHTMLSuperscriptTransformer())
textView.attributedText = renderer.render()

Customizing Attributed strings rendering

All attributes used to style the text are customizable using the CMTextAttributes class.

Every Markdown element type can be customized using the corresponding CMStyleAttributes property in CMTextAttributes, defining 3 different kinds of attributes:

  • String attributes, i.e. regular NSAttributedString attributes
  • Font attributes, for easy font setting
  • Paragraph attributes, relevant only for block elements

Attributes for any Markdown element kind can be directly set:

let textAttributes = CMTextAttributes()
textAttributes.linkAttributes.stringAttributes[NSAttributedString.Key.backgroundColor] = UIColor.yellow

A probably better alternative for style customization is to use grouped attributes setting methods available in CMTextAttributes:

let textAttributes = CMTextAttributes()

// Set the text color for all headers
textAttributes.addStringAttributes([ .foregroundColor: UIColor(red: 0.0, green: 0.446, blue: 0.657, alpha: 1.0)], 
                                   forElementWithKinds: .anyHeader)

// Set a specific font + font-traits for all headers
let boldItalicTrait: UIFontDescriptor.SymbolicTraits = [.traitBold, .traitItalic]
textAttributes.addFontAttributes([ .family: "Avenir Next" ,
                                   .traits: [ UIFontDescriptor.TraitKey.symbolic: boldItalicTrait.rawValue]], 
                                 forElementWithKinds: .anyHeader)
// Set specific font traits for header1 and header2
textAttributes.setFontTraits([.weight: UIFont.Weight.heavy], 
                             forElementWithKinds: [.header1, .header2])

// Center block-quote paragraphs        
textAttributes.addParagraphStyleAttributes([ .alignment: NSTextAlignment.center.rawValue], 
                                           forElementWithKinds: .blockQuote)

// Set a background color for code elements        
textAttributes.addStringAttributes([ .backgroundColor: UIColor(white: 0.9, alpha: 0.5)], 
                                   forElementWithKinds: [.inlineCode, .codeBlock])

List styles can be customized using dedicated paragraph style attributes:

// Customize the list bullets
textAttributes.addParagraphStyleAttributes([ .listItemBulletString: "๐Ÿ" ], 
                                           forElementWithKinds: .unorderedList)
textAttributes.addParagraphStyleAttributes([ .listItemBulletString: "๐ŸŒผ" ], 
                                           forElementWithKinds: .unorderedSublist)

// Customize numbered list item labels format and distance between label and paragraph
textAttributes.addParagraphStyleAttributes([ .listItemNumberFormat: "(%02ld)", 
                                             .listItemLabelIndent: 30 ],    
                                           forElementWithKinds: .orderedList)

Font and paragraph attributes are incremental, meaning that they allow to modify only specific aspects of the default rendering styles.

Additionally on iOS, Markdown elements styled using the font attributes API get automatic Dynamic-Type compliance in the generated attributed string, just like default rendering styles.

Rendering HTML

CMHTMLRenderer provides the ability to render HTML from Markdown:

let document = CMDocument(contentsOfFile: path, options: [])
let renderer = CMHTMLRenderer(document: document)
let HTML = renderer.render()

Or, using the convenience method on CMDocument:

let HTML = CMDocument(contentsOfFile: path).HTMLString()

Example Apps

The project includes example apps for iOS and macOS to demonstrate rendering attributed strings.

Contact

License

CocoaMarkdown is licensed under the MIT License. See LICENSE for more information.

cocoamarkdown's People

Contributors

frugghi avatar iby avatar indragiek avatar jlj avatar mjstallard avatar nuudles avatar rickharrison avatar timnn avatar vdugnist 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cocoamarkdown's Issues

Superscript Support in Markdown

Heya! Thanks for the wonderful parser, it's by far the best one I've used yet.

The only markdown elements which seem to be unparsable using CocoaMarkdown (besides tables, which would be pretty impossible to render without ASCII art anyway) are superscript.

Although I see that superscript HTML characters can be transformed into attributes using the CMHTMLSuperscriptTransformer class, there is no equivalent convenience for markdown. In fact, after running through the codebase for a while, it only makes sense to modify cmark itself to add this parsing ability... it's not a part of the delegate pattern or customization of CocoaMarkdown to add different markdown parsing tokens. This makes sense, but means that adding my necessary features to the markdown capability of CocoaMarkdown requires modifying an underlying library/framework (which ideally would be separable/detachable and not dependent; because CocoaMarkdown is already an extension on cmark, making an extension on the cmark that CocoaMarkdown uses would be inappropriate to upkeep (a fork inside a fork?!)).

Instead of diving that deep and modifying the C/C++ base itself, I wanted to create this issue so we could perhaps find a solution that involves CocoaMarkdown itself and extends the modular nature of the library (so perhaps other tokens can be added in the future, too). Although the delegate pattern is very convenient and useful, it does not seem appropriate for modifying parsing, only the attributes/effects of the parse-in-progress. Hope this is a reasonable request, cheers!

Failed to generate the attributed string for given text "<Test>"

Below is the code to generate an AttributedString in iOS

NSString * markdown = @""
CMDocument *doc = [[CMDocument alloc] initWithData: [markdown dataUsingEncoding: NSUTF8StringEncoding] options: 0];
CMTextAttributes *markdownAttributes = [[CMTextAttributes alloc]init];
CMAttributedStringRenderer *renderer = [[CMAttributedStringRenderer alloc] initWithDocument: doc attributes: markdownAttributes];
return [render render];

Links are white

let attributes = CMTextAttributes()
attributes.linkAttributes = [
NSForegroundColorAttributeName: UIColor.redColor()
]

Will render white links if the window.tintColor property is set...

Aside from that the code above actually doesn't work at all. Starting to think the external tints colors are causing this issue?

Any solid explanation why?

cache image

Did the author consider caching the image locally

CMHTMLStrikethroughTransformer init should use the current color by default

When initialising a CMHTMLStrikethroughTransformer with the convenience init constructor, I think it'd be better to pass nil(instead of black) as default color. This way, the line would get the same color (e.g. red) as the text it's striking through.

I can fork / pull request for that if you want.

Sample apps not working after #49 merge

Thanks for merging #49. However I went to try out the example app on both mac and iOS and it fails. In either case I get an exception... on iOS this crashes the app and on Mac it just fails to render anything.

The exception happens in CMAttributedStringRenderer:appendString because string parm is nil. This seems to go deep into the parsing logic which I didn't fully debug into yet.

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'NSConcreteAttributedString initWithString:: nil value'
*** First throw call stack:
(
0 CoreFoundation 0x00000001116f98db __exceptionPreprocess + 331
1 libobjc.A.dylib 0x00000001104e3ac5 objc_exception_throw + 48
2 CoreFoundation 0x00000001116f9735 +[NSException raise:format:] + 197
3 Foundation 0x000000010fb538f6 -[NSConcreteAttributedString initWithString:] + 135
4 Foundation 0x000000010fb539e9 -[NSConcreteAttributedString initWithString:attributes:] + 27
5 CocoaMarkdown 0x000000010f9669f8 -[CMAttributedStringRenderer appendString:] + 152
6 CocoaMarkdown 0x000000010f963a5b -[CMAttributedStringRenderer parser:foundText:] + 315
7 CocoaMarkdown 0x000000010f94a9ca -[CMParser handleNode:event:] + 778
8 CocoaMarkdown 0x000000010f94a567 __17-[CMParser parse]_block_invoke + 151
9 CocoaMarkdown 0x000000010f949eb7 -[CMIterator enumerateUsingBlock:] + 487
10 CocoaMarkdown 0x000000010f94a484 -[CMParser parse] + 244
11 CocoaMarkdown 0x000000010f96370b -[CMAttributedStringRenderer render] + 315
12 Example-iOS 0x000000010f5b9325 $s11Example_iOS14ViewControllerC11viewDidLoadyyF + 1765
13 Example-iOS 0x000000010f5b9784 $s11Example_iOS14ViewControllerC11viewDidLoadyyFTo + 36
14 UIKitCore 0x000000011978e0f7 -[UIViewController loadViewIfRequired] + 1183
15 UIKitCore 0x000000011978e524 -[UIViewController view] + 27
16 UIKitCore 0x0000000119dc722b -[UIWindow addRootViewControllerViewIfPossible] + 122
17 UIKitCore 0x0000000119dc791f -[UIWindow _setHidden:forced:] + 289
18 UIKitCore 0x0000000119dda57e -[UIWindow makeKeyAndVisible] + 42
19 UIKitCore 0x0000000119d8a33c -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 4555
20 UIKitCore 0x0000000119d8f4e6 -[UIApplication _runWithMainScene:transitionContext:completion:] + 1617
21 UIKitCore 0x00000001195d3a4e __111-[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:]_block_invoke + 904
22 UIKitCore 0x00000001195dc346 +[_UICanvas _enqueuePostSettingUpdateTransactionBlock:] + 153
23 UIKitCore 0x00000001195d3664 -[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:] + 236
24 UIKitCore 0x00000001195d3fc0 -[__UICanvasLifecycleMonitor_Compatability activateEventsOnly:withContext:completion:] + 1091
25 UIKitCore 0x00000001195d2332 __82-[_UIApplicationCanvas _transitionLifecycleStateWithTransitionContext:completion:]_block_invoke + 782
26 UIKitCore 0x00000001195d1fe9 -[_UIApplicationCanvas _transitionLifecycleStateWithTransitionContext:completion:] + 433
27 UIKitCore 0x00000001195d6d2e __125-[_UICanvasLifecycleSettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:]_block_invoke + 576
28 UIKitCore 0x00000001195d7988 _performActionsWithDelayForTransitionContext + 100
29 UIKitCore 0x00000001195d6a95 -[_UICanvasLifecycleSettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:] + 223
30 UIKitCore 0x00000001195dba48 -[_UICanvas scene:didUpdateWithDiff:transitionContext:completion:] + 392
31 UIKitCore 0x0000000119d8ddc8 -[UIApplication workspace:didCreateScene:withTransitionContext:completion:] + 514
32 UIKitCore 0x000000011994502f -[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:] + 361
33 FrontBoardServices 0x000000011cbead25 -[FBSSceneImpl _didCreateWithTransitionContext:completion:] + 448
34 FrontBoardServices 0x000000011cbf4ad6 __56-[FBSWorkspace client:handleCreateScene:withCompletion:]_block_invoke_2 + 283
35 FrontBoardServices 0x000000011cbf4300 __40-[FBSWorkspace _performDelegateCallOut:]_block_invoke + 53
36 libdispatch.dylib 0x0000000112a21db5 _dispatch_client_callout + 8
37 libdispatch.dylib 0x0000000112a252ba _dispatch_block_invoke_direct + 300
38 FrontBoardServices 0x000000011cc260da FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK + 30
39 FrontBoardServices 0x000000011cc25d92 -[FBSSerialQueue _performNext] + 451
40 FrontBoardServices 0x000000011cc26327 -[FBSSerialQueue _performNextFromRunLoopSource] + 42
41 CoreFoundation 0x0000000111660db1 CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 17
42 CoreFoundation 0x0000000111660633 __CFRunLoopDoSources0 + 243
43 CoreFoundation 0x000000011165acef __CFRunLoopRun + 1231
44 CoreFoundation 0x000000011165a4d2 CFRunLoopRunSpecific + 626
45 GraphicsServices 0x0000000115ebd2fe GSEventRunModal + 65
46 UIKitCore 0x0000000119d90fc2 UIApplicationMain + 140
47 Example-iOS 0x000000010f5ba9eb main + 75
48 libdyld.dylib 0x0000000112a96541 start + 1
49 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

H5 not working

Hi,

Love CocaMD but I'd love to see ##### and ###### support. If you could tell me how to implement it I'd greatly appreciate it !

Probably code block bug with trailing ```

what I did

NSString *md = @"```c\n//This is a code block\n```";
NSData *data = [md dataUsingEncoding:NSUTF8StringEncoding];
CMDocument *document = [[CMDocument alloc] initWithData:data options:0];
CMAttributedStringRenderer *renderer = [[CMAttributedStringRenderer alloc] initWithDocument:document attributes:[CMTextAttributes new]];
NSAttributedString *attributedString = [renderer render];
NSLog(@"%@", attributedString);

What I expect

//This is a code block{
    NSFont = ...
}

What I got

//This is a code block
```{
    NSFont = ...
}

Note that the trailing ``` is included in the returned NSAttributedString

UITextView configuration to allow opening of links

Hello!

I'm really excited by the possibilities of CocoaMarkdown, especially with an image support PR in progress! I'm trying to integrate it into a project I'm working on, but I'm having trouble getting links to open when tapped as per the example iOS app. I'm probably doing it wrong, but is there something glaringly incorrect with how I've configured this view controller/text view (please excuse the frame setting code ๐Ÿ˜œ )?

import UIKit
import CocoaMarkdown

class Wat: UIViewController {
    let textView = UITextView(frame: CGRect(x: 0, y: 0, width: 320, height: 500))

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(textView)

        let path = NSBundle.mainBundle().pathForResource("test", ofType: "md")!
        let document = CMDocument(contentsOfFile: path, options: .Smart)
        let renderer = CMAttributedStringRenderer(document: document, attributes: CMTextAttributes())
        textView.attributedText = renderer.render()
    }
}

Note that the link does render as blue and underlined, but is not tappable.

Some README code doesn't compile

Hello.

The README includes several references to code that sends nil for the options. But that parameter is a required one so it doesn't compile:

let document = CMDocument(contentsOfFile: path, options: nil)

Maybe I'm missing something?

Support two empty spaces at the end of line to trigger line return

If I understand correctly cmark does support this, like normal markdown syntax, but attributed string sees this break as a new paragraph. For example, the following markdown:

foo
bar

baz  
qux

Should render like this:

But attributed string renders like this:

Have a feeling I'm not the first one wondering about this. Anyone knows anything about this / can comment? If PR is needed, where should I start looking at?

Cocoapods install issue: 'cmark.h' file not found

Steps to reproduce:

  1. Install cmake
  2. Install cocoapods
  3. Clone this project
  4. Navigate to the project directory and run pod install
  5. Open the MarkdownTest.xcworkspace (Xcode 7.2.1)
  6. Build project

Expected results: The project should build without errors

Actual results: The project fails to build with the error:

/Users/me/dev/MarkdownTest/Pods/CocoaMarkdown/CocoaMarkdown/CMNode_Private.h:10:9:
'cmark.h' file not found

Parser does not detect \r newline characters

When parsing a string composed of \r characters, the parser continue parsing as if no newline character was detected. (e.g. Second * list bullet character will be rendered as * because no newline was detected).

The final result is weird because a UILabel or UITextView will detect newlines, but the whole attributed string will be messed up.

I know using \r characters is never a good idea, but sometimes that's the only thing you get from a remote server...

CocoaMarkdown does not compile on Sierra using /Applications/Xcode-beta 2.app/Contents/Developer

Installing cmark (0.21.0)
[!] /bin/bash -c
set -e
echo pwd
sed -i '' 's/include <(cmark.*)>/include "\1"/' src/cmark.h
mkdir -p build; cd build && cmake -G Xcode ..

/Users/colinayer2/Library/Caches/CocoaPods/Pods/Release/cmark/0.21.0-0868a
-- The C compiler identification is AppleClang 8.0.0.8000040
-- The CXX compiler identification is AppleClang 8.0.0.8000040
-- Configuring incomplete, errors occurred!
See also "/Users/colinayer2/Library/Caches/CocoaPods/Pods/Release/cmark/0.21.0-0868a/build/CMakeFiles/CMakeOutput.log".
CMake Error at CMakeLists.txt:1 (project):
No CMAKE_C_COMPILER could be found.

CMake Error at CMakeLists.txt:1 (project):
No CMAKE_CXX_COMPILER could be found.

Link by cocopods with duplicate symbol error

  • Pod version : 1.8.4
  • Xcode 11.2
  • iPhone device 12.4.2
Podfile:
pod "CocoaMarkdown", :git => 'https://github.com/indragiek/CocoaMarkdown.git'

Link error:

duplicate symbol '_main' in:
    /Users/chenyn/Library/Developer/Xcode/DerivedData/CaJian-gdqwwrpegxglvygdepdetmfjtucl/Build/Intermediates.noindex/CaJian.build/Debug-iphoneos/CaJian.build/Objects-normal/arm64/main.o
    /Users/chenyn/Library/Developer/Xcode/DerivedData/CaJian-gdqwwrpegxglvygdepdetmfjtucl/Build/Products/Debug-iphoneos/cmark/libcmark.a(main.o)
ld: 1 duplicate symbol for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Is this an error related to my environment or resulted from any incorrect operation?

I can't compile example projects

Hi,

I can't compile the example projects because CommonMark C files and other dependencies are not in the project.
Can you upload a version with all necessary files?
Thanks!

Better code block

Is there plans for syntax highlighting, and even potential inline scroll instead of word wrapping?

Bulleted lists line break bug

Two bulleted lists with two line breaks between them causes there to be a line break between the bullets and that list item's contents. For example, take this markdown with three bullet points:

* Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n* Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n* Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.

That results in what you'd expect of our bulleted lists:
screen shot 2017-01-24 at 11 04 15 am

But if you simply add another \n between the second and third bullet points (we'd expect this to create two different bulleted lists), you instead get this:
screen shot 2017-01-24 at 11 05 28 am

Just double checked this on the latest from master.

Convert Markdown from String not File

Hi,

Is there a way to convert Markdown directly from String instead of creating CMDocument? The reason is I have the markdown text in a String, so I need to save to local directory and then convert to CMDocument which is an expensive task. CMDocument can only take contentOfFile.

Thank you
Tal

Custom hooks?

I am using CocoaMarkdown for my open source macOS reddit client, and I was wondering if there is a way to create a custom hook? for example, if I want cocoaMarkdown to catch /r/subreddit text and highlight it and make it a clickable link. Is that possible using this library?

cocoapods

pod search CocoaMarkdown
[!] Unable to find a pod with name, author, summary, or description matching CocoaMarkdown

Image Support

I noticed that the images are not being implemented in the CMAttributedStringRenderer. Is there a plan for that?

I've been trying to work on an asynchronous version and getting some progress here.

Image renders as a placeholder until user clicks on it

Hi, I'm using the inline image functionality which was recently merged into the master branch. However, when I specify an image in markdown, I get a grey "question mark" in a box, which I see the code draws as a placeholder image. But the real image never appears until I click on that question mark, and then it instantly shows up.

Any advice? I am not fluent in NSAttributedStrings or NSTextAttachemts unfortunately.

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.