http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/Rakefile ---------------------------------------------------------------------- diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..0c0aa41 --- /dev/null +++ b/Rakefile @@ -0,0 +1,311 @@ +require "rubygems" +require 'rake' +require 'yaml' +require 'time' + +SOURCE = "." +CONFIG = { + 'version' => "0.3.0", + 'themes' => File.join(SOURCE, "_includes", "themes"), + 'layouts' => File.join(SOURCE, "_layouts"), + 'posts' => File.join(SOURCE, "_posts"), + 'post_ext' => "md", + 'theme_package_version' => "0.1.0" +} + +# Path configuration helper +module JB + class Path + SOURCE = "." + Paths = { + :layouts => "_layouts", + :themes => "_includes/themes", + :theme_assets => "assets/themes", + :theme_packages => "_theme_packages", + :posts => "_posts" + } + + def self.base + SOURCE + end + + # build a path relative to configured path settings. + def self.build(path, opts = {}) + opts[:root] ||= SOURCE + path = "#{opts[:root]}/#{Paths[path.to_sym]}/#{opts[:node]}".split("/") + path.compact! + File.__send__ :join, path + end + + end #Path +end #JB + +# Usage: rake post title="A Title" [date="2012-02-09"] [tags=[tag1,tag2]] [category="category"] +desc "Begin a new post in #{CONFIG['posts']}" +task :post do + abort("rake aborted: '#{CONFIG['posts']}' directory not found.") unless FileTest.directory?(CONFIG['posts']) + title = ENV["title"] || "new-post" + tags = ENV["tags"] || "[]" + category = ENV["category"] || "" + category = "\"#{category.gsub(/-/,' ')}\"" if !category.empty? + slug = title.downcase.strip.gsub(' ', '-').gsub(/[^\w-]/, '') + begin + date = (ENV['date'] ? Time.parse(ENV['date']) : Time.now).strftime('%Y-%m-%d') + rescue => e + puts "Error - date format must be YYYY-MM-DD, please check you typed it correctly!" + exit -1 + end + filename = File.join(CONFIG['posts'], "#{date}-#{slug}.#{CONFIG['post_ext']}") + if File.exist?(filename) + abort("rake aborted!") if ask("#{filename} already exists. Do you want to overwrite?", ['y', 'n']) == 'n' + end + + puts "Creating new post: #{filename}" + open(filename, 'w') do |post| + post.puts "---" + post.puts "layout: post" + post.puts "title: \"#{title.gsub(/-/,' ')}\"" + post.puts 'description: ""' + post.puts "category: #{category}" + post.puts "tags: #{tags}" + post.puts "---" + post.puts "{% include JB/setup %}" + end +end # task :post + +# Usage: rake page name="about.html" +# You can also specify a sub-directory path. +# If you don't specify a file extention we create an index.html at the path specified +desc "Create a new page." +task :page do + name = ENV["name"] || "new-page.md" + filename = File.join(SOURCE, "#{name}") + filename = File.join(filename, "index.html") if File.extname(filename) == "" + title = File.basename(filename, File.extname(filename)).gsub(/[\W\_]/, " ").gsub(/\b\w/){$&.upcase} + if File.exist?(filename) + abort("rake aborted!") if ask("#{filename} already exists. Do you want to overwrite?", ['y', 'n']) == 'n' + end + + mkdir_p File.dirname(filename) + puts "Creating new page: #{filename}" + open(filename, 'w') do |post| + post.puts "---" + post.puts "layout: page" + post.puts "title: \"#{title}\"" + post.puts 'description: ""' + post.puts "---" + post.puts "{% include JB/setup %}" + end +end # task :page + +desc "Launch preview environment" +task :preview do + system "jekyll serve -w" +end # task :preview + +# Public: Alias - Maintains backwards compatability for theme switching. +task :switch_theme => "theme:switch" + +namespace :theme do + + # Public: Switch from one theme to another for your blog. + # + # name - String, Required. name of the theme you want to switch to. + # The theme must be installed into your JB framework. + # + # Examples + # + # rake theme:switch name="the-program" + # + # Returns Success/failure messages. + desc "Switch between Jekyll-bootstrap themes." + task :switch do + theme_name = ENV["name"].to_s + theme_path = File.join(CONFIG['themes'], theme_name) + settings_file = File.join(theme_path, "settings.yml") + non_layout_files = ["settings.yml"] + + abort("rake aborted: name cannot be blank") if theme_name.empty? + abort("rake aborted: '#{theme_path}' directory not found.") unless FileTest.directory?(theme_path) + abort("rake aborted: '#{CONFIG['layouts']}' directory not found.") unless FileTest.directory?(CONFIG['layouts']) + + Dir.glob("#{theme_path}/*") do |filename| + next if non_layout_files.include?(File.basename(filename).downcase) + puts "Generating '#{theme_name}' layout: #{File.basename(filename)}" + + open(File.join(CONFIG['layouts'], File.basename(filename)), 'w') do |page| + if File.basename(filename, ".html").downcase == "default" + page.puts "---" + page.puts File.read(settings_file) if File.exist?(settings_file) + page.puts "---" + else + page.puts "---" + page.puts "layout: default" + page.puts "---" + end + page.puts "{% include JB/setup %}" + page.puts "{% include themes/#{theme_name}/#{File.basename(filename)} %}" + end + end + + puts "=> Theme successfully switched!" + puts "=> Reload your web-page to check it out =)" + end # task :switch + + # Public: Install a theme using the theme packager. + # Version 0.1.0 simple 1:1 file matching. + # + # git - String, Optional path to the git repository of the theme to be installed. + # name - String, Optional name of the theme you want to install. + # Passing name requires that the theme package already exist. + # + # Examples + # + # rake theme:install git="https://github.com/jekyllbootstrap/theme-twitter.git" + # rake theme:install name="cool-theme" + # + # Returns Success/failure messages. + desc "Install theme" + task :install do + if ENV["git"] + manifest = theme_from_git_url(ENV["git"]) + name = manifest["name"] + else + name = ENV["name"].to_s.downcase + end + + packaged_theme_path = JB::Path.build(:theme_packages, :node => name) + + abort("rake aborted! + => ERROR: 'name' cannot be blank") if name.empty? + abort("rake aborted! + => ERROR: '#{packaged_theme_path}' directory not found. + => Installable themes can be added via git. You can find some here: http://github.com/jekyllbootstrap + => To download+install run: `rake theme:install git='[PUBLIC-CLONE-URL]'` + => example : rake theme:install git='[email protected]:jekyllbootstrap/theme-the-program.git' + ") unless FileTest.directory?(packaged_theme_path) + + manifest = verify_manifest(packaged_theme_path) + + # Get relative paths to packaged theme files + # Exclude directories as they'll be recursively created. Exclude meta-data files. + packaged_theme_files = [] + FileUtils.cd(packaged_theme_path) { + Dir.glob("**/*.*") { |f| + next if ( FileTest.directory?(f) || f =~ /^(manifest|readme|packager)/i ) + packaged_theme_files << f + } + } + + # Mirror each file into the framework making sure to prompt if already exists. + packaged_theme_files.each do |filename| + file_install_path = File.join(JB::Path.base, filename) + if File.exist? file_install_path and ask("#{file_install_path} already exists. Do you want to overwrite?", ['y', 'n']) == 'n' + next + else + mkdir_p File.dirname(file_install_path) + cp_r File.join(packaged_theme_path, filename), file_install_path + end + end + + puts "=> #{name} theme has been installed!" + puts "=> ---" + if ask("=> Want to switch themes now?", ['y', 'n']) == 'y' + system("rake switch_theme name='#{name}'") + end + end + + # Public: Package a theme using the theme packager. + # The theme must be structured using valid JB API. + # In other words packaging is essentially the reverse of installing. + # + # name - String, Required name of the theme you want to package. + # + # Examples + # + # rake theme:package name="twitter" + # + # Returns Success/failure messages. + desc "Package theme" + task :package do + name = ENV["name"].to_s.downcase + theme_path = JB::Path.build(:themes, :node => name) + asset_path = JB::Path.build(:theme_assets, :node => name) + + abort("rake aborted: name cannot be blank") if name.empty? + abort("rake aborted: '#{theme_path}' directory not found.") unless FileTest.directory?(theme_path) + abort("rake aborted: '#{asset_path}' directory not found.") unless FileTest.directory?(asset_path) + + ## Mirror theme's template directory (_includes) + packaged_theme_path = JB::Path.build(:themes, :root => JB::Path.build(:theme_packages, :node => name)) + mkdir_p packaged_theme_path + cp_r theme_path, packaged_theme_path + + ## Mirror theme's asset directory + packaged_theme_assets_path = JB::Path.build(:theme_assets, :root => JB::Path.build(:theme_packages, :node => name)) + mkdir_p packaged_theme_assets_path + cp_r asset_path, packaged_theme_assets_path + + ## Log packager version + packager = {"packager" => {"version" => CONFIG["theme_package_version"].to_s } } + open(JB::Path.build(:theme_packages, :node => "#{name}/packager.yml"), "w") do |page| + page.puts packager.to_yaml + end + + puts "=> '#{name}' theme is packaged and available at: #{JB::Path.build(:theme_packages, :node => name)}" + end + +end # end namespace :theme + +# Internal: Download and process a theme from a git url. +# Notice we don't know the name of the theme until we look it up in the manifest. +# So we'll have to change the folder name once we get the name. +# +# url - String, Required url to git repository. +# +# Returns theme manifest hash +def theme_from_git_url(url) + tmp_path = JB::Path.build(:theme_packages, :node => "_tmp") + abort("rake aborted: system call to git clone failed") if !system("git clone #{url} #{tmp_path}") + manifest = verify_manifest(tmp_path) + new_path = JB::Path.build(:theme_packages, :node => manifest["name"]) + if File.exist?(new_path) && ask("=> #{new_path} theme package already exists. Override?", ['y', 'n']) == 'n' + remove_dir(tmp_path) + abort("rake aborted: '#{manifest["name"]}' already exists as theme package.") + end + + remove_dir(new_path) if File.exist?(new_path) + mv(tmp_path, new_path) + manifest +end + +# Internal: Process theme package manifest file. +# +# theme_path - String, Required. File path to theme package. +# +# Returns theme manifest hash +def verify_manifest(theme_path) + manifest_path = File.join(theme_path, "manifest.yml") + manifest_file = File.open( manifest_path ) + abort("rake aborted: repo must contain valid manifest.yml") unless File.exist? manifest_file + manifest = YAML.load( manifest_file ) + manifest_file.close + manifest +end + +def ask(message, valid_options) + if valid_options + answer = get_stdin("#{message} #{valid_options.to_s.gsub(/"/, '').gsub(/, /,'/')} ") while !valid_options.include?(answer) + else + answer = get_stdin(message) + end + answer +end + +def get_stdin(message) + print message + STDIN.gets.chomp +end + +#Load custom rake scripts +Dir['_rake/*.rake'].each { |r| load r }
http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_config-prod.yml ---------------------------------------------------------------------- diff --git a/_config-prod.yml b/_config-prod.yml new file mode 100644 index 0000000..e497b30 --- /dev/null +++ b/_config-prod.yml @@ -0,0 +1,5 @@ +# singa.incubator.apache.org +# + +JB: + BASE_PATH: "" http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_config.yml ---------------------------------------------------------------------- diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..32634db --- /dev/null +++ b/_config.yml @@ -0,0 +1,130 @@ +# This is the default format. +# For more see: http://jekyllrb.com/docs/permalinks/ +permalink: /:categories/:title + +exclude: [".rvmrc", ".rbenv-version", "README.md", "Rakefile", "changelog.md"] +highlighter: pygments + +# Themes are encouraged to use these universal variables +# so be sure to set them if your theme uses them. +# +time: 2015-05-06 +title : Apache SINGA +author : + email : [email protected] + #name : SINGA + #github: + +# The production_url is only used when full-domain names are needed +# such as sitemap.txt +# Most places will/should use BASE_PATH to make the urls +# +# If you have set a CNAME (pages.github.com) set your custom domain here. +# Else if you are pushing to username.github.io, replace with your username. +# Finally if you are pushing to a GitHub project page, include the project name at the end. +##http://nusinga.github.io +#production_url : + +# All Jekyll-Bootstrap specific configurations are namespaced into this hash +# +safe : true +JB : + version : 0.3.0 + + # All links will be namespaced by BASE_PATH if defined. + # Links in your website should always be prefixed with {{BASE_PATH}} + # however this value will be dynamically changed depending on your deployment situation. + # + # CNAME (http://yourcustomdomain.com) + # DO NOT SET BASE_PATH + # (urls will be prefixed with "/" and work relatively) + # + # GitHub Pages (http://username.github.io) + # DO NOT SET BASE_PATH + # (urls will be prefixed with "/" and work relatively) + # + # GitHub Project Pages (http://username.github.io/project-name) + # + # A GitHub Project site exists in the `gh-pages` branch of one of your repositories. + # REQUIRED! Set BASE_PATH to: http://username.github.io/project-name + # + # CAUTION: + # - When in Localhost, your site will run from root "/" regardless of BASE_PATH + # - Only the following values are falsy: ["", null, false] + # - When setting BASE_PATH it must be a valid url. + # This means always setting the protocol (http|https) or prefixing with "/" + # + BASE_PATH : "/singa" #http://www.comp.nus.edu.sg/~wangwei + + # By default, the asset_path is automatically defined relative to BASE_PATH plus the enabled theme. + # ex: [BASE_PATH]/assets/themes/[THEME-NAME] + # + # Override this by defining an absolute path to assets here. + # ex: + # http://s3.amazonaws.com/yoursite/themes/watermelon + # /assets + # + #ASSET_PATH : + + # These paths are to the main pages Jekyll-Bootstrap ships with. + # Some JB helpers refer to these paths; change them here if needed. + # + archive_path: /archive.html + categories_path : /categories.html + tags_path : /tags.html + atom_path : /atom.xml + rss_path : /rss.xml + + # Settings for comments helper + # Set 'provider' to the comment provider you want to use. + # Set 'provider' to false to turn commenting off globally. + # + comments : + provider : disqus + disqus : + short_name : nusinga + livefyre : + site_id : 123 + intensedebate : + account : 123abc + facebook : + appid : 123 + num_posts: 5 + width: 580 + colorscheme: light + + # Settings for analytics helper + # Set 'provider' to the analytics provider you want to use. + # Set 'provider' to false to turn analytics off globally. + # + analytics : + provider : google + google : + tracking_id : 'UA-58709187-1' + getclicky : + site_id : + mixpanel : + token : '_MIXPANEL_TOKEN_' + piwik : + baseURL : 'myserver.tld/piwik' # Piwik installation address (without protocol) + idsite : '1' # the id of the site on Piwik + + # Settings for sharing helper. + # Sharing is for things like tweet, plusone, like, reddit buttons etc. + # Set 'provider' to the sharing provider you want to use. + # Set 'provider' to false to turn sharing off globally. + # + sharing : + provider : false + + # Settings for all other include helpers can be defined by creating + # a hash with key named for the given helper. ex: + # + # pages_list : + # provider : "custom" + # + # Setting any helper's provider to 'custom' will bypass the helper code + # and include your custom code. Your custom file must be defined at: + # ./_includes/custom/[HELPER] + # where [HELPER] is the name of the helper you are overriding. + http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_drafts/jekyll-introduction-draft.md ---------------------------------------------------------------------- diff --git a/_drafts/jekyll-introduction-draft.md b/_drafts/jekyll-introduction-draft.md new file mode 100644 index 0000000..88b93f0 --- /dev/null +++ b/_drafts/jekyll-introduction-draft.md @@ -0,0 +1,10 @@ +--- +layout: post +category : lessons +tagline: "Supporting tagline" +tags : [intro, beginner, jekyll, tutorial] +--- +{% include JB/setup %} + + +This is an example of a draft. Read more here: [http://jekyllrb.com/docs/drafts/](http://jekyllrb.com/docs/drafts/) http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/JB/analytics ---------------------------------------------------------------------- diff --git a/_includes/JB/analytics b/_includes/JB/analytics new file mode 100644 index 0000000..951a0e3 --- /dev/null +++ b/_includes/JB/analytics @@ -0,0 +1,16 @@ +{% if site.safe and site.JB.analytics.provider and page.JB.analytics != false %} + +{% case site.JB.analytics.provider %} +{% when "google" %} + {% include JB/analytics-providers/google %} +{% when "getclicky" %} + {% include JB/analytics-providers/getclicky %} +{% when "mixpanel" %} + {% include JB/analytics-providers/mixpanel %} +{% when "piwik" %} + {% include JB/analytics-providers/piwik %} +{% when "custom" %} + {% include custom/analytics %} +{% endcase %} + +{% endif %} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/JB/analytics-providers/getclicky ---------------------------------------------------------------------- diff --git a/_includes/JB/analytics-providers/getclicky b/_includes/JB/analytics-providers/getclicky new file mode 100644 index 0000000..e9462f4 --- /dev/null +++ b/_includes/JB/analytics-providers/getclicky @@ -0,0 +1,12 @@ +<script type="text/javascript"> +var clicky_site_ids = clicky_site_ids || []; +clicky_site_ids.push({{ site.JB.analytics.getclicky.site_id }}); +(function() { + var s = document.createElement('script'); + s.type = 'text/javascript'; + s.async = true; + s.src = '//static.getclicky.com/js'; + ( document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0] ).appendChild( s ); +})(); +</script> +<noscript><p><img alt="Clicky" width="1" height="1" src="//in.getclicky.com/{{ site.JB.analytics.getclicky.site_id }}ns.gif" /></p></noscript> http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/JB/analytics-providers/google ---------------------------------------------------------------------- diff --git a/_includes/JB/analytics-providers/google b/_includes/JB/analytics-providers/google new file mode 100644 index 0000000..9014866 --- /dev/null +++ b/_includes/JB/analytics-providers/google @@ -0,0 +1,11 @@ +<script type="text/javascript"> + var _gaq = _gaq || []; + _gaq.push(['_setAccount', '{{ site.JB.analytics.google.tracking_id }}']); + _gaq.push(['_trackPageview']); + + (function() { + var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; + ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; + var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); + })(); +</script> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/JB/analytics-providers/mixpanel ---------------------------------------------------------------------- diff --git a/_includes/JB/analytics-providers/mixpanel b/_includes/JB/analytics-providers/mixpanel new file mode 100644 index 0000000..4406eb0 --- /dev/null +++ b/_includes/JB/analytics-providers/mixpanel @@ -0,0 +1,11 @@ +<script type="text/javascript"> + var mpq = []; + mpq.push(["init", "{{ site.JB.analytics.mixpanel.token}}"]); + (function(){var b,a,e,d,c;b=document.createElement("script");b.type="text/javascript"; + b.async=true;b.src=(document.location.protocol==="https:"?"https:":"http:")+ + "//api.mixpanel.com/site_media/js/api/mixpanel.js";a=document.getElementsByTagName("script")[0]; + a.parentNode.insertBefore(b,a);e=function(f){return function(){mpq.push( + [f].concat(Array.prototype.slice.call(arguments,0)))}};d=["init","track","track_links", + "track_forms","register","register_once","identify","name_tag","set_config"];for(c=0;c< + d.length;c++){mpq[d[c]]=e(d[c])}})(); +</script> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/JB/analytics-providers/piwik ---------------------------------------------------------------------- diff --git a/_includes/JB/analytics-providers/piwik b/_includes/JB/analytics-providers/piwik new file mode 100755 index 0000000..077a373 --- /dev/null +++ b/_includes/JB/analytics-providers/piwik @@ -0,0 +1,10 @@ +<script type="text/javascript"> + var pkBaseURL = (("https:" == document.location.protocol) ? "https://{{ site.JB.analytics.piwik.baseURL }}/" : "http://{{ site.JB.analytics.piwik.baseURL }}/"); + document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E")); +</script><script type="text/javascript"> + try { + var piwikTracker = Piwik.getTracker(pkBaseURL + "piwik.php", {{ site.JB.analytics.piwik.idsite }}); + piwikTracker.trackPageView(); + piwikTracker.enableLinkTracking(); + } catch( err ) {} +</script><noscript><p><img src="http://{{ site.JB.analytics.piwik.baseURL }}/piwik.php?idsite={{ site.JB.analytics.piwik.idsite }}" style="border:0" alt="" /></p></noscript> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/JB/categories_list ---------------------------------------------------------------------- diff --git a/_includes/JB/categories_list b/_includes/JB/categories_list new file mode 100644 index 0000000..83be2e2 --- /dev/null +++ b/_includes/JB/categories_list @@ -0,0 +1,37 @@ +{% comment %}<!-- +The categories_list include is a listing helper for categories. +Usage: + 1) assign the 'categories_list' variable to a valid array of tags. + 2) include JB/categories_list + example: + <ul> + {% assign categories_list = site.categories %} + {% include JB/categories_list %} + </ul> + + Notes: + Categories can be either a Hash of Category objects (hashes) or an Array of category-names (strings). + The encapsulating 'if' statement checks whether categories_list is a Hash or Array. + site.categories is a Hash while page.categories is an array. + + This helper can be seen in use at: ../_layouts/default.html +-->{% endcomment %} + +{% if site.JB.categories_list.provider == "custom" %} + {% include custom/categories_list %} +{% else %} + {% if categories_list.first[0] == null %} + {% for category in categories_list %} + <li><a href="{{ BASE_PATH }}{{ site.JB.categories_path }}#{{ category }}-ref"> + {{ category | join: "/" }} <span>{{ site.categories[category].size }}</span> + </a></li> + {% endfor %} + {% else %} + {% for category in categories_list %} + <li><a href="{{ BASE_PATH }}{{ site.JB.categories_path }}#{{ category[0] }}-ref"> + {{ category[0] | join: "/" }} <span>{{ category[1].size }}</span> + </a></li> + {% endfor %} + {% endif %} +{% endif %} +{% assign categories_list = nil %} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/JB/comments ---------------------------------------------------------------------- diff --git a/_includes/JB/comments b/_includes/JB/comments new file mode 100644 index 0000000..4e9e600 --- /dev/null +++ b/_includes/JB/comments @@ -0,0 +1,16 @@ +{% if site.JB.comments.provider and page.comments != false %} + +{% case site.JB.comments.provider %} +{% when "disqus" %} + {% include JB/comments-providers/disqus %} +{% when "livefyre" %} + {% include JB/comments-providers/livefyre %} +{% when "intensedebate" %} + {% include JB/comments-providers/intensedebate %} +{% when "facebook" %} + {% include JB/comments-providers/facebook %} +{% when "custom" %} + {% include custom/comments %} +{% endcase %} + +{% endif %} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/JB/comments-providers/disqus ---------------------------------------------------------------------- diff --git a/_includes/JB/comments-providers/disqus b/_includes/JB/comments-providers/disqus new file mode 100644 index 0000000..618a7b7 --- /dev/null +++ b/_includes/JB/comments-providers/disqus @@ -0,0 +1,14 @@ +<div id="disqus_thread"></div> +<script type="text/javascript"> + {% if site.safe == false %}var disqus_developer = 1;{% endif %} + var disqus_shortname = '{{ site.JB.comments.disqus.short_name }}'; // required: replace example with your forum shortname + {% if page.wordpress_id %}var disqus_identifier = '{{page.wordpress_id}} {{site.production_url}}/?p={{page.wordpress_id}}';{% endif %} + /* * * DON'T EDIT BELOW THIS LINE * * */ + (function() { + var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; + dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; + (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); + })(); +</script> +<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> +<a href="http://disqus.com" class="dsq-brlink">blog comments powered by <span class="logo-disqus">Disqus</span></a> http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/JB/comments-providers/facebook ---------------------------------------------------------------------- diff --git a/_includes/JB/comments-providers/facebook b/_includes/JB/comments-providers/facebook new file mode 100644 index 0000000..6b3e5e0 --- /dev/null +++ b/_includes/JB/comments-providers/facebook @@ -0,0 +1,9 @@ +<div id="fb-root"></div> +<script>(function(d, s, id) { + var js, fjs = d.getElementsByTagName(s)[0]; + if (d.getElementById(id)) return; + js = d.createElement(s); js.id = id; + js.src = "//connect.facebook.net/en_US/all.js#xfbml=1&appId={{ site.JB.comments.facebook.appid }}"; + fjs.parentNode.insertBefore(js, fjs); +}(document, 'script', 'facebook-jssdk'));</script> +<div class="fb-comments" data-href="{{ site.production_url }}" data-num-posts="{{ site.JB.comments.facebook.num_posts }}" data-width="{{ site.JB.comments.facebook.width }}" data-colorscheme="{{ site.JB.comments.facebook.colorscheme }}"></div> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/JB/comments-providers/intensedebate ---------------------------------------------------------------------- diff --git a/_includes/JB/comments-providers/intensedebate b/_includes/JB/comments-providers/intensedebate new file mode 100644 index 0000000..ab0c3c9 --- /dev/null +++ b/_includes/JB/comments-providers/intensedebate @@ -0,0 +1,6 @@ +<script> +var idcomments_acct = '{{ site.JB.comments.intensedebate.account }}'; +var idcomments_post_id; +var idcomments_post_url; +</script> +<script type="text/javascript" src="http://www.intensedebate.com/js/genericLinkWrapperV2.js"></script> http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/JB/comments-providers/livefyre ---------------------------------------------------------------------- diff --git a/_includes/JB/comments-providers/livefyre b/_includes/JB/comments-providers/livefyre new file mode 100644 index 0000000..704b803 --- /dev/null +++ b/_includes/JB/comments-providers/livefyre @@ -0,0 +1,6 @@ +<script type='text/javascript' src='http://zor.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js'></script> +<script type='text/javascript'> + var fyre = LF({ + site_id: {{ site.JB.comments.livefyre.site_id }} + }); +</script> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/JB/liquid_raw ---------------------------------------------------------------------- diff --git a/_includes/JB/liquid_raw b/_includes/JB/liquid_raw new file mode 100644 index 0000000..da2d359 --- /dev/null +++ b/_includes/JB/liquid_raw @@ -0,0 +1,32 @@ +{% comment%}<!-- +The liquid_raw helper is a way to display raw liquid code, as opposed to parsing it. +Normally you'd use Liquid's built in 'raw' tag. +The problem is GitHub Jekyll does not support the current Liquid release. +GitHub Jekyll supports the deprecated 'literal' tag. +Using one will break the other if you plan to deploy to GitHub pages. + see: https://github.com/mojombo/jekyll/issues/425 + +Since I don't want to mess with Liquid versions, I'll just rewrite the way I +intend to give liquid examples. It's not an elegant solution by any means: + +Usage: + 1) Define a 'text' variable with the block of liquid code you intend to display. + 2) Pass the text variable to include JB/liquid_raw + + example: + {% capture text %}|.% for tag in tags_list %.| + <li><a href="|.{ site.var.tags_path }.||.{ tag[0] }.|-ref">|.{ tag[0] }.| <span>|.{tag[1].size}.|</span></a></li> + |.% endfor %.| + + |.% assign tags_list = null %.|{% endcapture %} + {% include JB/liquid_raw %} + + As seen here, you must use "|." and ".|" as opening and closing brackets. +-->{% endcomment%} + +{% if site.JB.liquid_raw.provider == "custom" %} + {% include custom/liquid_raw %} +{% else %} + <pre><code>{{text | replace:"|.", "{" | replace:".|", "}" | replace:">", ">" | replace:"<", "<" }}</code></pre> +{% endif %} +{% assign text = nil %} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/JB/pages_list ---------------------------------------------------------------------- diff --git a/_includes/JB/pages_list b/_includes/JB/pages_list new file mode 100644 index 0000000..05e0525 --- /dev/null +++ b/_includes/JB/pages_list @@ -0,0 +1,39 @@ +{% comment %}<!-- +The pages_list include is a listing helper. +Usage: + 1) assign the 'pages_list' variable to a valid array of pages or posts. + 2) include JB/pages_list + example: + <ul> + {% assign pages_list = site.pages %} + {% include JB/pages_list %} + </ul> + + Grouping: (optional): + assign the 'group' variable to constrain the list to only pages/posts + in the given group. Note you must define the group manually in the page/post + meta-data to use this feature. + Grouping is mainly helpful for non-post pages. + If you want to group posts, it's easier/better to tag them, then pass the tagged posts array. + i.e. site.tags.cool_tag (this returns an array of posts tagged: cool_tag) + + This helper can be seen in use at: ../_layouts/default.html +-->{% endcomment %} + +{% if site.JB.pages_list.provider == "custom" %} + {% include custom/pages_list %} +{% else %} + {% for node in pages_list %} + {% if node.title != null %} + {% if group == null or group == node.group %} + {% if page.url == node.url %} + <li class="active"><a href="{{ BASE_PATH }}{{node.url}}" class="active">{{node.title}}</a></li> + {% else %} + <li><a href="{{ BASE_PATH }}{{node.url}}">{{node.title}}</a></li> + {% endif %} + {% endif %} + {% endif %} + {% endfor %} +{% endif %} +{% assign pages_list = nil %} +{% assign group = nil %} http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/JB/posts_collate ---------------------------------------------------------------------- diff --git a/_includes/JB/posts_collate b/_includes/JB/posts_collate new file mode 100644 index 0000000..f612ade --- /dev/null +++ b/_includes/JB/posts_collate @@ -0,0 +1,55 @@ +{% comment %}<!-- +Collate_posts helper. Collated posts by year and month. +Usage: + 1) assign the 'posts_collate' variable to a valid array of posts. + 2) include JB/posts_collate + example: + {% assign posts_collate = site.posts %} + {% include JB/posts_collate %} + + Ordering: + Posts are displayed in reverse chronological order. + For normal chronological order: + 1) Change the for loop to this: + => 'for post in site.posts reversed' + 2) Next make sure to change 'post.previous.date' to: + => 'post.next.date' + +-->{% endcomment %} + +{% if site.JB.posts_collate.provider == "custom" %} + {% include custom/posts_collate %} +{% else %} + {% for post in posts_collate %} + {% capture this_year %}{{ post.date | date: "%Y" }}{% endcapture %} + {% capture this_month %}{{ post.date | date: "%B" }}{% endcapture %} + {% capture next_year %}{{ post.previous.date | date: "%Y" }}{% endcapture %} + {% capture next_month %}{{ post.previous.date | date: "%B" }}{% endcapture %} + + {% if forloop.first %} + <h2>{{this_year}}</h2> + <h3>{{this_month}}</h3> + <ul> + {% endif %} + + <li><span>{{ post.date | date: "%B %e, %Y" }}</span> » <a href="{{ BASE_PATH }}{{ post.url }}">{{ post.title }}</a></li> + + {% if forloop.last %} + </ul> + {% else %} + {% if this_year != next_year %} + </ul> + <h2>{{next_year}}</h2> + <h3>{{next_month}}</h3> + <ul> + {% else %} + {% if this_month != next_month %} + </ul> + <h3>{{next_month}}</h3> + <ul> + {% endif %} + {% endif %} + {% endif %} + {% endfor %} +{% endif %} +{% assign posts_collate = nil %} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/JB/setup ---------------------------------------------------------------------- diff --git a/_includes/JB/setup b/_includes/JB/setup new file mode 100644 index 0000000..efcd84b --- /dev/null +++ b/_includes/JB/setup @@ -0,0 +1,22 @@ +{% capture jbcache %} + <!-- + - Dynamically set liquid variables for working with URLs/paths + --> + {% if site.JB.setup.provider == "custom" %} + {% include custom/setup %} + {% else %} + {% if site.safe and site.JB.BASE_PATH and site.JB.BASE_PATH != '' %} + {% assign BASE_PATH = site.JB.BASE_PATH %} + {% assign HOME_PATH = site.JB.BASE_PATH %} + {% else %} + {% assign BASE_PATH = nil %} + {% assign HOME_PATH = "/" %} + {% endif %} + + {% if site.JB.ASSET_PATH %} + {% assign ASSET_PATH = site.JB.ASSET_PATH %} + {% else %} + {% capture ASSET_PATH %}{{ BASE_PATH }}/assets/themes/{{ page.theme.name }}{% endcapture %} + {% endif %} + {% endif %} +{% endcapture %}{% assign jbcache = nil %} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/JB/sharing ---------------------------------------------------------------------- diff --git a/_includes/JB/sharing b/_includes/JB/sharing new file mode 100644 index 0000000..f5b1151 --- /dev/null +++ b/_includes/JB/sharing @@ -0,0 +1,8 @@ +{% if site.safe and site.JB.sharing.provider and page.JB.sharing != false %} + +{% case site.JB.sharing.provider %} +{% when "custom" %} + {% include custom/sharing %} +{% endcase %} + +{% endif %} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/JB/tags_list ---------------------------------------------------------------------- diff --git a/_includes/JB/tags_list b/_includes/JB/tags_list new file mode 100644 index 0000000..8eb62a7 --- /dev/null +++ b/_includes/JB/tags_list @@ -0,0 +1,33 @@ +{% comment %}<!-- +The tags_list include is a listing helper for tags. +Usage: + 1) assign the 'tags_list' variable to a valid array of tags. + 2) include JB/tags_list + example: + <ul> + {% assign tags_list = site.tags %} + {% include JB/tags_list %} + </ul> + + Notes: + Tags can be either a Hash of tag objects (hashes) or an Array of tag-names (strings). + The encapsulating 'if' statement checks whether tags_list is a Hash or Array. + site.tags is a Hash while page.tags is an array. + + This helper can be seen in use at: ../_layouts/default.html +-->{% endcomment %} + +{% if site.JB.tags_list.provider == "custom" %} + {% include custom/tags_list %} +{% else %} + {% if tags_list.first[0] == null %} + {% for tag in tags_list %} + <li><a href="{{ BASE_PATH }}{{ site.JB.tags_path }}#{{ tag }}-ref">{{ tag }} <span>{{ site.tags[tag].size }}</span></a></li> + {% endfor %} + {% else %} + {% for tag in tags_list %} + <li><a href="{{ BASE_PATH }}{{ site.JB.tags_path }}#{{ tag[0] }}-ref">{{ tag[0] }} <span>{{ tag[1].size }}</span></a></li> + {% endfor %} + {% endif %} +{% endif %} +{% assign tags_list = nil %} http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/themes/bootstrap-3/default.html ---------------------------------------------------------------------- diff --git a/_includes/themes/bootstrap-3/default.html b/_includes/themes/bootstrap-3/default.html new file mode 100644 index 0000000..bc5b220 --- /dev/null +++ b/_includes/themes/bootstrap-3/default.html @@ -0,0 +1,98 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + + <title>{{ page.title }}</title> + {% if page.description %}<meta name="description" content="{{ page.description }}">{% endif %} + <meta name="author" content="{{ site.author.name }}"> + + <!-- Enable responsive viewport --> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + + <!-- Bootstrap styles --> + <link href="{{ ASSET_PATH }}/bootstrap/css/bootstrap.min.css" rel="stylesheet"> + <!-- Optional theme --> + <link href="{{ ASSET_PATH }}/bootstrap/css/bootstrap-theme.min.css" rel="stylesheet"> + <!-- Sticky Footer --> + <link href="{{ ASSET_PATH }}/bootstrap/css/bs-sticky-footer.css" rel="stylesheet"> + + <!-- Custom styles --> + <link href="{{ ASSET_PATH }}/css/style.css?body=1" rel="stylesheet" type="text/css" media="all"> + + <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> + <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> + <!--[if lt IE 9]> + <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script> + <script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script> + <![endif]--> + + <!-- Fav and touch icons --> + <!-- Update these with your own images + <link rel="shortcut icon" href="images/favicon.ico"> + <link rel="apple-touch-icon" href="images/apple-touch-icon.png"> + <link rel="apple-touch-icon" sizes="72x72" href="images/apple-touch-icon-72x72.png"> + <link rel="apple-touch-icon" sizes="114x114" href="images/apple-touch-icon-114x114.png"> + --> + + <!-- atom & rss feed --> + <link href="{{ BASE_PATH }}{{ site.JB.atom_path }}" type="application/atom+xml" rel="alternate" title="Sitewide ATOM Feed"> + <link href="{{ BASE_PATH }}{{ site.JB.rss_path }}" type="application/rss+xml" rel="alternate" title="Sitewide RSS Feed"> + + </head> + + <body> + <div id="wrap"> + <nav class="navbar navbar-default" role="navigation"> + <!-- Brand and toggle get grouped for better mobile display --> + <div class="navbar-header"> + <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#jb-navbar-collapse"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + <a class="navbar-brand" href="{{ HOME_PATH }}">{{ site.title }}</a> + </div> + + <!-- Collect the nav links, forms, and other content for toggling --> + <div class="collapse navbar-collapse" id="jb-navbar-collapse"> + <ul class="nav navbar-nav"> + {% assign pages_list = site.pages %} + {% assign group = 'navigation' %} + {% include JB/pages_list %} + </ul> + <form class="navbar-form navbar-right" role="search"> + <div class="form-group"> + <input type="text" class="form-control" placeholder="Search"> + </div> + <button type="submit" class="btn btn-default">Submit</button> + </form> + </div><!-- /.navbar-collapse --> + </nav> + + <div class="container"> + {{ content }} + </div> + + </div> + + <div id="footer"> + <div class="container"> + <p>© {{ site.time | date: '%Y' }} {{ site.author.name }} + with help from <a href="http://jekyllbootstrap.com" target="_blank" title="The Definitive Jekyll Blogging Framework">Jekyll Bootstrap</a> + and <a href="http://twitter.github.com/bootstrap/" target="_blank">Twitter Bootstrap</a> + </p> + </div> + </div> + + {% include JB/analytics %} + + + <!-- Latest compiled and minified JavaScript, requires jQuery 1.x (2.x not supported in IE8) --> + <!-- Placed at the end of the document so the pages load faster --> + <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> + <script src="{{ ASSET_PATH }}/bootstrap/js/bootstrap.min.js"></script> + </body> +</html> http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/themes/bootstrap-3/page.html ---------------------------------------------------------------------- diff --git a/_includes/themes/bootstrap-3/page.html b/_includes/themes/bootstrap-3/page.html new file mode 100644 index 0000000..e981ad9 --- /dev/null +++ b/_includes/themes/bootstrap-3/page.html @@ -0,0 +1,9 @@ +<div class="page-header"> + <h1>{{ page.title }} {% if page.tagline %} <small>{{ page.tagline }}</small>{% endif %}</h1> +</div> + +<div class="row"> + <div class="col-xs-12"> + {{ content }} + </div> +</div> http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/themes/bootstrap-3/post.html ---------------------------------------------------------------------- diff --git a/_includes/themes/bootstrap-3/post.html b/_includes/themes/bootstrap-3/post.html new file mode 100644 index 0000000..85cc0f4 --- /dev/null +++ b/_includes/themes/bootstrap-3/post.html @@ -0,0 +1,47 @@ +<div class="page-header"> + <h1>{{ page.title }} {% if page.tagline %}<small>{{page.tagline}}</small>{% endif %}</h1> +</div> + +<div class="row post-full"> + <div class="col-xs-12"> + <div class="date"> + <span>{{ page.date | date_to_long_string }}</span> + </div> + <div class="content"> + {{ content }} + </div> + + {% unless page.categories == empty %} + <ul class="tag_box inline"> + <li><i class="glyphicon glyphicon-open"></i></li> + {% assign categories_list = page.categories %} + {% include JB/categories_list %} + </ul> + {% endunless %} + + {% unless page.tags == empty %} + <ul class="tag_box inline"> + <li><i class="glyphicon glyphicon-tags"></i></li> + {% assign tags_list = page.tags %} + {% include JB/tags_list %} + </ul> + {% endunless %} + + <hr> + <ul class="pagination"> + {% if page.previous %} + <li class="prev"><a href="{{ BASE_PATH }}{{ page.previous.url }}" title="{{ page.previous.title }}">« Previous</a></li> + {% else %} + <li class="prev disabled"><a>← Previous</a></li> + {% endif %} + <li><a href="{{ BASE_PATH }}{{ site.JB.archive_path }}">Archive</a></li> + {% if page.next %} + <li class="next"><a href="{{ BASE_PATH }}{{ page.next.url }}" title="{{ page.next.title }}">Next »</a></li> + {% else %} + <li class="next disabled"><a>Next →</a> + {% endif %} + </ul> + <hr> + {% include JB/comments %} + </div> +</div> http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/themes/bootstrap-3/settings.yml ---------------------------------------------------------------------- diff --git a/_includes/themes/bootstrap-3/settings.yml b/_includes/themes/bootstrap-3/settings.yml new file mode 100644 index 0000000..379bfbc --- /dev/null +++ b/_includes/themes/bootstrap-3/settings.yml @@ -0,0 +1,2 @@ +theme : + name : bootstrap-3 \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/themes/twitter/default.html ---------------------------------------------------------------------- diff --git a/_includes/themes/twitter/default.html b/_includes/themes/twitter/default.html new file mode 100644 index 0000000..6074ac0 --- /dev/null +++ b/_includes/themes/twitter/default.html @@ -0,0 +1,127 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <title>{{ page.title }}</title> + {% if page.description %}<meta name="description" content="{{ page.description }}">{% endif %} + <meta name="author" content="{{ site.author.name }}"> + + <!-- Enable responsive viewport --> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + + <!-- Le HTML5 shim, for IE6-8 support of HTML elements --> + <!--[if lt IE 9]> + <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + + <!-- Le styles --> + <link href="{{ ASSET_PATH }}/bootstrap/css/bootstrap.2.2.2.min.css" rel="stylesheet"> + <link href="{{ ASSET_PATH }}/css/style.css?body=1" rel="stylesheet" type="text/css" media="all"> + <link rel="shortcut icon" type="image/x-icon" href="{{ ASSET_PATH }}/css/favicon.ico"> + + <!-- Le fav and touch icons --> + <!-- Update these with your own images + <link rel="shortcut icon" href="images/favicon.ico"> + <link rel="apple-touch-icon" href="images/apple-touch-icon.png"> + <link rel="apple-touch-icon" sizes="72x72" href="images/apple-touch-icon-72x72.png"> + <link rel="apple-touch-icon" sizes="114x114" href="images/apple-touch-icon-114x114.png"> + --> + + <!-- atom & rss feed --> + <link href="{{ BASE_PATH }}{{ site.JB.atom_path }}" type="application/atom+xml" rel="alternate" title="Sitewide ATOM Feed"> + <link href="{{ BASE_PATH }}{{ site.JB.rss_path }}" type="application/rss+xml" rel="alternate" title="Sitewide RSS Feed"> + + <!-- toc --> + <script src="http://code.jquery.com/jquery-1.7.2.min.js"></script> + <script src="{{ ASSET_PATH }}/js/toc.js"></script> + <script type="text/javascript"> + $(document).ready(function() { + $('#toc').toc(); + }); + </script> + <style > + .clickable-header { + cursor:pointer; + } + .clickable-header:hover { + text-decoration:underline; + } + .top-level-header { + display:inline; + } + .back-to-top { + margin-left:5px; + cursor:pointer; + } + #backtotop { + position: fixed; + left: 50%; + bottom: 100px; + margin-left:520px; + width: 30px; + height: 30px; + } + #toc, .toc, .mw-warning { + background-color: #FFF; + border-left: 1px solid #AAAAAA; + font-size: 95%; + padding-top: 45px; + position: fixed; + top: 0px; + left: 50%; + margin-left: 520px; + } + #toc strong{ + margin:20px; + } + </style> + + </head> + + <body> + <a href="https://github.com/apache/incubator-singa"><img style="position: absolute; top: 0; + left: 0; border: 0;" + src="https://camo.githubusercontent.com/8b6b8ccc6da3aa5722903da7b58eb5ab1081adee/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f6c6566745f6f72616e67655f6666373630302e706e67" + alt="Fork me on GitHub" + data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_left_orange_ff7600.png"></a> + + <div id="topanchor"></div> + <div class="navbar"> + <div class="navbar-inner"> + <div class="container-narrow"> + <a class="brand" href="{{ HOME_PATH }}">{{ site.title }}</a> + <ul class="nav"> + {% assign pages_list = site.pages %} + {% assign group = 'navigation' %} + {% include JB/pages_list %} + </ul> + </div> + </div> + </div> + <div class="container-narrow"> + <div class="content"> + {{ content }} + </div> + <hr> + <footer> + <p>Copyright © {{ site.time | date: '%Y' }} {{ site.author.name }} + The Apache Software Foundation. All rights reserved. + + Apache Singa, Apache, the Apache feather logo, and the Apache Singa + project logos are trademarks of The Apache Software Foundation. All + other marks mentioned may be trademarks or registered trademarks of + their respective owners. + <a href="./privacy.html"> Privacy Policy </a>. + </p> + </footer> + + </div> + + <!-- back to top + <div id="backtotop"> + <a href="#topanchor"><i class="icon-arrow-up back-to-top"></i>Top</a> + </div>--> + + {% include JB/analytics %} + </body> +</html> http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/themes/twitter/frontpage.html ---------------------------------------------------------------------- diff --git a/_includes/themes/twitter/frontpage.html b/_includes/themes/twitter/frontpage.html new file mode 100644 index 0000000..1030c27 --- /dev/null +++ b/_includes/themes/twitter/frontpage.html @@ -0,0 +1,136 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <title>{{ page.title }}</title> + {% if page.description %}<meta name="description" content="{{ page.description }}">{% endif %} + <meta name="author" content="{{ site.author.name }}"> + + <!-- Enable responsive viewport --> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + + <!-- Le HTML5 shim, for IE6-8 support of HTML elements --> + <!--[if lt IE 9]> + <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + + <!-- Le styles --> + <link href="{{ ASSET_PATH }}/bootstrap/css/bootstrap.2.2.2.min.css" rel="stylesheet"> + <link href="{{ ASSET_PATH }}/css/style.css?body=1" rel="stylesheet" type="text/css" media="all"> + <link rel="shortcut icon" type="image/x-icon" href="{{ ASSET_PATH }}/css/favicon.ico"> + + <!-- Le fav and touch icons --> + <!-- Update these with your own images + <link rel="shortcut icon" href="images/favicon.ico"> + <link rel="apple-touch-icon" href="images/apple-touch-icon.png"> + <link rel="apple-touch-icon" sizes="72x72" href="images/apple-touch-icon-72x72.png"> + <link rel="apple-touch-icon" sizes="114x114" href="images/apple-touch-icon-114x114.png"> + --> + + <!-- atom & rss feed --> + <link href="{{ BASE_PATH }}{{ site.JB.atom_path }}" type="application/atom+xml" rel="alternate" title="Sitewide ATOM Feed"> + <link href="{{ BASE_PATH }}{{ site.JB.rss_path }}" type="application/rss+xml" rel="alternate" title="Sitewide RSS Feed"> + + <!-- toc --> + <script src="http://code.jquery.com/jquery-1.7.2.min.js"></script> + <script src="{{ ASSET_PATH }}/js/toc.js"></script> + <script type="text/javascript"> + $(document).ready(function() { + $('#toc').toc(); + }); + </script> + <style > + .clickable-header { + cursor:pointer; + } + .clickable-header:hover { + text-decoration:underline; + } + .top-level-header { + display:inline; + } + .back-to-top { + margin-left:5px; + cursor:pointer; + } + #backtotop { + position: fixed; + left: 50%; + bottom: 100px; + margin-left:520px; + width: 30px; + height: 30px; + } + #toc, .toc, .mw-warning { + background-color: #FFF; + border-left: 1px solid #AAAAAA; + font-size: 95%; + padding-top: 45px; + position: fixed; + top: 0px; + left: 50%; + margin-left: 520px; + } + #toc strong{ + margin:20px; + } + </style> + + </head> + + <body> + <div id="topanchor"></div> + <div class="navbar"> + <div class="navbar-inner"> + <div class="container-narrow"> + <a class="brand" href="{{ HOME_PATH }}">{{ site.title }}</a> + <ul class="nav"> + {% assign pages_list = site.pages %} + {% assign group = 'navigation' %} + {% include JB/pages_list %} + </ul> + </div> + </div> + </div> + <div id="banner"> + <a href="https://github.com/apache/incubator-singa" style="float: left"><img style="position: relative; top: -9px; + left: 0; border: 0;" + src="https://camo.githubusercontent.com/8b6b8ccc6da3aa5722903da7b58eb5ab1081adee/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f6c6566745f6f72616e67655f6666373630302e706e67" + alt="Fork me on GitHub" + data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_left_orange_ff7600.png"></a> + + <div id="logos"> + <img class="singa-logo" src="{{ BASE_PATH }}/assets/image/singa-logo.png"/> + <div> + <img class="incubator-logo" src="{{ BASE_PATH }}/assets/image/incubator.png"/> + <span> A General Distributed Deep Learning Platform</span> + </div> + </div> + </div> + <div class="container-narrow"> + <div class="content"> + {{ content }} + </div> + <hr> + <footer> + <p>Copyright © {{ site.time | date: '%Y' }} {{ site.author.name }} + The Apache Software Foundation. All rights reserved. + + Apache Singa, Apache, the Apache feather logo, and the Apache Singa + project logos are trademarks of The Apache Software Foundation. All + other marks mentioned may be trademarks or registered trademarks of + their respective owners. + <a href="./privacy.html"> Privacy Policy </a>. + </p> + </footer> + + </div> + + <!-- back to top + <div id="backtotop"> + <a href="#topanchor"><i class="icon-arrow-up back-to-top"></i>Top</a> + </div>--> + + {% include JB/analytics %} + </body> +</html> http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/themes/twitter/page.html ---------------------------------------------------------------------- diff --git a/_includes/themes/twitter/page.html b/_includes/themes/twitter/page.html new file mode 100644 index 0000000..7c060ce --- /dev/null +++ b/_includes/themes/twitter/page.html @@ -0,0 +1,11 @@ +<!-- +<div class="page-header"> + <h1>{{ page.title }} {% if page.tagline %} <small>{{ page.tagline }}</small>{% endif %} </h1> +</div> +--> + +<div class="row-fluid"> + <div class="span12"> + {{ content }} + </div> +</div> http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/themes/twitter/post.html ---------------------------------------------------------------------- diff --git a/_includes/themes/twitter/post.html b/_includes/themes/twitter/post.html new file mode 100644 index 0000000..b46dcf5 --- /dev/null +++ b/_includes/themes/twitter/post.html @@ -0,0 +1,52 @@ +<div class="page-header"> + <h1>{{ page.title }} {% if page.tagline %}<small>{{page.tagline}}</small>{% endif %}<img src="{{ BASE_PATH }}/assets/image/singa_logo.jpg", style="width: 100px" align="right"/></h1> +</div> + +<div id="toc" class="toc"></div> +<div class="row-fluid post-full"> + <div class="span12"> + <!-- + <div class="date"> + <span>{{ page.date | date_to_long_string }}</span> + </div> + --> + <div class="content"> + {{ content }} + </div> + + {% unless page.categories == empty %} + <ul class="tag_box inline"> + <li><i class="icon-folder-open"></i></li> + {% assign categories_list = page.categories %} + {% include JB/categories_list %} + </ul> + {% endunless %} + + {% unless page.tags == empty %} + <ul class="tag_box inline"> + <li><i class="icon-tags"></i></li> + {% assign tags_list = page.tags %} + {% include JB/tags_list %} + </ul> + {% endunless %} + + <hr> + <div class="pagination"> + <ul> + {% if page.previous %} + <li class="prev"><a href="{{ BASE_PATH }}{{ page.previous.url }}" title="{{ page.previous.title }}">← Previous</a></li> + {% else %} + <li class="prev disabled"><a>← Previous</a></li> + {% endif %} + <li><a href="{{ BASE_PATH }}{{ site.JB.archive_path }}">Archive</a></li> + {% if page.next %} + <li class="next"><a href="{{ BASE_PATH }}{{ page.next.url }}" title="{{ page.next.title }}">Next →</a></li> + {% else %} + <li class="next disabled"><a>Next →</a> + {% endif %} + </ul> + </div> + <hr> + {% include JB/comments %} + </div> +</div> http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_includes/themes/twitter/settings.yml ---------------------------------------------------------------------- diff --git a/_includes/themes/twitter/settings.yml b/_includes/themes/twitter/settings.yml new file mode 100644 index 0000000..7ca7b73 --- /dev/null +++ b/_includes/themes/twitter/settings.yml @@ -0,0 +1,2 @@ +theme : + name : twitter \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_layouts/default.html ---------------------------------------------------------------------- diff --git a/_layouts/default.html b/_layouts/default.html new file mode 100644 index 0000000..2d9be07 --- /dev/null +++ b/_layouts/default.html @@ -0,0 +1,6 @@ +--- +theme : + name : twitter +--- +{% include JB/setup %} +{% include themes/twitter/default.html %} http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_layouts/frontpage.html ---------------------------------------------------------------------- diff --git a/_layouts/frontpage.html b/_layouts/frontpage.html new file mode 100644 index 0000000..2226e50 --- /dev/null +++ b/_layouts/frontpage.html @@ -0,0 +1,6 @@ +--- +theme : + name : twitter +--- +{% include JB/setup %} +{% include themes/twitter/frontpage.html %} http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_layouts/page.html ---------------------------------------------------------------------- diff --git a/_layouts/page.html b/_layouts/page.html new file mode 100644 index 0000000..6810b93 --- /dev/null +++ b/_layouts/page.html @@ -0,0 +1,5 @@ +--- +layout: frontpage +--- +{% include JB/setup %} +{% include themes/twitter/page.html %} http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_layouts/post.html ---------------------------------------------------------------------- diff --git a/_layouts/post.html b/_layouts/post.html new file mode 100644 index 0000000..9971d7c --- /dev/null +++ b/_layouts/post.html @@ -0,0 +1,5 @@ +--- +layout: default +--- +{% include JB/setup %} +{% include themes/twitter/post.html %} http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_plugins/debug.rb ---------------------------------------------------------------------- diff --git a/_plugins/debug.rb b/_plugins/debug.rb new file mode 100644 index 0000000..e1dde39 --- /dev/null +++ b/_plugins/debug.rb @@ -0,0 +1,38 @@ +# A simple way to inspect liquid template variables. +# Usage: +# Can be used anywhere liquid syntax is parsed (templates, includes, posts/pages) +# {{ site | debug }} +# {{ site.posts | debug }} +# +require 'pp' +module Jekyll + # Need to overwrite the inspect method here because the original + # uses < > to encapsulate the psuedo post/page objects in which case + # the output is taken for HTML tags and hidden from view. + # + class Post + def inspect + "#Jekyll:Post @id=#{self.id.inspect}" + end + end + + class Page + def inspect + "#Jekyll:Page @name=#{self.name.inspect}" + end + end + +end # Jekyll + +module Jekyll + module DebugFilter + + def debug(obj, stdout=false) + puts obj.pretty_inspect if stdout + "<pre>#{obj.class}\n#{obj.pretty_inspect}</pre>" + end + + end # DebugFilter +end # Jekyll + +Liquid::Template.register_filter(Jekyll::DebugFilter) \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_plugins/tocGenerator.rb ---------------------------------------------------------------------- diff --git a/_plugins/tocGenerator.rb b/_plugins/tocGenerator.rb new file mode 100644 index 0000000..12929c6 --- /dev/null +++ b/_plugins/tocGenerator.rb @@ -0,0 +1,117 @@ +require 'nokogiri' + +module Jekyll + module TOCGenerator + TOGGLE_HTML = '<div id="toctitle"><h3>%1</h3>%2</div>' + TOC_CONTAINER_HTML = '<div id="toc-container"><table class="toc" id="toc"><tbody><tr><td>%1<ul>%2</ul></td></tr></tbody></table></div>' + HIDE_HTML = '<span class="toctoggle">[<a id="toctogglelink" class="internal" href="#">%1</a>]</span>' + + def toc_generate(html) + # No Toc can be specified on every single page + # For example the index page has no table of contents + no_toc = @context.environments.first["page"]["noToc"] || false; + + if no_toc + return html + end + + config = @context.registers[:site].config + # Minimum number of items needed to show TOC, default 0 (0 means no minimum) + min_items_to_show_toc = config["minItemsToShowToc"] || 0 + + anchor_prefix = config["anchorPrefix"] || 'tocAnchor-' + + # Text labels + contents_label = config["contentsLabel"] || 'Contents' + hide_label = config["hideLabel"] || 'hide' + show_label = config["showLabel"] || 'show' + show_toggle_button = config["showToggleButton"] + + toc_html = '' + toc_level = 1 + toc_section = 1 + item_number = 1 + level_html = '' + + doc = Nokogiri::HTML(html) + + # Find h2 tag and all its h3 siblings until next h2 + doc.css('h2').each do |h2| + # TODO This XPATH expression can greatly improved + ct = h2.xpath('count(following-sibling::h2)') + h3s = h2.xpath("following-sibling::h3[count(following-sibling::h2)=#{ct}]") + + level_html = ''; + inner_section = 0; + + h3s.map.each do |h3| + inner_section += 1; + anchor_id = anchor_prefix + toc_level.to_s + '-' + toc_section.to_s + '-' + inner_section.to_s + h3['id'] = "#{anchor_id}" + + level_html += create_level_html(anchor_id, + toc_level + 1, + toc_section + inner_section, + item_number.to_s + '.' + inner_section.to_s, + h3.text, + '') + end + if level_html.length > 0 + level_html = '<ul>' + level_html + '</ul>'; + end + anchor_id = anchor_prefix + toc_level.to_s + '-' + toc_section.to_s; + h2['id'] = "#{anchor_id}" + + toc_html += create_level_html(anchor_id, + toc_level, + toc_section, + item_number, + h2.text, + level_html); + + toc_section += 1 + inner_section; + item_number += 1; + end + + # for convenience item_number starts from 1 + # so we decrement it to obtain the index count + toc_index_count = item_number - 1 + + if toc_html.length > 0 + hide_html = ''; + if (show_toggle_button) + hide_html = HIDE_HTML.gsub('%1', hide_label) + end + + if min_items_to_show_toc <= toc_index_count + replaced_toggle_html = TOGGLE_HTML + .gsub('%1', contents_label) + .gsub('%2', hide_html); + toc_table = TOC_CONTAINER_HTML + .gsub('%1', replaced_toggle_html) + .gsub('%2', toc_html); + doc.css('body').children.before(toc_table) + end + doc.css('body').children.to_xhtml(indent:3, indent_text:" ") + else + return html + end + end + +private + + def create_level_html(anchor_id, toc_level, toc_section, tocNumber, tocText, tocInner) + link = '<a href="#%1"><span class="tocnumber">%2</span> <span class="toctext">%3</span></a>%4' + .gsub('%1', anchor_id.to_s) + .gsub('%2', tocNumber.to_s) + .gsub('%3', tocText) + .gsub('%4', tocInner ? tocInner : ''); + '<li class="toc_level-%1 toc_section-%2">%3</li>' + .gsub('%1', toc_level.to_s) + .gsub('%2', toc_section.to_s) + .gsub('%3', link) + end + end +end + +Liquid::Template.register_filter(Jekyll::TOCGenerator) http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_posts/community/2015-01-20-code-style.md ---------------------------------------------------------------------- diff --git a/_posts/community/2015-01-20-code-style.md b/_posts/community/2015-01-20-code-style.md new file mode 100644 index 0000000..ff8b24b --- /dev/null +++ b/_posts/community/2015-01-20-code-style.md @@ -0,0 +1,42 @@ +--- +layout: post +title: Coding and Documentation Style +category : community +tagline: +tags : [coding, contribution, style] +--- +{% include JB/setup %} + +## Coding Styling +We follow Google's C++ coding [style](http://google-styleguide.googlecode.com/svn/trunk/cppguide.html) + +## Documentation Style + +### Comments + +We follow the [Doxygen](http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html) +style to add comments for the code. There are at least three points we need to follow, + +1. **JAVADOC_AUTOREF** is enabled to write the comment block as, + + /** + * brief description with a dot at the end. + * detailed description. + * @param + * @param + * @return + */ + +2. One line comment should be like this (actually there are more choices. We use this one), + + int num_procs; /**> total number of mpi processes */ + + the comments after double slashes `//` will not be generated to the html API pages but are allowed. + +3. Comments are apart from code should use macros like, + + /** + * \file this file, solver.h, contains two classes \class Solver and \class Prefetcher + */ + +### Tutorial and User Guide http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_posts/docs/2015-01-10-quick-start.md ---------------------------------------------------------------------- diff --git a/_posts/docs/2015-01-10-quick-start.md b/_posts/docs/2015-01-10-quick-start.md new file mode 100644 index 0000000..bf953ba --- /dev/null +++ b/_posts/docs/2015-01-10-quick-start.md @@ -0,0 +1,103 @@ +--- +layout: post +title: Quick Start +category : docs +tags : [installation, examples] +--- +{% include JB/setup %} + + +## Installation + +Clone the SINGA code from [Github](https://github.com/apache/incubator-singa) +or Apache's git repository + + git clone [email protected]:apache/incubator-singa.git + or + git clone https://github.com/apache/incubator-singa.git + + +Compile SINGA: + + ./configure + make + +If there are dependent libraries missing, please refer to +[installation]({{ BASE_PATH }}{% post_url /docs/2015-01-20-installation %}) page +for guidance on installing them. After successful compilation, the libsinga.so +and singa executable will be built into the build folder. + +## Run in standalone mode + +Running SINGA in standalone mode is on the contrary of running it on Mesos or +YARN. For standalone mode, users have to manage the resources manually. For +instance, they have to prepare a host file containing all running nodes. +There is no management on CPU and memory resources, hence SINGA consumes as much +CPU and memory resources as it needs. + +### Training on a single node + +For single node training, one process will be launched to run the SINGA code on +the node where SINGA is started. We train the [CNN model](http://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks) over the +[CIFAR-10](http://www.cs.toronto.edu/~kriz/cifar.html) dataset as an example. +The hyper-parameters are set following +[cuda-convnet](https://code.google.com/p/cuda-convnet/). + + +#### Data and model preparation + +Download the dataset and create the data shards for training and testing. + + cd examples/cifar10/ + make download + make shard + +A training dataset and a test dataset are created under *train-shard* and +*test-shard* folder respectively. A mena.shard file is also generated, which +contains the feature mean of all images. +<!--After creating the data shards, you to update the paths in the +model configuration file (*model.conf*) for the +training data shard, test data shard and the mean file.--> + +Since all modules used for training this CNN model are provided by SINGA as +built-in modules, there is no need to write any code. Instead, you just run the +executable file (*../../build/singa*) by providing the model configuration file +(*model.conf*). If you want to implement your own modules, e.g., layer, +then you have to register your modules in the driver code. After compiling the +driver code, link it with the SINGA library to generate the executable. More +details are described in [Code your own models](). + +#### Training without partitioning + +To train the model without any partitioning, you just set the numbers +in the cluster configuration file (*cluster.conf*) as : + + nworker_groups: 1 + nworkers_per_group: 1 + nserver_groups: 1 + nservers_per_group: 1 + +One worker group trains against one partition of the training dataset. If +*nworker_groups* is set to 1, then there is no data partitioning. One worker +runs over a partition of the model. If *nworkers_per_group* is set to 1, then +there is no model partitioning. More details on the cluster configuration are +described in the [System Architecture]() page. + +Start the training by running: + + #goto top level folder + cd .. + ./build/singa -model=examples/cifar10/model.conf -cluster=examples/cifar10/cluster.conf + +#### Training with data Partitioning + +#### Training with model Partitioning + +### Training in a cluster + + +## Run with Mesos + +*in working*... + +## Run with YARN http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_posts/docs/2015-01-20-installation.md ---------------------------------------------------------------------- diff --git a/_posts/docs/2015-01-20-installation.md b/_posts/docs/2015-01-20-installation.md new file mode 100644 index 0000000..bdc1b28 --- /dev/null +++ b/_posts/docs/2015-01-20-installation.md @@ -0,0 +1,9 @@ +--- +layout: post +title: Installation +category : docs +tags : [installation, examples] +--- +{% include JB/setup %} + + http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/666a841d/_posts/docs/2015-01-30-architecture.md ---------------------------------------------------------------------- diff --git a/_posts/docs/2015-01-30-architecture.md b/_posts/docs/2015-01-30-architecture.md new file mode 100644 index 0000000..f03c2b4 --- /dev/null +++ b/_posts/docs/2015-01-30-architecture.md @@ -0,0 +1,171 @@ +--- +layout: post +title: System Architecture +category : docs +tagline: +tags : [development, documentation, system architecture] +--- +{% include JB/setup %} + +We design the architecture of Singa with the consideration to make it general +to unify existing architectures. Then users can easily test the performance of +different architectures and select the best for their models. + +## Logical Architecture + +<figure> +<img src="{{ BASE_PATH }}/assets/image/arch/logical.png" align="center" width="550px"/> +<figcaption><strong> Fig.1 - Logical system architecture</strong></figcaption> +</figure> + +The logical system architecture is shown in Fig.1 with four worker groups and +two server groups. Each worker group runs against a partition of the +training dataset (called data parallelism) to compute the updates (e.g., the +gradients) of parameters of one model replica. Worker groups run +asynchronously, while workers within one group run synchronously with each +worker computing updates for a partition of the model parameters (called +model parallelism). Each server group maintains one replica of the model +parameters. It receives requests (e.g., Get/Put/Update) from workers and +handles these requests. Server groups synchronize with neighboring server groups +periodically or according to some rules. One worker (or server) group consists +of multiple (user defined number) threads. These threads may resident in one +process or span across multiple processes. + +Each worker (or server) group has a ParamShard object, which contains a full +set of Param objects for a model replica. Since the workers (or servers) may +span across multiple processes, this ParamShard may also be partitioned across +multiple processes. The ParamShards can share the same memory space for +parameter values if they resident in the same process like +[Caffe](http://caffe.berkeleyvision.org/)'s parallel implementation. Sharing +memory could save memory space, but it could also change the training logic and +thus affects the convergence rate. + +Each worker (thread) has a PMWorker (abbr for parameter management on workers) +object, e.g., pmw1, pmw2, which calls the Get/Put/Update functions to get +parameters, put parameters and update parameters. These functions may send +requests to servers that use PMServer (abbr for parameter management on +servers), e.g., pms1, pms2, to handle these requests. + +## Physical Architecture + +In this section, we describe how to configure Singa to generalize the logical +architecture to the physical architectures of existing systems, e.g., Caffe and +Baidu's DeepImage, Google Brain and Microsoft Adam. The architecture +configuration includes: + + * Number of worker threads per worker group and per process, which decides + the partitioning of worker side ParamShard + + * Number of server threads per server group and per process, which decides + the partitioning of server side ParamShard + + * Separation of servers and workers in different processes + + * Number of worker groups per server group + + * Topology of server groups, e.g., ring, tree, fully connected, etc. + +We put automatic optimization of the configuration as a future feature. + +### No Partition of ParamShard + +<figure> +<img src="{{ BASE_PATH }}/assets/image/arch/arch1.png" align="center" width="550px"/> +<figcaption><strong> Fig.2 - Physical system architecture without partitioning +ParamShard</strong></figcaption> +</figure> + +Fig.2 shows the architecture by configuring three threads per worker group, two +threads per server group, two worker groups and one server group per process. +Worker threads and server threads run as sub-threads. The main thread runs a +loop as a stub to forward messages. For instance, the Get/Put/Update requests +from workers are forwarded to the local servers, while Sync requests from the +local servers are forwarded to remote servers. In this architecture, every +group is fully contained in one process, hence the ParamShard objects is not +partitioned. If the ParamShards within one process share the same memory space +for parameter values, the training procedure then follows +[Hogwild](http://i.stanford.edu/hazy/hazy/victor/Hogwild/). If we only +launch process 1, Singa then runs in standalone mode. If we launch multiple +processes, we can connect the server groups to form different topologies, +e.g., ring or tree. Synchronization is conducted via inter-process +communication between neighboring server groups. In +[Caffe's](http://caffe.berkeleyvision.org/) parallel training architecture, +processes are arranged into a ring. Caffe luanches one thread per model +replica, hence it only supports data parallelism. Singa can also support +model parallelism by partition the model replica among multiple worker +threads within one group. + +### Partition Server Side ParamShard + +<figure> +<img src="{{ BASE_PATH }}/assets/image/arch/arch2.png" align="center" width="550px"/> +<figcaption><strong> Fig.3 - Physical system architecture, partitioning +server ParamShard</strong></figcaption> +</figure> + +Fig.3 shows another physical architecture by configuring one worker group per +process, and two processes per server group. Because the server group spans two +processes, the ParamShard of the server group is partitioned across the two +processes. We only show one server groups in the figure. The vertical lines +represent inter-process communication to synchronize server groups if there +are multiple server groups. In process 1, if the update for a parameter that +residents in process 2, then the PMWorker's update request would be sent to +process 2 via inter-process communication. If the parameter is maintained by +process 1, then the update request is sent to pms2 directly via intra-process +communication. The processes for other requests are the same. Baidu's +[DeepImage](http://arxiv.org/abs/1501.02876) system uses one server group and +its ParamShard is partitioned across all processes. Consequently, the stub of each process is +connected with all other processes' stubs for updating parameters. Like Caffe, +it launches only one thread per worker group, thus only support data +parallelism. + +### Partition Worker Side ParamShard + +<figure> +<img src="{{ BASE_PATH }}/assets/image/arch/arch3.png" align="center" width="550px"/> +<figcaption><strong> Fig.4 - Physical system architecture, partitioning +worker ParamShard</strong></figcaption> +</figure> + +The main difference of the architectures in Fig.4 and Fig.3 is that the worker +group is partitioned over two processes in Fig.4. Consequently, the ParamShard +is partitioned across process 1 and process 2. There are two kinds of +parameters to consider: + + * unique parameter: this kind of parameter exists in only one of the + partitioned ParamShards (due to model partition), and is updated by one + worker in its host process. Hence the update is conducted similar to that in + Fig.2. + + * replicated parameter: this kind of parameter is replicated in all + ParamShards (due to data partition), and its update is the aggregation of + updates from all workers. The aggregation is processed as follows. First the + first process is selected as the leader process. (Update/Get/Put) requests of + PMWorkers on other processes are aggregated locally and then forwarded to the + leader process which handles it in the main thread. *The main thread of the + leader process creates a PMWorker over the ParamShard it owns. It handles + the request by calling the correspondingly functions, e.g., Update/Get/Put(). + The responses from the servers are sent to the first worker of all sub ParamShards.* + +### Workers and Servers in Different Processes + +<figure> +<img src="{{ BASE_PATH }}/assets/image/arch/arch4.png" align="center" width="550px"/> +<figcaption><strong> Fig.5 - Physical system architecture, separating workers +and servers</strong></figcaption> +</figure> + +Fig.5 shows an architecture similar to that in Fig.4 except that the servers +and workers are separated into different processes. Consequently all requests +are sent via inter-process communication and handled by remote servers. More +details on this architecture are explained in +[Worker-Server Architecture]({{ BASE_PATH }}{% post_url /docs/2015-03-20-parameter-management %}). This is +the architecture used by Google's Brain and Microsoft's Adam system. It is also +called the Downpour architecture. + +## Conclusion + +We have shown that Singa's architecture is general enough +to unify the architectures of existing distributed training systems. +Since the rest architectures can be derived similarly as the above four by +setting different architecture configurations, we do not numerate them here.
