phocoder-rails 0.0.33

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.
Files changed (116) hide show
  1. data/.autotest +46 -0
  2. data/.document +5 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +44 -0
  5. data/LICENSE.txt +20 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.rdoc +3 -0
  8. data/Rakefile +56 -0
  9. data/VERSION +5 -0
  10. data/app/controllers/phocoder_controller.rb +118 -0
  11. data/app/helpers/phocoder_helper.rb +320 -0
  12. data/app/models/encodable_job.rb +91 -0
  13. data/app/views/phocoder/_offline_video_embed.html.erb +19 -0
  14. data/app/views/phocoder/_thumbnail_update.html.erb +3 -0
  15. data/app/views/phocoder/_video_embed.html.erb +23 -0
  16. data/app/views/phocoder/multi_thumbnail_update.json.erb +7 -0
  17. data/app/views/phocoder/thumbnail_update.js.erb +9 -0
  18. data/config/routes.rb +8 -0
  19. data/lib/generators/phocoder_rails/model_update_generator.rb +52 -0
  20. data/lib/generators/phocoder_rails/scaffold_generator.rb +94 -0
  21. data/lib/generators/phocoder_rails/setup_generator.rb +33 -0
  22. data/lib/generators/phocoder_rails/templates/controller.rb +71 -0
  23. data/lib/generators/phocoder_rails/templates/helper.rb +5 -0
  24. data/lib/generators/phocoder_rails/templates/migration.rb +24 -0
  25. data/lib/generators/phocoder_rails/templates/model.rb +20 -0
  26. data/lib/generators/phocoder_rails/templates/model_migration.rb +56 -0
  27. data/lib/generators/phocoder_rails/templates/model_thumbnail.rb +5 -0
  28. data/lib/generators/phocoder_rails/templates/model_update_migration.rb +64 -0
  29. data/lib/generators/phocoder_rails/templates/phocodable.yml +28 -0
  30. data/lib/generators/phocoder_rails/templates/views/_form.html.erb.tt +23 -0
  31. data/lib/generators/phocoder_rails/templates/views/index.html.erb.tt +26 -0
  32. data/lib/generators/phocoder_rails/templates/views/new.html.erb.tt +5 -0
  33. data/lib/generators/phocoder_rails/templates/views/show.html.erb.tt +12 -0
  34. data/lib/phocoder_rails.rb +12 -0
  35. data/lib/phocoder_rails/acts_as_phocodable.rb +1153 -0
  36. data/lib/phocoder_rails/engine.rb +24 -0
  37. data/lib/phocoder_rails/errors.rb +46 -0
  38. data/phocoder-rails.gemspec +219 -0
  39. data/public/images/building.gif +0 -0
  40. data/public/images/error.png +0 -0
  41. data/public/images/play_small.png +0 -0
  42. data/public/images/storing.gif +0 -0
  43. data/public/images/waiting.gif +0 -0
  44. data/public/javascripts/phocodable.js +110 -0
  45. data/public/javascripts/video-js-2.0.2/.DS_Store +0 -0
  46. data/public/javascripts/video-js-2.0.2/LICENSE.txt +165 -0
  47. data/public/javascripts/video-js-2.0.2/README.markdown +202 -0
  48. data/public/javascripts/video-js-2.0.2/demo-subtitles.srt +13 -0
  49. data/public/javascripts/video-js-2.0.2/demo.html +101 -0
  50. data/public/javascripts/video-js-2.0.2/skins/hu.css +116 -0
  51. data/public/javascripts/video-js-2.0.2/skins/tube.css +111 -0
  52. data/public/javascripts/video-js-2.0.2/skins/vim.css +89 -0
  53. data/public/javascripts/video-js-2.0.2/video-js.css +242 -0
  54. data/public/javascripts/video-js-2.0.2/video.js +1758 -0
  55. data/public/stylesheets/phocodable.css +19 -0
  56. data/spec/controllers/phocoder_controller_spec.rb +123 -0
  57. data/spec/dummy/Rakefile +7 -0
  58. data/spec/dummy/app/controllers/application_controller.rb +7 -0
  59. data/spec/dummy/app/controllers/images_controller.rb +72 -0
  60. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  61. data/spec/dummy/app/helpers/images_helper.rb +5 -0
  62. data/spec/dummy/app/models/image.rb +20 -0
  63. data/spec/dummy/app/models/image_thumbnail.rb +5 -0
  64. data/spec/dummy/app/models/image_upload.rb +11 -0
  65. data/spec/dummy/app/views/images/_form.html.erb +23 -0
  66. data/spec/dummy/app/views/images/index.html.erb +26 -0
  67. data/spec/dummy/app/views/images/new.html.erb +5 -0
  68. data/spec/dummy/app/views/images/show.html.erb +12 -0
  69. data/spec/dummy/app/views/layouts/application.html.erb +18 -0
  70. data/spec/dummy/config.ru +4 -0
  71. data/spec/dummy/config/application.rb +45 -0
  72. data/spec/dummy/config/boot.rb +10 -0
  73. data/spec/dummy/config/database.yml +25 -0
  74. data/spec/dummy/config/environment.rb +8 -0
  75. data/spec/dummy/config/environments/development.rb +26 -0
  76. data/spec/dummy/config/environments/production.rb +49 -0
  77. data/spec/dummy/config/environments/test.rb +40 -0
  78. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  79. data/spec/dummy/config/initializers/inflections.rb +10 -0
  80. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  81. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  82. data/spec/dummy/config/initializers/session_store.rb +8 -0
  83. data/spec/dummy/config/locales/en.yml +5 -0
  84. data/spec/dummy/config/routes.rb +60 -0
  85. data/spec/dummy/db/migrate/001_create_image_uploads.rb +37 -0
  86. data/spec/dummy/db/migrate/20110523165213_add_parent_type_to_image_uploads.rb +11 -0
  87. data/spec/dummy/db/migrate/20110523165522_create_encodable_jobs.rb +24 -0
  88. data/spec/dummy/db/migrate/20111101024507_create_images.rb +56 -0
  89. data/spec/dummy/db/schema.rb +99 -0
  90. data/spec/dummy/public/404.html +26 -0
  91. data/spec/dummy/public/422.html +26 -0
  92. data/spec/dummy/public/500.html +26 -0
  93. data/spec/dummy/public/favicon.ico +0 -0
  94. data/spec/dummy/public/index.html +239 -0
  95. data/spec/dummy/public/javascripts/application.js +2 -0
  96. data/spec/dummy/public/javascripts/controls.js +965 -0
  97. data/spec/dummy/public/javascripts/dragdrop.js +974 -0
  98. data/spec/dummy/public/javascripts/effects.js +1123 -0
  99. data/spec/dummy/public/javascripts/jquery-1.6.4.js +9046 -0
  100. data/spec/dummy/public/javascripts/prototype.js +6001 -0
  101. data/spec/dummy/public/javascripts/rails.js +175 -0
  102. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  103. data/spec/dummy/script/rails +6 -0
  104. data/spec/engine_spec.rb +12 -0
  105. data/spec/fixtures/big_eye_tiny.jpg +0 -0
  106. data/spec/fixtures/octologo.png +0 -0
  107. data/spec/fixtures/test.txt +2 -0
  108. data/spec/fixtures/video-test.mov +0 -0
  109. data/spec/helpers/phocoder_helper_spec.rb +421 -0
  110. data/spec/integration/navigation_spec.rb +10 -0
  111. data/spec/models/acts_as_phocodable_spec.rb +664 -0
  112. data/spec/models/encodable_job_spec.rb +50 -0
  113. data/spec/phocoder_rails_spec.rb +8 -0
  114. data/spec/routing/phocoder_routing_spec.rb +19 -0
  115. data/spec/spec_helper.rb +75 -0
  116. metadata +375 -0
@@ -0,0 +1,19 @@
1
+ /******************************************************
2
+ * Video Posters
3
+ */
4
+ span.phocoder_video_poster{
5
+ position:relative;
6
+ }
7
+
8
+ span.phocoder_video_poster .play{
9
+ position:absolute;
10
+ bottom:10px;
11
+ left:5px;
12
+ border:0px !important;
13
+ }
14
+
15
+ .phocoder_error{
16
+ border:1px solid red;
17
+ background:#fee;
18
+ padding:10px;
19
+ }
@@ -0,0 +1,123 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe PhocoderController do
4
+
5
+ before(:each) do
6
+ @image_upload = ImageUpload.create(:phocoder_job_id=>1,:phocoder_input_id=>1,:phocoder_output_id=>1,
7
+ :zencoder_job_id=>1,:zencoder_input_id=>1,:zencoder_output_id=>1,
8
+ :file_size=>1,:width=>1,:height=>1,:filename=>"test.png",:content_type=>"image/png")
9
+ @encodable_job = EncodableJob.create(:phocoder_job_id=>1,:phocoder_input_id=>1,:phocoder_output_id=>1,
10
+ :zencoder_job_id=>1,:zencoder_input_id=>1,:zencoder_output_id=>1,
11
+ :encodable=>@image_upload)
12
+ end
13
+
14
+ after(:each) do
15
+ @image_upload.destroy
16
+ @encodable_job.destroy
17
+ end
18
+
19
+
20
+ #at this point the image_upload does not have any thumbnails created
21
+ describe "POST to 'thumbnail_update' " do
22
+
23
+ it "should assign and update an img" do
24
+ post 'thumbnail_update', { :class=>@image_upload.class.name.to_s,:id=>@image_upload.id,:thumbnail=>"small",:format=>"js" }
25
+ response.should be_success
26
+ assigns(:img).id.should == @image_upload.id
27
+ end
28
+
29
+ end
30
+
31
+
32
+
33
+ describe "POST 'phocoder_update'" do
34
+
35
+ it "should update an input" do
36
+ post 'phocoder_notification_update', {:class=>"ImageUpload",:id=>1, :job=>{:id => 1},:input=>{:id=>1,:file_size=>2,:width=>2,:height=>2,:url=>"http://production.webapeel.com/octolabs/themes/octolabs/images/octologo.png"},:format=>"json" }
37
+ response.should be_success
38
+ #@image_upload.reload
39
+ #@image_upload.file_size.should == 2
40
+ end
41
+
42
+ it "should update an output" do
43
+ EncodableJob.should_receive(:update_from_phocoder)
44
+ post 'phocoder_notification_update', {:class=>"ImageUpload",:id=>1, :job=>{:id => 1}, :output=>{:id=>1,:file_size=>2,:width=>2,:height=>2,:url=>"http://production.webapeel.com/octolabs/themes/octolabs/images/octologo.png"},:format=>"json" }
45
+ response.should be_success
46
+ #@image_upload.reload
47
+ #@image_upload.file_size.should == 2
48
+ end
49
+
50
+ # sometimes an encodable job doesn't get created. Why?
51
+ it "should fall back if no encodable job can be found" do
52
+ EncodableJob.should_receive(:update_from_phocoder)
53
+ post 'phocoder_notification_update', {:class=>"ImageUpload",:id=>@image_upload.id, :job=>{:id => 2}, :output=>{:id=>2,:file_size=>2,:width=>2,:height=>2,:url=>"http://production.webapeel.com/octolabs/themes/octolabs/images/octologo.png"},:format=>"json" }
54
+ response.should be_success
55
+ # This is a controller test, not integration test
56
+ #@image_upload.reload
57
+ #@image_upload.file_size.should == 2
58
+ end
59
+
60
+ end
61
+
62
+
63
+
64
+
65
+ describe "POST zencoder update" do
66
+
67
+ before(:each) do
68
+ @thumb = @image_upload.thumbnails.create(:phocoder_job_id=>2,:phocoder_input_id=>2,:phocoder_output_id=>2,
69
+ :zencoder_job_id=>2,:zencoder_input_id=>2,:zencoder_output_id=>2,
70
+ :file_size=>2,:width=>2,:height=>2)
71
+ @encodable_job2 = EncodableJob.create(:phocoder_job_id=>2,:phocoder_input_id=>2,:phocoder_output_id=>2,
72
+ :zencoder_job_id=>2,:zencoder_input_id=>2,:zencoder_output_id=>2,
73
+ :encodable=>@thumb)
74
+ end
75
+
76
+ after(:each) do
77
+ @thumb.destroy
78
+ @encodable_job2.destroy
79
+ end
80
+
81
+
82
+
83
+
84
+
85
+ it "should update an output" do
86
+ #Zencoder::Job.should_receive(:details).and_return(mock(Zencoder::Response,:body=>{
87
+ # "job" => {"id"=>2,
88
+ # "state" => "finished",
89
+ # "input_media_file" => {"width" => 2,"height" => 2,
90
+ # "duration_in_ms" => 2, "file_size_bytes" => 2 } ,
91
+ # "output_media_files" => [{"width" => 1, "height" => 1, "duration_in_ms" => 1, "file_size_bytes" => 1, "id" => 2 }],
92
+ # "thumbnails" => [{ "url" => "http://farm2.static.flickr.com/1243/5168720424_ea33e31d96.jpg", "id" => 1 }]
93
+ # }
94
+ # }))
95
+ #
96
+ # Phocoder::Job.should_receive(:create).and_return(mock(Phocoder::Response,:body=>{
97
+ # "job"=>{
98
+ # "id"=>1,
99
+ # "inputs"=>["id"=>1],
100
+ # "thumbnails"=>[{"label"=>"small","filename"=>"small-test-file.jpg","id"=>1}]
101
+ #}
102
+ #}))
103
+
104
+
105
+ EncodableJob.should_receive(:update_from_zencoder)
106
+ #@image_upload.should_receive(:create_zencoder_image_thumb).and_return(nil)
107
+ post 'zencoder_notification_update', {:class=>"ImageUpload",:id=>@thumb.id,
108
+ "job"=>{"state"=>"finished","id"=>2},
109
+ "output" => { :label => "web", :url => "http://example.com/file.mp4", :state => "finished", :id => 2},
110
+ :format=>"json"
111
+ }
112
+ response.should be_success
113
+ # Comment this out for now. This is a controller test, not an integration test.
114
+ # we don't get direct info on the input, just the thumb
115
+ #@thumb.reload
116
+ #@thumb.file_size.should == 1
117
+ end
118
+
119
+ end # describe POST
120
+
121
+
122
+
123
+ end
@@ -0,0 +1,7 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+ require 'rake'
6
+
7
+ Dummy::Application.load_tasks
@@ -0,0 +1,7 @@
1
+ class ApplicationController < ActionController::Base
2
+
3
+ protect_from_forgery
4
+
5
+ helper :phocoder
6
+
7
+ end
@@ -0,0 +1,72 @@
1
+ class ImagesController < ApplicationController
2
+
3
+
4
+ # This example does not handle all of the ins and outs of
5
+ # allowing someone to 'replace' a file by edit/update.
6
+ # That's a sticky problem that would only cloud
7
+ # the concepts we're demonstrating here.
8
+
9
+
10
+ # GET /images
11
+ # GET /images.xml
12
+ def index
13
+ @images = Image.top_level.all
14
+
15
+ respond_to do |format|
16
+ format.html # index.html.erb
17
+ format.xml { render :xml => @images }
18
+ end
19
+ end
20
+
21
+ # GET /images/1
22
+ # GET /images/1.xml
23
+ def show
24
+ @image = Image.find(params[:id])
25
+
26
+ respond_to do |format|
27
+ format.html # show.html.erb
28
+ format.xml { render :xml => @image }
29
+ end
30
+ end
31
+
32
+ # GET /images/new
33
+ # GET /images/new.xml
34
+ def new
35
+ @image = Image.new
36
+
37
+ respond_to do |format|
38
+ format.html # new.html.erb
39
+ format.xml { render :xml => @image }
40
+ end
41
+ end
42
+
43
+
44
+ # POST /images
45
+ # POST /images.xml
46
+ def create
47
+ @image = Image.new(params[:image])
48
+
49
+ respond_to do |format|
50
+ if @image.save
51
+ format.html { redirect_to(@image, :notice => "Image was successfully created.") }
52
+ format.xml { render :xml => @image, :status => :created, :location => @image }
53
+ else
54
+ format.html { render :action => "new" }
55
+ format.xml { render :xml => @image.errors, :status => :unprocessable_entity }
56
+ end
57
+ end
58
+ end
59
+
60
+
61
+ # DELETE /images/1
62
+ # DELETE /images/1.xml
63
+ def destroy
64
+ @image = Image.find(params[:id])
65
+ @image.destroy
66
+
67
+ respond_to do |format|
68
+ format.html { redirect_to(images_url) }
69
+ format.xml { head :ok }
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,5 @@
1
+ module ImagesHelper
2
+
3
+
4
+
5
+ end
@@ -0,0 +1,20 @@
1
+ class Image < ActiveRecord::Base
2
+
3
+ acts_as_phocodable :thumbnail_class => "ImageThumbnail",
4
+ :thumbnails => [
5
+ {:label=>"small",:width=>100,:height=>100 },
6
+ {:label=>"medium",:width=>400,:height=>400,
7
+ :frame=>{ :width=>20, :bottom=>50, :color=>'003' },
8
+ :annotations=>[
9
+ {:text=>"Annotation Testing",:pointsize=>30,:fill_color=>'fff',:gravity=>"South",:y=>10},
10
+ {:text=>"Howdy!",:pointsize=>10,:fill_color=>'ccc',:gravity=>"North",:y=>5}
11
+ ]
12
+ }
13
+ ],
14
+
15
+ :videos => [ {:label => 'mp4',:video_codec=>"h264" }, #, :thumbnails=>{ :number=>1, :start_at_first_frame=>1 }
16
+ {:label => 'webm', :video_codec=>"vp8" },
17
+ {:label => 'ogv', :video_codec=>"theora" }
18
+ ]
19
+
20
+ end
@@ -0,0 +1,5 @@
1
+ class ImageThumbnail < ActiveRecord::Base
2
+
3
+ acts_as_phocodable :parent_class => "Image"
4
+
5
+ end
@@ -0,0 +1,11 @@
1
+
2
+ #dummy class that can become phocodeable
3
+ class ImageUpload < ActiveRecord::Base
4
+
5
+ acts_as_phocodable :thumbnails => [{:label=>"small",:width=>100,:height=>100 },
6
+ {:label=>"medium",:width=>200,:height=>200 }],
7
+ :videos => [ {:label => 'mp4',:video_codec=>"h264" },
8
+ {:label => 'webm', :video_codec=>"vp8"}
9
+ ]
10
+
11
+ end
@@ -0,0 +1,23 @@
1
+ <%= form_for( @image, :html => { :multipart => true } ) do |f| %>
2
+
3
+ <% if @image.errors.any? %>
4
+ <div id="error_explanation">
5
+ <h2><%= pluralize(@image.errors.count, "error") %> prohibited this encodable from being saved:</h2>
6
+ <ul>
7
+ <% @image.errors.full_messages.each do |msg| %>
8
+ <li><%= msg %></li>
9
+ <% end %>
10
+ </ul>
11
+ </div>
12
+ <% end %>
13
+
14
+ <div class="field">
15
+ <%= f.label :file, "Upload image file" %>
16
+ <%= f.file_field :file %>
17
+ </div>
18
+
19
+ <div class="actions">
20
+ <%= f.submit %>
21
+ </div>
22
+
23
+ <% end %>
@@ -0,0 +1,26 @@
1
+ <h1>Listing images</h1>
2
+
3
+ <table>
4
+ <tr>
5
+ <th>Filename</th>
6
+ <th></th>
7
+ <th></th>
8
+
9
+ </tr>
10
+
11
+ <% @images.each do |image| %>
12
+ <tr>
13
+ <td>
14
+ <%= phocoder_thumbnail image,"small",false %><br/>
15
+ <%= image.filename %>
16
+ </td>
17
+ <td><%= link_to 'Show', image %></td>
18
+
19
+ <td><%= link_to 'Destroy', image, :confirm => 'Are you sure?', :method => :delete %></td>
20
+ </tr>
21
+ <% end %>
22
+ </table>
23
+
24
+ <br />
25
+
26
+ <%= link_to 'New image', new_image_path %>
@@ -0,0 +1,5 @@
1
+ <h1>New image</h1>
2
+
3
+ <%= render 'form' %>
4
+
5
+ <%= link_to 'Back', images_path %>
@@ -0,0 +1,12 @@
1
+ <p id="notice"><%= notice %></p>
2
+
3
+ <p>
4
+ <b>Filename:</b>
5
+ <%= @image.filename %>
6
+ </p>
7
+
8
+ <%= phocoder_thumbnail @image,"medium" %>
9
+
10
+ <br/>
11
+
12
+ <%= link_to 'Back', images_path %>
@@ -0,0 +1,18 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dummy</title>
5
+ <%= stylesheet_link_tag :all %>
6
+ <%= javascript_include_tag 'jquery-1.6.4' %>
7
+ <%= phocoder_includes %>
8
+ <%= csrf_meta_tag %>
9
+ <script type="text/javascript">
10
+ new Phocodable.JQueryUpdater().init();
11
+ </script>
12
+ </head>
13
+ <body>
14
+
15
+ <%= yield %>
16
+
17
+ </body>
18
+ </html>
@@ -0,0 +1,4 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+
3
+ require ::File.expand_path('../config/environment', __FILE__)
4
+ run Dummy::Application
@@ -0,0 +1,45 @@
1
+ require File.expand_path('../boot', __FILE__)
2
+
3
+ require "active_model/railtie"
4
+ require "active_record/railtie"
5
+ require "action_controller/railtie"
6
+ require "action_view/railtie"
7
+ require "action_mailer/railtie"
8
+
9
+ Bundler.require
10
+ require "phocoder_rails"
11
+
12
+ module Dummy
13
+ class Application < Rails::Application
14
+ # Settings in config/environments/* take precedence over those specified here.
15
+ # Application configuration should go into files in config/initializers
16
+ # -- all .rb files in that directory are automatically loaded.
17
+
18
+ # Custom directories with classes and modules you want to be autoloadable.
19
+ # config.autoload_paths += %W(#{config.root}/extras)
20
+
21
+ # Only load the plugins named here, in the order given (default is alphabetical).
22
+ # :all can be used as a placeholder for all plugins not explicitly named.
23
+ # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
24
+
25
+ # Activate observers that should always be running.
26
+ # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
27
+
28
+ # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
29
+ # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
30
+ # config.time_zone = 'Central Time (US & Canada)'
31
+
32
+ # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
33
+ # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
34
+ # config.i18n.default_locale = :de
35
+
36
+ # JavaScript files you want as :defaults (application.js is always included).
37
+ # config.action_view.javascript_expansions[:defaults] = %w(jquery rails)
38
+
39
+ # Configure the default encoding used in templates for Ruby 1.9.
40
+ config.encoding = "utf-8"
41
+
42
+ # Configure sensitive parameters which will be filtered from the log file.
43
+ config.filter_parameters += [:password]
44
+ end
45
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ gemfile = File.expand_path('../../../../Gemfile', __FILE__)
3
+
4
+ if File.exist?(gemfile)
5
+ ENV['BUNDLE_GEMFILE'] = gemfile
6
+ require 'bundler'
7
+ Bundler.setup
8
+ end
9
+
10
+ $:.unshift File.expand_path('../../../../lib', __FILE__)