dreadpiratepj-poolparty 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +12 -0
- data/Manifest +115 -0
- data/README.txt +140 -0
- data/Rakefile +27 -0
- data/bin/instance +61 -0
- data/bin/pool +62 -0
- data/config/cloud_master_takeover +17 -0
- data/config/create_proxy_ami.sh +582 -0
- data/config/haproxy.conf +29 -0
- data/config/heartbeat.conf +8 -0
- data/config/heartbeat_authkeys.conf +2 -0
- data/config/installers/ubuntu_install.sh +77 -0
- data/config/monit.conf +9 -0
- data/config/monit/haproxy.monit.conf +7 -0
- data/config/monit/nginx.monit.conf +0 -0
- data/config/nginx.conf +24 -0
- data/config/reconfigure_instances_script.sh +18 -0
- data/config/sample-config.yml +23 -0
- data/config/scp_instances_script.sh +12 -0
- data/lib/core/array.rb +13 -0
- data/lib/core/exception.rb +9 -0
- data/lib/core/float.rb +13 -0
- data/lib/core/hash.rb +11 -0
- data/lib/core/kernel.rb +12 -0
- data/lib/core/module.rb +22 -0
- data/lib/core/object.rb +18 -0
- data/lib/core/proc.rb +15 -0
- data/lib/core/string.rb +49 -0
- data/lib/core/time.rb +41 -0
- data/lib/modules/callback.rb +133 -0
- data/lib/modules/ec2_wrapper.rb +82 -0
- data/lib/modules/safe_instance.rb +31 -0
- data/lib/modules/vlad_override.rb +82 -0
- data/lib/poolparty.rb +105 -0
- data/lib/poolparty/application.rb +170 -0
- data/lib/poolparty/init.rb +6 -0
- data/lib/poolparty/master.rb +329 -0
- data/lib/poolparty/monitors.rb +13 -0
- data/lib/poolparty/monitors/cpu.rb +19 -0
- data/lib/poolparty/monitors/memory.rb +26 -0
- data/lib/poolparty/monitors/web.rb +23 -0
- data/lib/poolparty/optioner.rb +16 -0
- data/lib/poolparty/plugin.rb +43 -0
- data/lib/poolparty/plugin_manager.rb +67 -0
- data/lib/poolparty/provider.rb +2 -0
- data/lib/poolparty/provider/packages/essential.rb +6 -0
- data/lib/poolparty/provider/packages/git.rb +4 -0
- data/lib/poolparty/provider/packages/haproxy.rb +20 -0
- data/lib/poolparty/provider/packages/heartbeat.rb +4 -0
- data/lib/poolparty/provider/packages/monit.rb +6 -0
- data/lib/poolparty/provider/packages/rsync.rb +4 -0
- data/lib/poolparty/provider/packages/ruby.rb +37 -0
- data/lib/poolparty/provider/packages/s3fuse.rb +11 -0
- data/lib/poolparty/provider/provider.rb +60 -0
- data/lib/poolparty/remote_instance.rb +216 -0
- data/lib/poolparty/remoter.rb +106 -0
- data/lib/poolparty/remoting.rb +112 -0
- data/lib/poolparty/scheduler.rb +103 -0
- data/lib/poolparty/tasks.rb +29 -0
- data/lib/poolparty/tasks/cloud.rake +57 -0
- data/lib/poolparty/tasks/development.rake +38 -0
- data/lib/poolparty/tasks/ec2.rake +20 -0
- data/lib/poolparty/tasks/instance.rake +63 -0
- data/lib/poolparty/tasks/plugins.rake +30 -0
- data/lib/poolparty/tasks/server.rake +42 -0
- data/lib/poolparty/tmp.rb +46 -0
- data/lib/s3/s3_object_store_folders.rb +44 -0
- data/misc/basics_tutorial.txt +142 -0
- data/poolparty.gemspec +72 -0
- data/spec/application_spec.rb +39 -0
- data/spec/callback_spec.rb +194 -0
- data/spec/core_spec.rb +15 -0
- data/spec/helpers/ec2_mock.rb +44 -0
- data/spec/kernel_spec.rb +11 -0
- data/spec/master_spec.rb +203 -0
- data/spec/monitors/cpu_monitor_spec.rb +38 -0
- data/spec/monitors/memory_spec.rb +50 -0
- data/spec/monitors/misc_monitor_spec.rb +50 -0
- data/spec/monitors/web_spec.rb +39 -0
- data/spec/optioner_spec.rb +22 -0
- data/spec/plugin_manager_spec.rb +31 -0
- data/spec/plugin_spec.rb +101 -0
- data/spec/pool_binary_spec.rb +10 -0
- data/spec/poolparty_spec.rb +15 -0
- data/spec/provider_spec.rb +17 -0
- data/spec/remote_instance_spec.rb +149 -0
- data/spec/remoter_spec.rb +65 -0
- data/spec/remoting_spec.rb +84 -0
- data/spec/scheduler_spec.rb +75 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/string_spec.rb +28 -0
- data/web/static/conf/nginx.conf +22 -0
- data/web/static/site/images/balloon.png +0 -0
- data/web/static/site/images/cb.png +0 -0
- data/web/static/site/images/clouds.png +0 -0
- data/web/static/site/images/railsconf_preso_img.png +0 -0
- data/web/static/site/index.html +71 -0
- data/web/static/site/javascripts/application.js +3 -0
- data/web/static/site/javascripts/corner.js +178 -0
- data/web/static/site/javascripts/jquery-1.2.6.pack.js +11 -0
- data/web/static/site/misc.html +42 -0
- data/web/static/site/storage/pool_party_presentation.pdf +0 -0
- data/web/static/site/stylesheets/application.css +100 -0
- data/web/static/site/stylesheets/reset.css +17 -0
- data/web/static/src/layouts/application.haml +25 -0
- data/web/static/src/pages/index.haml +25 -0
- data/web/static/src/pages/misc.haml +5 -0
- data/web/static/src/stylesheets/application.sass +100 -0
- metadata +260 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
class TestRemote
|
4
|
+
include Remoter
|
5
|
+
include Callbacks
|
6
|
+
attr_accessor :ip
|
7
|
+
end
|
8
|
+
describe "Remoter" do
|
9
|
+
before(:each) do
|
10
|
+
@instance = RemoteInstance.new
|
11
|
+
@master = Master.new
|
12
|
+
|
13
|
+
@remoter = TestRemote.new
|
14
|
+
@remoter.stub!(:put).and_return "true"
|
15
|
+
# @tempfile = Tempfile.new("/tmp") do |f|
|
16
|
+
# f << "hi"
|
17
|
+
# end
|
18
|
+
Application.stub!(:ec2_dir).and_return "/Users"
|
19
|
+
Application.stub!(:keypair).and_return "app"
|
20
|
+
Application.stub!(:username).and_return "root"
|
21
|
+
end
|
22
|
+
it "should have an ssh method that corresponds to ssm with the keypair" do
|
23
|
+
@remoter.ssh_string.should == "ssh -i /Users/id_rsa-app -o StrictHostKeyChecking=no"
|
24
|
+
end
|
25
|
+
it "should have a list of ssh_tasks" do
|
26
|
+
@remoter.ssh_tasks.should == []
|
27
|
+
end
|
28
|
+
it "should have a list of scp_tasks" do
|
29
|
+
@remoter.scp_tasks.should == []
|
30
|
+
end
|
31
|
+
it "should reset the values to nil when calling reset" do
|
32
|
+
@remoter.target_hosts.should_not be_nil
|
33
|
+
@remoter.reset!
|
34
|
+
@hosts.should be_nil
|
35
|
+
end
|
36
|
+
describe "executing" do
|
37
|
+
it "should call set_hosts before it executes the tasks" do
|
38
|
+
@remoter.should_receive(:set_hosts).once
|
39
|
+
@remoter.execute_tasks {}
|
40
|
+
end
|
41
|
+
it "should not call set_hosts before it executes the task if it explicitly doesn't want it to" do
|
42
|
+
@remoter.should_not_receive(:set_hosts)
|
43
|
+
@remoter.execute_tasks(:dont_set_hosts => true) {}
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "ssh" do
|
47
|
+
before(:each) do
|
48
|
+
@arr = []
|
49
|
+
@arr << @a = proc{puts "hello"}
|
50
|
+
@arr << @b = proc{puts "world"}
|
51
|
+
@instance.stub!(:ip).and_return("127.0.0.1")
|
52
|
+
end
|
53
|
+
it "should run the tasks in an array with run_thread_list" do
|
54
|
+
@remoter.should_receive(:run_thread_list).once
|
55
|
+
@remoter.run_array_of_tasks(@arr)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should be able to collect the list of the target hosts's ips" do
|
59
|
+
Master.should_receive(:new).and_return(@master)
|
60
|
+
@master.stub!(:nodes).and_return([@instance])
|
61
|
+
@remoter.target_hosts.should == %w(127.0.0.1)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require File.dirname(__FILE__) + "/helpers/ec2_mock"
|
3
|
+
|
4
|
+
describe "Master remoting: " do
|
5
|
+
before(:each) do
|
6
|
+
Kernel.stub!(:system).and_return true
|
7
|
+
Application.stub!(:environment).and_return("test") # So it doesn't daemonize
|
8
|
+
Application.stub!(:minimum_instances).and_return(2)
|
9
|
+
Application.stub!(:maximum_instances).and_return(10)
|
10
|
+
Application.stub!(:polling_time).and_return(0.1)
|
11
|
+
Application.stub!(:verbose).and_return(false) # Turn off messaging
|
12
|
+
|
13
|
+
@master = Master.new
|
14
|
+
@master.launch_new_instance!
|
15
|
+
end
|
16
|
+
describe "starting" do
|
17
|
+
before(:each) do
|
18
|
+
@master.start_cloud!
|
19
|
+
end
|
20
|
+
it "should start the cloud with instances" do
|
21
|
+
@master.list_of_instances.should_not be_empty
|
22
|
+
end
|
23
|
+
it "should start the cloud with running instances" do
|
24
|
+
@master.list_of_running_instances.should_not be_empty
|
25
|
+
end
|
26
|
+
it "should start with the minimum_instances running" do
|
27
|
+
wait 0.5 # Give the last one time to get to running
|
28
|
+
@master.list_of_running_instances.size.should == Application.minimum_instances
|
29
|
+
end
|
30
|
+
end
|
31
|
+
describe "maintaining" do
|
32
|
+
it "should maintain the minimum_instances if one goes down" do
|
33
|
+
@master.start_cloud!
|
34
|
+
wait 0.2 # Give the two instances time to boot up
|
35
|
+
(Application.minimum_instances - @master.number_of_pending_and_running_instances).should == 0
|
36
|
+
|
37
|
+
# Kill one off to test how it handles the response
|
38
|
+
@master.terminate_instance!(@master.list_of_running_instances[0][:instance_id])
|
39
|
+
(Application.minimum_instances - @master.number_of_pending_and_running_instances).should == 1
|
40
|
+
@master.launch_minimum_instances # Assume this runs in the bg process
|
41
|
+
|
42
|
+
(Application.minimum_instances - @master.number_of_pending_and_running_instances).should == 0
|
43
|
+
@master.number_of_pending_and_running_instances.should == Application.minimum_instances
|
44
|
+
end
|
45
|
+
it "should launch a new instance when the load gets too heavy set in the configs" do
|
46
|
+
@master.stub!(:expand?).and_return true
|
47
|
+
@master.start_cloud!
|
48
|
+
wait 0.2 # Give the two instances time to boot up
|
49
|
+
(Application.minimum_instances - @master.number_of_pending_and_running_instances).should == 0
|
50
|
+
@master.scale_cloud!
|
51
|
+
@master.nodes.size.should == Application.minimum_instances + 1
|
52
|
+
end
|
53
|
+
it "should terminate an instance when the load shows that it's too light" do
|
54
|
+
@master.stub!(:contract?).and_return true
|
55
|
+
@master.start_cloud!
|
56
|
+
@master.request_launch_new_instance
|
57
|
+
wait 0.5 # Give the two instances time to boot up
|
58
|
+
@master.number_of_pending_and_running_instances.should == Application.minimum_instances + 1
|
59
|
+
@master.scale_cloud!
|
60
|
+
@master.number_of_pending_and_running_instances.should == Application.minimum_instances
|
61
|
+
end
|
62
|
+
end
|
63
|
+
describe "configuring" do
|
64
|
+
it "should call configure on all of the nodes when calling reconfigure_running_instances" do
|
65
|
+
@master.nodes.each {|a|
|
66
|
+
a.stub!(:status).and_return("running")
|
67
|
+
a.should_receive(:configure).and_return true
|
68
|
+
}
|
69
|
+
@master.reconfigure_running_instances
|
70
|
+
end
|
71
|
+
it "should call restart_with_monit on all of the nodes when calling restart_running_instances_services" do
|
72
|
+
@master.nodes.each {|a| a.should_receive(:restart_with_monit).and_return true }
|
73
|
+
@master.restart_running_instances_services
|
74
|
+
end
|
75
|
+
it "should be able to say there are no number_of_unconfigured_nodes left when all the nodes are configured" do
|
76
|
+
@master.nodes.each {|a| a.should_receive(:stack_installed?).and_return true }
|
77
|
+
@master.number_of_unconfigured_nodes.should == 0
|
78
|
+
end
|
79
|
+
it "should be able to say that there is an unconfigured node" do
|
80
|
+
@master.nodes[-1].should_receive(:stack_installed?).and_return false
|
81
|
+
@master.number_of_unconfigured_nodes.should_not == 0
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
class TestSched
|
4
|
+
include Scheduler
|
5
|
+
end
|
6
|
+
describe "Scheduler" do
|
7
|
+
before(:each) do
|
8
|
+
@test = TestSched.new
|
9
|
+
end
|
10
|
+
it "should create a ScheduleTasks" do
|
11
|
+
@test._tasker.class.should == ScheduleTasks
|
12
|
+
end
|
13
|
+
describe "run_thread_loop" do
|
14
|
+
before(:each) do
|
15
|
+
@klass = Class.new
|
16
|
+
@klass.stub!(:pop).once.and_return true
|
17
|
+
@block = Proc.new {@klass.pop}
|
18
|
+
end
|
19
|
+
it "should yield the block that it is given" do
|
20
|
+
@test.run_thread_list &@block
|
21
|
+
end
|
22
|
+
it "should run run_threads" do
|
23
|
+
@test.should_receive(:run_threads).and_return true
|
24
|
+
@test.run_thread_list &@block
|
25
|
+
end
|
26
|
+
it "should call run on the _tasker" do
|
27
|
+
@test._tasker.should_receive(:run).once.and_return true
|
28
|
+
@test.run_thread_list &@block
|
29
|
+
end
|
30
|
+
describe "ScheduleTasks class" do
|
31
|
+
before(:each) do
|
32
|
+
@stasks = ScheduleTasks.new
|
33
|
+
@test.stub!(:_tasker).and_return(@stasks)
|
34
|
+
end
|
35
|
+
it "should have its tasks listed as an empty array if there are no tasks added" do
|
36
|
+
@stasks.tasks.should == []
|
37
|
+
end
|
38
|
+
it "should have one task listed if it is added" do
|
39
|
+
@test.add_task {@klass.pop}
|
40
|
+
@stasks.tasks.size.should == 1
|
41
|
+
end
|
42
|
+
it "should add each task as a thread" do
|
43
|
+
Thread.should_receive(:new).once
|
44
|
+
@stasks.push proc{puts "hi"}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
describe "when running" do
|
48
|
+
before(:each) do
|
49
|
+
@test.add_task {@klass.pop}
|
50
|
+
end
|
51
|
+
it "should not run the tasks after adding them" do
|
52
|
+
@klass.should_not_receive(:pop)
|
53
|
+
@test.add_task {@klass.pop}
|
54
|
+
end
|
55
|
+
it "should run the tasks when run_thread_list" do
|
56
|
+
@klass.should_receive(:pop)
|
57
|
+
@test.run_thread_list
|
58
|
+
end
|
59
|
+
it "should be able to add tasks and have the run_thread_list run" do
|
60
|
+
@test._tasker.class.should_receive(:synchronize).once
|
61
|
+
@test.run_thread_list
|
62
|
+
end
|
63
|
+
it "should empty all the tasks after running them in the loop" do
|
64
|
+
@test.run_thread_list
|
65
|
+
@test._tasker.tasks.size.should == 0
|
66
|
+
end
|
67
|
+
describe "daemonizing" do
|
68
|
+
it "should detached the process" do
|
69
|
+
Process.should_receive(:detach).once
|
70
|
+
@test.daemonize
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. lib poolparty])
|
2
|
+
|
3
|
+
%w(test/spec).each do |library|
|
4
|
+
begin
|
5
|
+
require library
|
6
|
+
rescue
|
7
|
+
STDERR.puts "== Cannot run test without #{library}"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
Dir["#{File.dirname(__FILE__)}/helpers/**"].each {|a| require a}
|
12
|
+
|
13
|
+
include PoolParty
|
14
|
+
extend PoolParty
|
15
|
+
|
16
|
+
Application.environment = "test"
|
17
|
+
Application.verbose = false
|
18
|
+
|
19
|
+
def wait_launch(time=5)
|
20
|
+
pid = fork {yield}
|
21
|
+
wait time
|
22
|
+
Process.kill("INT", pid)
|
23
|
+
Process.wait(pid, 0)
|
24
|
+
end
|
25
|
+
|
26
|
+
module Test::Unit::AssertDifference
|
27
|
+
def assert_difference(object, method = nil, difference = 1)
|
28
|
+
initial_value = object.send(method)
|
29
|
+
yield
|
30
|
+
assert_equal initial_value + difference, object.send(method), "#{object}##{method}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def assert_no_difference(object, method, &block)
|
34
|
+
assert_difference object, method, 0, &block
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
Test::Spec::Should.send(:include, Test::Unit::AssertDifference)
|
39
|
+
Test::Spec::ShouldNot.send(:include, Test::Unit::AssertDifference)
|
data/spec/string_spec.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe "String" do
|
4
|
+
before(:each) do
|
5
|
+
@string = "string"
|
6
|
+
@string.stub!(:bucket_objects).and_return([])
|
7
|
+
end
|
8
|
+
# Dumb test
|
9
|
+
it "should be able to call bucket_objects on itself" do
|
10
|
+
@string.should_receive(:bucket_objects)
|
11
|
+
@string.bucket_objects
|
12
|
+
end
|
13
|
+
describe "with config replacements" do
|
14
|
+
it "should replace those syms in the string" do
|
15
|
+
("new :port" ^ {:port => 100}).should == "new 100"
|
16
|
+
end
|
17
|
+
it "should be able to detect vars" do
|
18
|
+
@string=<<-EOC
|
19
|
+
listen web_proxy 127.0.0.1::client_port
|
20
|
+
\tserver web1 127.0.0.1::port weight 1 minconn 3 maxconn 6 check inter 30000
|
21
|
+
EOC
|
22
|
+
(@string ^ {:client_port => 3000, :port => 3001}).should ==<<-EOO
|
23
|
+
listen web_proxy 127.0.0.1:3000
|
24
|
+
\tserver web1 127.0.0.1:3001 weight 1 minconn 3 maxconn 6 check inter 30000
|
25
|
+
EOO
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
server {
|
2
|
+
|
3
|
+
listen 80;
|
4
|
+
server_name www.poolpartyrb.com;
|
5
|
+
rewrite ^/(.*) http://poolpartyrb.com permanent;
|
6
|
+
}
|
7
|
+
|
8
|
+
|
9
|
+
server {
|
10
|
+
|
11
|
+
listen 80;
|
12
|
+
server_name poolpartyrb.com;
|
13
|
+
|
14
|
+
access_log /apps/poolpartyrb/logs/access.log;
|
15
|
+
error_log /apps/poolpartyrb/logs/error.log;
|
16
|
+
|
17
|
+
location / {
|
18
|
+
root /apps/poolpartyrb;
|
19
|
+
index index.html;
|
20
|
+
}
|
21
|
+
|
22
|
+
}
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,71 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>PoolParty - Cloud EC2 Computing Made Easy</title>
|
5
|
+
<link href="/stylesheets/reset.css" media="all" rel="stylesheet" type="text/css"/>
|
6
|
+
<link href="/stylesheets/application.css" media="all" rel="stylesheet" type="text/css"/>
|
7
|
+
<script type="text/javascript" src="/javascripts/jquery-1.2.6.pack.js"></script>
|
8
|
+
<script type="text/javascript" src="/javascripts/corner.js"></script>
|
9
|
+
<script type="text/javascript" src="/javascripts/application.js"></script>
|
10
|
+
</head>
|
11
|
+
<body>
|
12
|
+
<div class='container'>
|
13
|
+
<div class='balloon'><img alt="Balloon" src="images/balloon.png"/></div>
|
14
|
+
<div class='header'>
|
15
|
+
<h1><a href="/">PoolParty</a></h1>
|
16
|
+
<div class='clouds'><img alt="Clouds" src="images/clouds.png"/></div>
|
17
|
+
<div class='links'>
|
18
|
+
<a href="#">api</a>
|
19
|
+
<a href="http://poolparty.rubyforge.org/">docs</a>
|
20
|
+
<a href="misc.html">misc</a>
|
21
|
+
<a href="#">group</a>
|
22
|
+
</div>
|
23
|
+
<div class='clear'>
|
24
|
+
</div>
|
25
|
+
</div>
|
26
|
+
<div class='clear'>
|
27
|
+
</div>
|
28
|
+
<div class='content'>
|
29
|
+
<h2>
|
30
|
+
One Ruby <strong><a href="http://github.com/auser/pool-party/tree/master">Gem</a></strong> = easy EC2 computing cloud.
|
31
|
+
</h2>
|
32
|
+
<div class='tout'>
|
33
|
+
<p class='alt'>
|
34
|
+
Amazon's Elastic Compute Cloud provides pay-per-use scalability to the masses. However, clouds do not have innate load-balancing ability, and there is no native failover solution.
|
35
|
+
</p>
|
36
|
+
<p class='alt'>
|
37
|
+
PoolParty is an <strong>open source</strong> tool that <strong>automates</strong> deployment, monitoring, and load balancing of EC2 instances. Configure once, and relax by the poolside -- PoolParty will keep your site and its instances afloat.
|
38
|
+
</p>
|
39
|
+
</div>
|
40
|
+
<p>
|
41
|
+
"I'm convinced, how do I get started?"
|
42
|
+
<code>
|
43
|
+
sudo gem install auser-poolparty -s http://gems.github.com
|
44
|
+
</code>
|
45
|
+
</p>
|
46
|
+
<p>
|
47
|
+
"Okay, are there examples or documentation?"
|
48
|
+
<span class='alt'>
|
49
|
+
<a href="http://poolparty.rubyforge.org/">Docs</a>
|
50
|
+
&
|
51
|
+
<a href="#">Examples</a>
|
52
|
+
</span>
|
53
|
+
</p>
|
54
|
+
<p>
|
55
|
+
"How do I extend it?"
|
56
|
+
<p class='alt'>
|
57
|
+
More coming soon
|
58
|
+
<strong>
|
59
|
+
<a href='http://github.com/auser/pool-party-plugins/tree/master'>
|
60
|
+
http://github.com/auser/pool-party-plugins/tree/master
|
61
|
+
</a>
|
62
|
+
</strong>
|
63
|
+
</p>
|
64
|
+
</p>
|
65
|
+
</div>
|
66
|
+
<div class='cb'>
|
67
|
+
<a href="http://www.citrusbyte.com"><img alt="Cb" src="images/cb.png"/></a>
|
68
|
+
</div>
|
69
|
+
</div>
|
70
|
+
</body>
|
71
|
+
</html>
|
@@ -0,0 +1,178 @@
|
|
1
|
+
/*
|
2
|
+
* jQuery corner plugin
|
3
|
+
*
|
4
|
+
* version 1.92 (12/18/2007)
|
5
|
+
*
|
6
|
+
* Dual licensed under the MIT and GPL licenses:
|
7
|
+
* http://www.opensource.org/licenses/mit-license.php
|
8
|
+
* http://www.gnu.org/licenses/gpl.html
|
9
|
+
*/
|
10
|
+
|
11
|
+
/**
|
12
|
+
* The corner() method provides a simple way of styling DOM elements.
|
13
|
+
*
|
14
|
+
* corner() takes a single string argument: $().corner("effect corners width")
|
15
|
+
*
|
16
|
+
* effect: The name of the effect to apply, such as round or bevel.
|
17
|
+
* If you don't specify an effect, rounding is used.
|
18
|
+
*
|
19
|
+
* corners: The corners can be one or more of top, bottom, tr, tl, br, or bl.
|
20
|
+
* By default, all four corners are adorned.
|
21
|
+
*
|
22
|
+
* width: The width specifies the width of the effect; in the case of rounded corners this
|
23
|
+
* will be the radius of the width.
|
24
|
+
* Specify this value using the px suffix such as 10px, and yes it must be pixels.
|
25
|
+
*
|
26
|
+
* For more details see: http://methvin.com/jquery/jq-corner.html
|
27
|
+
* For a full demo see: http://malsup.com/jquery/corner/
|
28
|
+
*
|
29
|
+
*
|
30
|
+
* @example $('.adorn').corner();
|
31
|
+
* @desc Create round, 10px corners
|
32
|
+
*
|
33
|
+
* @example $('.adorn').corner("25px");
|
34
|
+
* @desc Create round, 25px corners
|
35
|
+
*
|
36
|
+
* @example $('.adorn').corner("notch bottom");
|
37
|
+
* @desc Create notched, 10px corners on bottom only
|
38
|
+
*
|
39
|
+
* @example $('.adorn').corner("tr dog 25px");
|
40
|
+
* @desc Create dogeared, 25px corner on the top-right corner only
|
41
|
+
*
|
42
|
+
* @example $('.adorn').corner("round 8px").parent().css('padding', '4px').corner("round 10px");
|
43
|
+
* @desc Create a rounded border effect by styling both the element and its parent
|
44
|
+
*
|
45
|
+
* @name corner
|
46
|
+
* @type jQuery
|
47
|
+
* @param String options Options which control the corner style
|
48
|
+
* @cat Plugins/Corner
|
49
|
+
* @return jQuery
|
50
|
+
* @author Dave Methvin (dave.methvin@gmail.com)
|
51
|
+
* @author Mike Alsup (malsup@gmail.com)
|
52
|
+
*/
|
53
|
+
(function($) {
|
54
|
+
|
55
|
+
$.fn.corner = function(o) {
|
56
|
+
var ie6 = $.browser.msie && /MSIE 6.0/.test(navigator.userAgent);
|
57
|
+
function sz(el, p) { return parseInt($.css(el,p))||0; };
|
58
|
+
function hex2(s) {
|
59
|
+
var s = parseInt(s).toString(16);
|
60
|
+
return ( s.length < 2 ) ? '0'+s : s;
|
61
|
+
};
|
62
|
+
function gpc(node) {
|
63
|
+
for ( ; node && node.nodeName.toLowerCase() != 'html'; node = node.parentNode ) {
|
64
|
+
var v = $.css(node,'backgroundColor');
|
65
|
+
if ( v.indexOf('rgb') >= 0 ) {
|
66
|
+
if ($.browser.safari && v == 'rgba(0, 0, 0, 0)')
|
67
|
+
continue;
|
68
|
+
var rgb = v.match(/\d+/g);
|
69
|
+
return '#'+ hex2(rgb[0]) + hex2(rgb[1]) + hex2(rgb[2]);
|
70
|
+
}
|
71
|
+
if ( v && v != 'transparent' )
|
72
|
+
return v;
|
73
|
+
}
|
74
|
+
return '#ffffff';
|
75
|
+
};
|
76
|
+
function getW(i) {
|
77
|
+
switch(fx) {
|
78
|
+
case 'round': return Math.round(width*(1-Math.cos(Math.asin(i/width))));
|
79
|
+
case 'cool': return Math.round(width*(1+Math.cos(Math.asin(i/width))));
|
80
|
+
case 'sharp': return Math.round(width*(1-Math.cos(Math.acos(i/width))));
|
81
|
+
case 'bite': return Math.round(width*(Math.cos(Math.asin((width-i-1)/width))));
|
82
|
+
case 'slide': return Math.round(width*(Math.atan2(i,width/i)));
|
83
|
+
case 'jut': return Math.round(width*(Math.atan2(width,(width-i-1))));
|
84
|
+
case 'curl': return Math.round(width*(Math.atan(i)));
|
85
|
+
case 'tear': return Math.round(width*(Math.cos(i)));
|
86
|
+
case 'wicked': return Math.round(width*(Math.tan(i)));
|
87
|
+
case 'long': return Math.round(width*(Math.sqrt(i)));
|
88
|
+
case 'sculpt': return Math.round(width*(Math.log((width-i-1),width)));
|
89
|
+
case 'dog': return (i&1) ? (i+1) : width;
|
90
|
+
case 'dog2': return (i&2) ? (i+1) : width;
|
91
|
+
case 'dog3': return (i&3) ? (i+1) : width;
|
92
|
+
case 'fray': return (i%2)*width;
|
93
|
+
case 'notch': return width;
|
94
|
+
case 'bevel': return i+1;
|
95
|
+
}
|
96
|
+
};
|
97
|
+
o = (o||"").toLowerCase();
|
98
|
+
var keep = /keep/.test(o); // keep borders?
|
99
|
+
var cc = ((o.match(/cc:(#[0-9a-f]+)/)||[])[1]); // corner color
|
100
|
+
var sc = ((o.match(/sc:(#[0-9a-f]+)/)||[])[1]); // strip color
|
101
|
+
var width = parseInt((o.match(/(\d+)px/)||[])[1]) || 10; // corner width
|
102
|
+
var re = /round|bevel|notch|bite|cool|sharp|slide|jut|curl|tear|fray|wicked|sculpt|long|dog3|dog2|dog/;
|
103
|
+
var fx = ((o.match(re)||['round'])[0]);
|
104
|
+
var edges = { T:0, B:1 };
|
105
|
+
var opts = {
|
106
|
+
TL: /top|tl/.test(o), TR: /top|tr/.test(o),
|
107
|
+
BL: /bottom|bl/.test(o), BR: /bottom|br/.test(o)
|
108
|
+
};
|
109
|
+
if ( !opts.TL && !opts.TR && !opts.BL && !opts.BR )
|
110
|
+
opts = { TL:1, TR:1, BL:1, BR:1 };
|
111
|
+
var strip = document.createElement('div');
|
112
|
+
strip.style.overflow = 'hidden';
|
113
|
+
strip.style.height = '1px';
|
114
|
+
strip.style.backgroundColor = sc || 'transparent';
|
115
|
+
strip.style.borderStyle = 'solid';
|
116
|
+
return this.each(function(index){
|
117
|
+
var pad = {
|
118
|
+
T: parseInt($.css(this,'paddingTop'))||0, R: parseInt($.css(this,'paddingRight'))||0,
|
119
|
+
B: parseInt($.css(this,'paddingBottom'))||0, L: parseInt($.css(this,'paddingLeft'))||0
|
120
|
+
};
|
121
|
+
|
122
|
+
if ($.browser.msie) this.style.zoom = 1; // force 'hasLayout' in IE
|
123
|
+
if (!keep) this.style.border = 'none';
|
124
|
+
strip.style.borderColor = cc || gpc(this.parentNode);
|
125
|
+
var cssHeight = $.curCSS(this, 'height');
|
126
|
+
|
127
|
+
for (var j in edges) {
|
128
|
+
var bot = edges[j];
|
129
|
+
// only add stips if needed
|
130
|
+
if ((bot && (opts.BL || opts.BR)) || (!bot && (opts.TL || opts.TR))) {
|
131
|
+
strip.style.borderStyle = 'none '+(opts[j+'R']?'solid':'none')+' none '+(opts[j+'L']?'solid':'none');
|
132
|
+
var d = document.createElement('div');
|
133
|
+
$(d).addClass('jquery-corner');
|
134
|
+
var ds = d.style;
|
135
|
+
|
136
|
+
bot ? this.appendChild(d) : this.insertBefore(d, this.firstChild);
|
137
|
+
|
138
|
+
if (bot && cssHeight != 'auto') {
|
139
|
+
if ($.css(this,'position') == 'static')
|
140
|
+
this.style.position = 'relative';
|
141
|
+
ds.position = 'absolute';
|
142
|
+
ds.bottom = ds.left = ds.padding = ds.margin = '0';
|
143
|
+
if ($.browser.msie)
|
144
|
+
ds.setExpression('width', 'this.parentNode.offsetWidth');
|
145
|
+
else
|
146
|
+
ds.width = '100%';
|
147
|
+
}
|
148
|
+
else if (!bot && $.browser.msie) {
|
149
|
+
if ($.css(this,'position') == 'static')
|
150
|
+
this.style.position = 'relative';
|
151
|
+
ds.position = 'absolute';
|
152
|
+
ds.top = ds.left = ds.right = ds.padding = ds.margin = '0';
|
153
|
+
|
154
|
+
// fix ie6 problem when blocked element has a border width
|
155
|
+
var bw = 0;
|
156
|
+
if (ie6 || !$.boxModel)
|
157
|
+
bw = sz(this,'borderLeftWidth') + sz(this,'borderRightWidth');
|
158
|
+
ie6 ? ds.setExpression('width', 'this.parentNode.offsetWidth - '+bw+'+ "px"') : ds.width = '100%';
|
159
|
+
}
|
160
|
+
else {
|
161
|
+
ds.margin = !bot ? '-'+pad.T+'px -'+pad.R+'px '+(pad.T-width)+'px -'+pad.L+'px' :
|
162
|
+
(pad.B-width)+'px -'+pad.R+'px -'+pad.B+'px -'+pad.L+'px';
|
163
|
+
}
|
164
|
+
|
165
|
+
for (var i=0; i < width; i++) {
|
166
|
+
var w = Math.max(0,getW(i));
|
167
|
+
var e = strip.cloneNode(false);
|
168
|
+
e.style.borderWidth = '0 '+(opts[j+'R']?w:0)+'px 0 '+(opts[j+'L']?w:0)+'px';
|
169
|
+
bot ? d.appendChild(e) : d.insertBefore(e, d.firstChild);
|
170
|
+
}
|
171
|
+
}
|
172
|
+
}
|
173
|
+
});
|
174
|
+
};
|
175
|
+
|
176
|
+
$.fn.uncorner = function(o) { return $('.jquery-corner', this).remove(); };
|
177
|
+
|
178
|
+
})(jQuery);
|