type_pad_template 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +31 -0
- data/bin/type_pad_template +6 -0
- data/lib/type_pad_template.rb +15 -0
- data/lib/type_pad_template/account.rb +90 -0
- data/lib/type_pad_template/blog.rb +50 -0
- data/lib/type_pad_template/command.rb +117 -0
- data/lib/type_pad_template/form.rb +37 -0
- data/lib/type_pad_template/request.rb +65 -0
- data/lib/type_pad_template/response.rb +23 -0
- data/lib/type_pad_template/template.rb +77 -0
- data/lib/type_pad_template/version.rb +3 -0
- metadata +124 -0
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
TypePad Temlpate
|
2
|
+
================
|
3
|
+
|
4
|
+
This is gem and command interface to manipulate TypePad advanced templates from command line.
|
5
|
+
|
6
|
+
Usage
|
7
|
+
-----
|
8
|
+
|
9
|
+
Install gem which provides ``type_pad_template`` command.
|
10
|
+
|
11
|
+
gem install type_pad_template
|
12
|
+
|
13
|
+
To see the usage, use help command.
|
14
|
+
|
15
|
+
type_pad_template help
|
16
|
+
|
17
|
+
Download and upload templates
|
18
|
+
-----------------------------
|
19
|
+
|
20
|
+
First you need to login to typepad using your email address and password.
|
21
|
+
|
22
|
+
type_pad_template login -u 'your-email@address'
|
23
|
+
|
24
|
+
Then list blogs on your account to get a blog id.
|
25
|
+
|
26
|
+
type_pad_template blogs
|
27
|
+
|
28
|
+
To download, upload templates, use each command with ``-b`` option.
|
29
|
+
|
30
|
+
type_pad_template download -b 'your-blog-id'
|
31
|
+
type_pad_template upload -b 'your-blog-id'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "type_pad_template/version"
|
2
|
+
require "nokogiri"
|
3
|
+
require "typhoeus"
|
4
|
+
require "uri"
|
5
|
+
require "forwardable"
|
6
|
+
|
7
|
+
module TypePadTemplate
|
8
|
+
autoload :Command, "type_pad_template/command"
|
9
|
+
autoload :Form, "type_pad_template/form"
|
10
|
+
autoload :Request, "type_pad_template/request"
|
11
|
+
autoload :Response, "type_pad_template/response"
|
12
|
+
autoload :Account, "type_pad_template/account"
|
13
|
+
autoload :Blog, "type_pad_template/blog"
|
14
|
+
autoload :Template, "type_pad_template/template"
|
15
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module TypePadTemplate
|
2
|
+
class Account
|
3
|
+
def self.login(username, password)
|
4
|
+
account = new.tap do |a|
|
5
|
+
a.login(username, password)
|
6
|
+
end
|
7
|
+
|
8
|
+
account if account.logged_in?
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :login_cookies
|
12
|
+
|
13
|
+
def initialize(login_cookies = nil)
|
14
|
+
@login_cookies = login_cookies
|
15
|
+
end
|
16
|
+
|
17
|
+
def login(username, password)
|
18
|
+
form_element = Request.new("/secure/services/signin", :ssl => true).
|
19
|
+
dispatch.
|
20
|
+
response.
|
21
|
+
doc.
|
22
|
+
at("//form[@id='signin-form-typepad']")
|
23
|
+
|
24
|
+
form = Form.new(form_element).tap do |f|
|
25
|
+
f[:username] = username
|
26
|
+
f[:password] = password
|
27
|
+
end
|
28
|
+
|
29
|
+
@login_cookies = Request.new("/secure/services/signin/save", {
|
30
|
+
:ssl => true,
|
31
|
+
:method => :post,
|
32
|
+
:params => form.to_hash
|
33
|
+
}).
|
34
|
+
dispatch.
|
35
|
+
response.
|
36
|
+
cookies
|
37
|
+
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def blogs
|
42
|
+
return [] unless logged_in?
|
43
|
+
|
44
|
+
request("/dashboard") do |response|
|
45
|
+
response.
|
46
|
+
doc.
|
47
|
+
search("//ul[@id='blogs-list']//a[@class='blog-name']").
|
48
|
+
map do |element|
|
49
|
+
if %r{/([0-9a-f]+)/dashboard$} === element["href"]
|
50
|
+
id = $1
|
51
|
+
Blog.new(self, id, element.text)
|
52
|
+
end
|
53
|
+
end.
|
54
|
+
compact
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def logged_in?
|
59
|
+
!@login_cookies.empty?
|
60
|
+
end
|
61
|
+
|
62
|
+
def request(path, options = {})
|
63
|
+
# FIXME raise a proper exception instead.
|
64
|
+
return nil unless logged_in?
|
65
|
+
|
66
|
+
request = Request.new(path, merge_login_cookie_header(options))
|
67
|
+
|
68
|
+
if block_given?
|
69
|
+
yield request.
|
70
|
+
dispatch.
|
71
|
+
response
|
72
|
+
else
|
73
|
+
request
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def merge_login_cookie_header(options)
|
80
|
+
options.dup.tap do |options|
|
81
|
+
headers = options[:headers] ||= {}
|
82
|
+
headers["Cookie"] = [login_cookies_string, headers["Cookie"]].compact.join("; ")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def login_cookies_string
|
87
|
+
@login_cookies.map{|key, value| "#{key}=#{value}"}.join("; ")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module TypePadTemplate
|
2
|
+
class Blog
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def_delegator :account, :request
|
6
|
+
|
7
|
+
attr_reader :account, :blog_id, :name
|
8
|
+
|
9
|
+
def initialize(account, blog_id, name)
|
10
|
+
@account = account
|
11
|
+
@blog_id = blog_id
|
12
|
+
@name = name
|
13
|
+
end
|
14
|
+
|
15
|
+
def templates
|
16
|
+
return [] unless design_id = current_design_id
|
17
|
+
|
18
|
+
request("/site/blogs/#{@blog_id}/design/#{design_id}/templates") do |response|
|
19
|
+
response.
|
20
|
+
doc.
|
21
|
+
search("//td[@class='index-templates' or @class='archive-templates' or @class='template-modules']/a[@class='link']").
|
22
|
+
map do |element|
|
23
|
+
name = element.text
|
24
|
+
|
25
|
+
output_file_element = element.at("../..//td[@class='output-file']")
|
26
|
+
|
27
|
+
filename = if output_file_element
|
28
|
+
output_file_element.text
|
29
|
+
else
|
30
|
+
"#{name.downcase.gsub(/[\- ]/, "_")}.template"
|
31
|
+
end
|
32
|
+
|
33
|
+
Template.new(self, name, filename, element["href"])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def current_design_id
|
41
|
+
request("/site/blogs/#{@blog_id}/design") do |response|
|
42
|
+
response.
|
43
|
+
doc.
|
44
|
+
css(".design-current .design-actions a").find do |a|
|
45
|
+
%r{/([0-9a-f]+)/templates$} === a["href"]
|
46
|
+
end and $1
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "yaml"
|
3
|
+
require "highline"
|
4
|
+
|
5
|
+
module TypePadTemplate
|
6
|
+
SESSION_FILE = File.expand_path("~/.type_pad_template_session")
|
7
|
+
|
8
|
+
class Command < Thor
|
9
|
+
def self.blog_id_option
|
10
|
+
method_option(:blog_id, {
|
11
|
+
:type => :string,
|
12
|
+
:aliases => "-b",
|
13
|
+
:required => true,
|
14
|
+
:desc => "Blog ID which blogs command shows"
|
15
|
+
})
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.directory_option
|
19
|
+
method_option(:directory, {
|
20
|
+
:type => :string,
|
21
|
+
:aliases => "-d",
|
22
|
+
:desc => "Path to templates directory"
|
23
|
+
})
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.pattern_option
|
27
|
+
method_option(:pattern, {
|
28
|
+
:type => :string,
|
29
|
+
:aliases => "-p",
|
30
|
+
:desc => "Pattern to select templates"
|
31
|
+
})
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "login", "Login to TypePad"
|
35
|
+
method_option :username, :type => :string, :aliases => "-u", :desc => "Login email address"
|
36
|
+
method_option :password, :type => :string, :aliases => "-p", :desc => "Password"
|
37
|
+
def login
|
38
|
+
username = options[:username] || highline.ask("Enter login email address: ")
|
39
|
+
password = options[:password] || highline.ask("Enter password: "){|q| q.echo = false }
|
40
|
+
|
41
|
+
account = Account.login(username, password)
|
42
|
+
|
43
|
+
File.open(SESSION_FILE, "w") do |file|
|
44
|
+
YAML.dump(account.login_cookies, file)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "logout", "Logout from TypePad"
|
49
|
+
def logout
|
50
|
+
File.unlink(SESSION_FILE)
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "blogs", "List current blogs"
|
54
|
+
def blogs
|
55
|
+
print_table account.blogs.map{|blog| [blog.blog_id, blog.name]}
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "templates", "List current templates"
|
59
|
+
blog_id_option
|
60
|
+
def templates
|
61
|
+
print_table blog.templates.map{|template| [template.filename, template.name]}
|
62
|
+
end
|
63
|
+
|
64
|
+
desc "download", "Download templates from TypePad"
|
65
|
+
blog_id_option
|
66
|
+
directory_option
|
67
|
+
pattern_option
|
68
|
+
def download(filenames = nil)
|
69
|
+
pattern_select(blog.templates).each do |template|
|
70
|
+
template.enqueue_get do |text|
|
71
|
+
say "Downloaded #{template.filename}"
|
72
|
+
File.open(File.join(directory, template.filename), "w"){|f| f.write(text)}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
Request.dispatch
|
76
|
+
end
|
77
|
+
|
78
|
+
desc "upload", "Upload templates from local"
|
79
|
+
blog_id_option
|
80
|
+
directory_option
|
81
|
+
pattern_option
|
82
|
+
def upload
|
83
|
+
pattern_select(blog.templates).each do |template|
|
84
|
+
path = File.join(directory, template.filename)
|
85
|
+
template.enqueue_post(File.read(path)) do |response|
|
86
|
+
say "Uploaded #{template.filename}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
Request.dispatch
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def account
|
95
|
+
@account ||= Account.new(YAML.load(File.read(SESSION_FILE)))
|
96
|
+
end
|
97
|
+
|
98
|
+
def blog
|
99
|
+
@blog ||= account.blogs.find{|blog| blog.blog_id == options[:blog_id]}
|
100
|
+
end
|
101
|
+
|
102
|
+
def directory
|
103
|
+
@directory ||= File.expand_path(options[:directory] || Dir.pwd)
|
104
|
+
end
|
105
|
+
|
106
|
+
def pattern_select(list)
|
107
|
+
return list unless options[:pattern]
|
108
|
+
list.select do |item|
|
109
|
+
File.fnmatch(options[:pattern], item.filename)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def highline
|
114
|
+
@highline ||= HighLine.new
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module TypePadTemplate
|
2
|
+
class Form
|
3
|
+
def initialize(form_element)
|
4
|
+
@form_element = form_element
|
5
|
+
@values = default_values
|
6
|
+
end
|
7
|
+
|
8
|
+
def [](key)
|
9
|
+
@values[key.to_sym]
|
10
|
+
end
|
11
|
+
|
12
|
+
def []=(key, value)
|
13
|
+
@values[key.to_sym] = value
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_hash
|
17
|
+
@values.dup
|
18
|
+
end
|
19
|
+
|
20
|
+
def method
|
21
|
+
@form_element["method"].downcase.to_sym rescue :get
|
22
|
+
end
|
23
|
+
|
24
|
+
def url
|
25
|
+
@form_element["action"]
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def default_values
|
31
|
+
@form_element.search("input[@name!='']").inject({}) do |hash, input|
|
32
|
+
hash[input["name"].to_sym] = input["value"] if input["name"]
|
33
|
+
hash
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module TypePadTemplate
|
2
|
+
class Request
|
3
|
+
DEFAULT_HOST_NAME = "www.typepad.com"
|
4
|
+
MAX_CONCURRENCY = 10
|
5
|
+
|
6
|
+
def self.dispatch
|
7
|
+
hydra.run
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.hydra
|
11
|
+
@@hydra ||= Typhoeus::Hydra.new(:max_concurrency => MAX_CONCURRENCY)
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(url_or_path, options = {})
|
15
|
+
@url_or_path = url_or_path
|
16
|
+
@options = options
|
17
|
+
end
|
18
|
+
|
19
|
+
def enqueue(&block)
|
20
|
+
request.on_complete = lambda do |response|
|
21
|
+
block.call(Response.new(response))
|
22
|
+
end
|
23
|
+
self.class.hydra.queue(request)
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def dispatch
|
28
|
+
hydra = Typhoeus::Hydra.new
|
29
|
+
hydra.queue(request)
|
30
|
+
hydra.run
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def response
|
35
|
+
@response ||= Response.new(request.response) if request.response
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def ssl?
|
41
|
+
@options[:ssl]
|
42
|
+
end
|
43
|
+
|
44
|
+
def protocol
|
45
|
+
ssl? ? "https" : "http"
|
46
|
+
end
|
47
|
+
|
48
|
+
def url
|
49
|
+
@url ||= begin
|
50
|
+
uri = URI.parse(@url_or_path)
|
51
|
+
unless uri.scheme
|
52
|
+
"#{protocol}://#{DEFAULT_HOST_NAME}#{uri.path}"
|
53
|
+
else
|
54
|
+
uri.to_s
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def request
|
60
|
+
@request ||= Typhoeus::Request.new(url, @options.merge({
|
61
|
+
:disable_ssl_peer_verification => ssl?
|
62
|
+
}))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module TypePadTemplate
|
2
|
+
class Response
|
3
|
+
def initialize(response)
|
4
|
+
@response = response
|
5
|
+
end
|
6
|
+
|
7
|
+
def successful?
|
8
|
+
@response.code == 200
|
9
|
+
end
|
10
|
+
|
11
|
+
def cookies
|
12
|
+
@cokies ||= Array(@response.headers_hash["Set-Cookie"]).inject({}) do |hash, cookie|
|
13
|
+
key, value = cookie.split(/;/, 2).first.split(/=/, 2)
|
14
|
+
hash[key] = value
|
15
|
+
hash
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def doc
|
20
|
+
@doc ||= Nokogiri::HTML.parse(@response.body)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module TypePadTemplate
|
2
|
+
class Template
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def_delegator :blog, :request
|
6
|
+
|
7
|
+
attr_reader :blog, :name, :filename, :url, :text
|
8
|
+
|
9
|
+
def initialize(blog, name, filename, edit_url)
|
10
|
+
@blog = blog
|
11
|
+
@name = name
|
12
|
+
@filename = filename
|
13
|
+
@edit_path = URI.parse(edit_url).path
|
14
|
+
end
|
15
|
+
|
16
|
+
def enqueue_get(&block)
|
17
|
+
request(@edit_path).enqueue do |response|
|
18
|
+
@text = get_text_from_response(response)
|
19
|
+
block.call(text)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def get
|
24
|
+
request(@edit_path) do |response|
|
25
|
+
@text = get_text_from_response(response)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def enqueue_post(text, &block)
|
30
|
+
request(@edit_path).enqueue do |response|
|
31
|
+
form = get_form_for_body(response).tap do |f|
|
32
|
+
f[:text] = text
|
33
|
+
end
|
34
|
+
request_for_form(form).enqueue do |response|
|
35
|
+
@text = text
|
36
|
+
block.call(response)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def post(text)
|
42
|
+
request(@edit_path) do |response|
|
43
|
+
form = get_form_for_body(response).tap do |f|
|
44
|
+
f[:text] = text
|
45
|
+
end
|
46
|
+
|
47
|
+
response = request_for_form(form).dispatch.response
|
48
|
+
@text = text
|
49
|
+
|
50
|
+
response
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def get_form_for_body(response)
|
57
|
+
Form.new(response.
|
58
|
+
doc.
|
59
|
+
at("form[@id='template-form']"))
|
60
|
+
end
|
61
|
+
|
62
|
+
def get_text_from_response(response)
|
63
|
+
response.
|
64
|
+
doc.
|
65
|
+
at("//form[@id='template-form']//textarea[@name='text']").
|
66
|
+
text
|
67
|
+
end
|
68
|
+
|
69
|
+
# FIXME make this works in Form.
|
70
|
+
def request_for_form(form)
|
71
|
+
request(form.url, {
|
72
|
+
:method => form.method,
|
73
|
+
:params => form.to_hash
|
74
|
+
})
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: type_pad_template
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Yoshimasa Niwa
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-08 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: typhoeus
|
16
|
+
requirement: &70329624589040 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70329624589040
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: nokogiri
|
27
|
+
requirement: &70329624588600 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70329624588600
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: thor
|
38
|
+
requirement: &70329624588060 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70329624588060
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: highline
|
49
|
+
requirement: &70329624587140 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70329624587140
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: bundler
|
60
|
+
requirement: &70329624586680 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70329624586680
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: &70329624586140 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70329624586140
|
80
|
+
description: ''
|
81
|
+
email:
|
82
|
+
- niw@niw.at
|
83
|
+
executables:
|
84
|
+
- type_pad_template
|
85
|
+
extensions: []
|
86
|
+
extra_rdoc_files:
|
87
|
+
- README.md
|
88
|
+
files:
|
89
|
+
- bin/type_pad_template
|
90
|
+
- lib/type_pad_template.rb
|
91
|
+
- lib/type_pad_template/account.rb
|
92
|
+
- lib/type_pad_template/blog.rb
|
93
|
+
- lib/type_pad_template/command.rb
|
94
|
+
- lib/type_pad_template/form.rb
|
95
|
+
- lib/type_pad_template/request.rb
|
96
|
+
- lib/type_pad_template/response.rb
|
97
|
+
- lib/type_pad_template/template.rb
|
98
|
+
- lib/type_pad_template/version.rb
|
99
|
+
- README.md
|
100
|
+
homepage: http://niw.at/
|
101
|
+
licenses: []
|
102
|
+
post_install_message:
|
103
|
+
rdoc_options: []
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ! '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
requirements: []
|
119
|
+
rubyforge_project: type_pad_template
|
120
|
+
rubygems_version: 1.8.11
|
121
|
+
signing_key:
|
122
|
+
specification_version: 3
|
123
|
+
summary: ''
|
124
|
+
test_files: []
|