├── .gitignore ├── Rakefile ├── render.rb ├── schedule.yml ├── index.haml ├── day0.json ├── day1.json └── day2.json /.gitignore: -------------------------------------------------------------------------------- 1 | /.cache 2 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | desc "build static files" 2 | task :build do 3 | system "ruby render.rb > index.html" 4 | end 5 | 6 | desc "refresh JSON files" 7 | task :json do 8 | system "curl", "-s", "-o", "day0.json", "http://yapcasia.org/2015/talk/schedule?format=json&date=2015-08-20" 9 | system "curl", "-s", "-o", "day1.json", "http://yapcasia.org/2015/talk/schedule?format=json&date=2015-08-21" 10 | system "curl", "-s", "-o", "day2.json", "http://yapcasia.org/2015/talk/schedule?format=json&date=2015-08-22" 11 | end 12 | -------------------------------------------------------------------------------- /render.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # coding: utf-8 3 | require 'haml' 4 | require 'yaml' 5 | require 'nokogiri' 6 | require 'open-uri' 7 | require 'json' 8 | require 'uri' 9 | require 'open_uri_redirections' 10 | require 'time' 11 | require 'active_support/cache' 12 | 13 | def tweak_image(url) 14 | case url 15 | when /twimg\.com/ 16 | url.sub(/_normal\./, '_bigger.') 17 | when /graph\.facebook\.com/ 18 | url + '?type=square&width=240' 19 | else 20 | url 21 | end 22 | end 23 | 24 | def ucfirst(txt) 25 | txt.sub(/^(\w)/, &:capitalize) 26 | end 27 | 28 | def gcal_link(talk) 29 | start = Time.parse(talk["start_on"] + " +0900") 30 | finish = start + talk["duration"].to_i * 60 31 | 32 | uri = URI("https://www.google.com/calendar/event") 33 | uri.query = URI.encode_www_form( 34 | action: "TEMPLATE", 35 | text: (talk["title"] || talk["title_en"]) + " - " + talk["speaker"]["name"], 36 | dates: start.utc.strftime('%Y%m%dT%H%M%SZ') + '/' + finish.utc.strftime('%Y%m%dT%H%M%SZ'), 37 | location: talk["venue"], 38 | ) 39 | uri 40 | end 41 | 42 | def oembed(url) 43 | cache = ActiveSupport::Cache::FileStore.new('.cache', expires_in: 1.day) 44 | cache.fetch("oembed:#{url}") do 45 | JSON.parse(open(url, allow_redirections: :safe).read)["html"] 46 | end 47 | end 48 | 49 | def embed(url) 50 | case url 51 | when /slideshare/ 52 | oembed("http://www.slideshare.net/api/oembed/2?url=#{URI.encode_www_form_component url}&maxwidth=600&format=json") 53 | when /speakerdeck\.com\// 54 | oembed("http://speakerdeck.com/oembed.json?url=#{URI.encode_www_form_component url}&maxwidth=600") 55 | when /docs\.google\.com\/presentation\/d\/(.*?)\/(pub|mobile)/ 56 | %Q() 57 | when /drive\.google\.com\/open\?id=(.*)/ 58 | %Q() 59 | when nil 60 | nil 61 | else 62 | %Q() 63 | end 64 | end 65 | 66 | def get_talk_details(talk) 67 | { 68 | "id" => talk["id"], 69 | "title" => talk["title"] || talk["title_en"], 70 | "title_en" => talk["title_en"], 71 | "avatar" => tweak_image(talk["speaker"]["profile_image_url"]), 72 | "speaker" => talk["speaker"]["name"], 73 | "nickname" => talk["speaker"]["nickname"], 74 | "description" => talk["abstract_html"], 75 | "labels" => [ ucfirst(talk["category"]), ucfirst(talk["material_level"]) ], 76 | "duration" => talk["duration"], 77 | "language" => talk["language"] == "ja" ? "Japanese" : "English", 78 | "gcal" => gcal_link(talk), 79 | "video_url" => talk["video_url"], 80 | "presentation" => embed(talk["slide_url"]), 81 | } 82 | end 83 | 84 | schedule = YAML.load(File.read("schedule.yml")) 85 | 86 | talk_data = {} 87 | %W[day0 day1 day2].each do |file| 88 | data = JSON.parse(File.read("#{file}.json")) 89 | data["talks_by_venue"].each do |venue_talks| 90 | venue_talks.each do |talk| 91 | talk_data[talk["id"]] = talk.merge("venue" => data["venue_id2name"][talk["venue_id"]]) 92 | end 93 | end 94 | end 95 | 96 | schedule.each do |event| 97 | event["slots"].each do |slot| 98 | slot["hour"] = [slot["hour"]].flatten 99 | slot["talks"] = slot["talks"].map { |talks| 100 | [talks].flatten.map {|talk_id| 101 | if talk_id 102 | get_talk_details(talk_data[talk_id]) 103 | else 104 | nil 105 | end 106 | } 107 | } 108 | end 109 | end 110 | 111 | engine = Haml::Engine.new(File.read("index.haml")) 112 | puts engine.render(binding) 113 | -------------------------------------------------------------------------------- /schedule.yml: -------------------------------------------------------------------------------- 1 | - date: 8/20 2 | rooms: 3 | - Track D (605-606) 4 | - Track E (607-608) 5 | slots: 6 | - hour: "19:00" 7 | talks: 8 | - b355fa20-122e-11e5-8ba5-d9f87d574c3a 9 | - 621948f2-0d46-11e5-a403-67dc7d574c3a 10 | dur: 30 11 | - hour: "19:40" 12 | talks: 13 | - 39a72c04-10e3-11e5-b8ab-d7f07d574c3a 14 | - f5aa5054-12fd-11e5-b4c9-d9f87d574c3a 15 | dur: 30 16 | - hour: "20:20" 17 | talks: 18 | - 5f5cad74-004a-11e5-acf4-89c77d574c3a 19 | - 7d62caf8-12f4-11e5-881c-d9f87d574c3a 20 | dur: 30 21 | - date: 8/21 22 | rooms: 23 | - Track A Hall 24 | - Track B (701-702) 25 | - Track C (703) 26 | - Track D (605-606) 27 | - Track E (607-608) 28 | slots: 29 | - hour: "9:45" 30 | talks: 31 | - 1ffa6f7a-f5e8-11e4-a4ec-49b37d574c3a 32 | dur: 30 33 | - hour: "10:00" 34 | talks: 35 | - a636430c-0fbf-11e5-8a02-43ec7d574c3a 36 | - hour: ["11:10","11:40"] 37 | talks: 38 | - e19fe827-13c1-11e5-aca1-525412004261 39 | - [f283a924-fddc-11e4-90cd-bdc07d574c3a, e8eebd70-f906-11e4-8f91-8ab37d574c3a] 40 | - 44721562-10e4-11e5-88a0-d7f07d574c3a 41 | - 4bab2728-00fa-11e5-9931-79c97d574c3a 42 | - 9ec2791c-05e5-11e5-81fa-79c97d574c3a 43 | - hour: "13:10" 44 | talks: 45 | - cc0ec485-1879-11e5-aca1-525412004261 46 | - 94051590-fb11-11e4-a39d-8ab37d574c3a 47 | - a668ef3e-080b-11e5-b2b4-79c97d574c3a 48 | - dead6890-09b7-11e5-998a-67dc7d574c3a 49 | - b335dee0-09ad-11e5-8d7a-67dc7d574c3a 50 | - hour: "14:20" 51 | talks: 52 | - a06d9970-0d7b-11e5-aaf9-67dc7d574c3a 53 | - c61a32a4-f797-11e4-bcef-8ab37d574c3a 54 | - 9f7059dc-003c-11e5-a00c-89c77d574c3a 55 | - e14c5ae0-12f7-11e5-a909-d9f87d574c3a 56 | - de9e7a1e-136d-11e5-a9fc-d9f87d574c3a 57 | - hour: ["15:30","16:00"] 58 | talks: 59 | - [7d66b640-0a6b-11e5-b1a0-67dc7d574c3a, c191c08a-0a98-11e5-be34-67dc7d574c3a] 60 | - [bb82c8fc-12a3-11e5-962e-d9f87d574c3a, b396e912-091a-11e5-8d2d-67dc7d574c3a] 61 | - [1da55daa-0deb-11e5-944c-67dc7d574c3a, 53944d48-09ba-11e5-998a-67dc7d574c3a] 62 | - 523b9508-0d77-11e5-8174-67dc7d574c3a 63 | - cf39f7fc-ff44-11e4-9264-66c47d574c3a 64 | - hour: "16:40" 65 | talks: 66 | - 22957e9c-1872-11e5-aca1-525412004261 67 | 68 | - date: 8/22 69 | rooms: 70 | - Track A Hall 71 | - Track B (701-702) 72 | - Track C (703) 73 | - Track D (605-606) 74 | - Track E (607-608) 75 | slots: 76 | - hour: "10:00" 77 | talks: 78 | - 21cb8176-065b-11e5-9492-79c97d574c3a 79 | - 82e93a96-f60e-11e4-907e-8ab37d574c3a 80 | - 5b1cd536-07ed-11e5-9e42-79c97d574c3a 81 | - c5ea5428-fac9-11e4-88c1-8ab37d574c3a 82 | - 86ebd212-fab3-11e4-8f5a-8ab37d574c3a 83 | - hour: ["11:10","11:40"] 84 | talks: 85 | - 3fe49c10-fa67-11e4-9e02-8ab37d574c3a 86 | - [93eaf068-faec-11e4-a8fd-8ab37d574c3a,5ea2630a-133d-11e5-8cbb-d9f87d574c3a] 87 | - c2c7b8a4-faaa-11e4-a8be-8ab37d574c3a 88 | - [f2816038-10ec-11e5-89bf-d7f07d574c3a, 0af26fe4-0b7b-11e5-a29c-67dc7d574c3a] 89 | - 39a15ad4-0ff5-11e5-a984-d7f07d574c3a 90 | - hour: "12:20" 91 | talks: 92 | - 93 | - e46f9d1b-2ad1-11e5-aca1-525412004261 94 | - e34fca9d-2ad1-11e5-aca1-525412004261 95 | - hour: "13:10" 96 | talks: 97 | - bd04b86c-f9de-11e4-b996-8ab37d574c3a 98 | - a4318242-f5f2-11e4-afb7-49b37d574c3a 99 | - 268d730e-136c-11e5-ac8f-d9f87d574c3a 100 | - dd8ce20e-fad2-11e4-b6e7-8ab37d574c3a 101 | - 4f85e87a-f9ec-11e4-8262-8ab37d574c3a 102 | - hour: ["14:20","14:50"] 103 | talks: 104 | - 22f59fb8-0fad-11e5-98ef-43ec7d574c3a 105 | - [5ceebdcc-136c-11e5-a014-d9f87d574c3a, 897abeb2-1007-11e5-a760-d7f07d574c3a] 106 | - [e466d60a-11db-11e5-b07b-d7f07d574c3a, b03162be-0052-11e5-ba92-89c77d574c3a] 107 | - ad57ca84-13e9-11e5-aca1-525412004261 108 | - 32a684e8-fd21-11e4-94eb-bdc07d574c3a 109 | - hour: ["15:30","16:00"] 110 | talks: 111 | - 6bde6c69-187a-11e5-aca1-525412004261 112 | - [92a7bb60-1323-11e5-a252-d9f87d574c3a, 81342dae-1351-11e5-ab94-d9f87d574c3a] 113 | - 0b669ad8-f616-11e4-90fb-8ab37d574c3a 114 | - 9e9ae188-fb20-11e4-9a97-8ab37d574c3a 115 | - 53aacc02-faca-11e4-8c2e-8ab37d574c3a 116 | - hour: "16:40" 117 | talks: 118 | - 69caedbd-1872-11e5-aca1-525412004261 119 | - hour: "17:50" 120 | talks: 121 | - 6964fd88-f5e8-11e4-b323-49b37d574c3a 122 | dur: 30 123 | -------------------------------------------------------------------------------- /index.haml: -------------------------------------------------------------------------------- 1 | !!! 5 2 | %html 3 | %title YAPC::Asia 2015 4 | %meta{name: "mobile-web-app-capable", content: "yes"} 5 | %link{rel: "icon", href: "http://yapcasia.org/2015/assets/images/header_logo.png"} 6 | %link{rel: "apple-touch-icon-precomposed", href: "http://yapcasia.org/2015/assets/images/header_logo.png"} 7 | %link{rel: "stylesheet", type: "text/css", class: "ui", href: "//oss.maxcdn.com/semantic-ui/2.0.8/semantic.min.css"} 8 | %script{type: "text/javascript", src: "//code.jquery.com/jquery-1.11.3.min.js"} 9 | %script{type: "text/javascript", src: "//oss.maxcdn.com/semantic-ui/2.0.8/semantic.min.js"} 10 | :css 11 | .talk-title { color: #000; font-weight: bold; } 12 | .talk { height: 12em } 13 | .talk-meta { color: #888 } 14 | .talk-materials { margin-top: 0.5em } 15 | .speaker { margin-top: 0.5em } 16 | .presentation { width: 600px; height: 600px } 17 | .embed iframe { width: 600px; height: 540px } 18 | :javascript 19 | jQuery(function(){ 20 | $('.talk-open').click(function(){ 21 | $("#modal-" + $(this).data('id')).modal({ 22 | duration: 100, 23 | transition: 'fade', 24 | onShow: function(){ $('.embed', this).each(function(){ $(this).html($(this).data('html')) }) }, 25 | onHide: function(){ history.replaceState({}, "", '#') } 26 | }).modal("show"); 27 | history.replaceState({}, "", '#' + $(this).data('id')); 28 | }); 29 | 30 | $('.rating').each(function(){ 31 | var value = localStorage.getItem("star-" + $(this).data('talk-id')); 32 | if (typeof(value) != 'undefined') { 33 | $(this).attr('data-rating', value); 34 | } 35 | }); 36 | 37 | $('.rating').rating({ 38 | onRate: function(value){ 39 | if (typeof(value) != 'undefined') { 40 | localStorage.setItem("star-" + $(this).data('talk-id'), value); 41 | } 42 | } 43 | }); 44 | 45 | if (navigator.language.match(/^en/)) { 46 | $('.translatable').each(function() { 47 | $(this).text($(this).data('en')); 48 | }); 49 | } 50 | 51 | if (location.hash) { 52 | $("#modal-" + location.hash.substring(1)).modal({ 53 | transition: 'fade', 54 | duration: 200, 55 | onShow: function(){ $('.embed', this).each(function(){ $(this).html($(this).data('html')) }) } 56 | }).modal("show"); 57 | } 58 | }); 59 | %body{style: "padding: 1em"} 60 | - schedule.each_with_index do |event, i| 61 | %h2.ui.header.aligned.center.horizontal.divider{id: "day-#{i}"} 62 | %i.icon.calendar 63 | = event["date"] 64 | .ui.grid.divided 65 | .row 66 | .one.wide.column 67 | - event["rooms"].each do |room| 68 | .three.wide.column.center.aligned 69 | %strong= room 70 | - event["slots"].each do |slot| 71 | .stretched.row 72 | .one.wide.column 73 | - slot["hour"].each do |hour| 74 | .ui.vertical.segment= hour 75 | - dur = slot["dur"] == 30 ? "30" : "60" 76 | - slot["talks"].each do |talks| 77 | .three.wide.column{class: "slot#{dur}"} 78 | - talks.each do |talk| 79 | - if talk 80 | .ui.modal{id: "modal-#{talk['id']}"} 81 | .header.translatable{data: {en: talk["title_en"]}}= talk["title"] 82 | .content 83 | .description 84 | .ui.header 85 | %img.ui.image.avatar{src: talk["avatar"], alt: talk["speaker"]} 86 | = talk["speaker"] 87 | - if talk["presentation"] 88 | .presentation 89 | .embed{data: {html: talk["presentation"]}} 90 | = talk["description"] 91 | .ui.tag.label= talk["language"] 92 | - talk["labels"].each do |label| 93 | .ui.tag.label= label 94 | .actions 95 | .ui.cancel.button Close 96 | .ui.vertical.segment.talk{id: talk["id"]} 97 | .item 98 | .content 99 | %a.talk-title.talk-open.translatable.header{data: {"id": talk["id"], "en": talk["title_en"]} }= talk["title"] 100 | .talk-meta 101 | = talk["language"] + ", " + talk["duration"] + " min" 102 | .ui.star.rating{data:{"max-rating": 1, "talk-id": talk['id']}} 103 | .talk-materials.talk-open{data:{id: talk["id"]}} 104 | - if talk["presentation"] 105 | .ui.label.tiny 106 | %i.icon.desktop 107 | Slides 108 | .description.speaker 109 | %img.ui.avatar.image{src: talk["avatar"]} 110 | = talk["speaker"] 111 | 112 | -------------------------------------------------------------------------------- /day0.json: -------------------------------------------------------------------------------- 1 | {"events_by_venue":[[],[],[],[],[],[]],"date":"2015-08-20","venue_id2name":{"5":"トラックE (607-608)","1":"トラックA 国際会議場","3":"トラックC (703)","4":"トラックD (605-606)","6":"レセプションホール 1F","2":"トラックB (701-702)"},"talks_by_venue":[[],[],[],[{"modified_on":"2015-06-14 09:45:49","memo":"本発表では、企業活動やソフトウェアの規模に関係なく、プログラマがOSSとどのように関わり、プログラミングという活動について改めて向き合う機会を提供することを第一目的としています。","abstract_html":"

インターネットの普及とともに、インターネットを支える主要技術の多くを構築する OSS はより一般的なものとなりました。特に Web サービスやモバイルアプリケーションを開発する会社にとっては、コードを書く上で避けては通れないものとなりました。<\/p>\n\n

OSS は小さいライブラリから、プロダクションで使用するようなフレームワーク、大規模なサービスを支えるミドルウェア、OS や言語のようなプログラミングの根幹とも言えるような要素など、ソフトウェアのコードベースの大小こそあるものの、それらは全て OSD<\/a> に準拠しているものであり、誰でもコードを読むことができ、ソフトウェアによってはコントリビュートすることも可能です。<\/p>\n\n

近年では GitHub の普及により、ライブラリやフレームワークについては身近なものとなりましたが、ミドルウェア、言語、OSについては GitHub を用いない開発スタイルも多く存在し、雲の上のような存在に感じるのではないかと思います。しかし、GitHub というツールの種類に関係なく、OSSというものはプログラマに身近なものです。<\/p>\n\n

本発表では、Ruby というプログラミング言語のメンテナという立場から、プログラミング言語を例としてどのように開発の意思決定を行い、実装し、リリースされるかまでの一連の流れを紹介し、言語開発の見えない部分について露わにしたいと思います。<\/p>\n","has_interpratation":"0","video_url":"https:\/\/www.youtube.com\/watch?v=vCL2OjEmBrM&index=1&list=PLzT643y4OYZp0K4YhPmmaLtnZzlVrbz0G","photo_permission":"allow","slide_url":"http:\/\/www.slideshare.net\/hsbt\/the-story-of-language-development","status":"accepted","id":"b355fa20-122e-11e5-8ba5-d9f87d574c3a","speaker":{"nickname":"hsbt","id":"8eab30ca-f9e0-11e4-a562-8ab37d574c3a","name":"SHIBATA Hiroshi","profile_image_url":"https:\/\/avatars.githubusercontent.com\/u\/12301?v=3"},"venue_id":"4","calendar_entry_id":null,"is_confirmed":"1","title":"言語開発の現場","language":"ja","tags":null,"video_permission":"allow","title_en":"The story of language development","abstract":"インターネットの普及とともに、インターネットを支える主要技術の多くを構築する OSS はより一般的なものとなりました。特に Web サービスやモバイルアプリケーションを開発する会社にとっては、コードを書く上で避けては通れないものとなりました。\r\n\r\nOSS は小さいライブラリから、プロダクションで使用するようなフレームワーク、大規模なサービスを支えるミドルウェア、OS や言語のようなプログラミングの根幹とも言えるような要素など、ソフトウェアのコードベースの大小こそあるものの、それらは全て [OSD](http:\/\/www.opensource.jp\/osd\/osd-japanese.html) に準拠しているものであり、誰でもコードを読むことができ、ソフトウェアによってはコントリビュートすることも可能です。\r\n\r\n近年では GitHub の普及により、ライブラリやフレームワークについては身近なものとなりましたが、ミドルウェア、言語、OSについては GitHub を用いない開発スタイルも多く存在し、雲の上のような存在に感じるのではないかと思います。しかし、GitHub というツールの種類に関係なく、OSSというものはプログラマに身近なものです。\r\n\r\n本発表では、Ruby というプログラミング言語のメンテナという立場から、プログラミング言語を例としてどのように開発の意思決定を行い、実装し、リリースされるかまでの一連の流れを紹介し、言語開発の見えない部分について露わにしたいと思います。","duration":"30","sort_order":"0","category":"tutorial","created_on":"2015-06-14 09:45:49","start_on":"2015-08-20 19:00:00","member_id":"8eab30ca-f9e0-11e4-a562-8ab37d574c3a","material_level":"regular","subtitles":"en"},{"id":"39a72c04-10e3-11e5-b8ab-d7f07d574c3a","status":"accepted","speaker":{"id":"8072fa70-fdd1-11e4-897e-bdc07d574c3a","profile_image_url":"http:\/\/graph.facebook.com\/929494707114841\/picture","name":"Akira Sakamoto","nickname":"Akira Sakamoto"},"venue_id":"4","slide_url":null,"memo":null,"abstract_html":"

Perlワンライナー便利です<\/h2>\n\n

たくさんの技術があるなかで、適切な場面で適切な技術を選択するのは大切です。\n自分が働いているフリークアウトはアドテクと呼ばれる業態です。Perlで業務を行っています。\n弊社の業務ではログファイルなどで何十万行程度のテキストファイルからアドホックにデータを抽出・加工するような業務が頻出します。\n自分はそういった場面ではPerlを選択するのが最善ではないかと思っています。<\/p>\n\n

pythonで5分かかる作業を30秒で書いたワンライナーがなんとかしてくれる様子は「Practical Extraction and Report Language(実用データ取得レポート作成言語)」の面目躍如といった趣があります。<\/p>\n\n

似た領域の技術にawkがありますが、かなりややこしいことまで出来るPerlワンライナーをおぼえておいても損はないはずです(-M<\/code>オプションもございます)<\/p>\n\n

内容<\/h2>\n\n

この発表ではperlワンライナー初心者を対象にしています。ハンズオンで下記内容でやるつもりです。<\/p>\n\n