├── .gitignore
├── .ruby-version
├── .travis.yml
├── Appraisals
├── CHANGELOG.md
├── Gemfile
├── MIT-LICENSE
├── README.md
├── Rakefile
├── gemfiles
├── .bundle
│ └── config
├── .gitignore
├── rails_4.1.gemfile
├── rails_4.2.gemfile
├── rails_5.0.gemfile
├── rails_5.1.gemfile
├── rails_5.2.gemfile
├── rails_5.2.gemfile~Ruby on Rails 5.2 & 6.0 and Ruby 2.6.1 testing
├── rails_6.0.gemfile
└── rails_6.1.gemfile
├── lib
├── olive_branch.rb
└── olive_branch
│ ├── middleware.rb
│ └── version.rb
├── olive_branch.gemspec
└── spec
├── benchmark_spec.rb
├── integration_spec.rb
├── olive_branch
└── middleware_spec.rb
├── rails_helper.rb
├── spec_helper.rb
└── test_app
├── .gitignore
├── Rakefile
├── app
└── controllers
│ ├── application_controller.rb
│ └── posts_controller.rb
├── bin
├── bundle
├── rails
└── rake
├── config.ru
├── config
├── application.rb
├── boot.rb
├── environment.rb
├── environments
│ ├── development.rb
│ ├── production.rb
│ └── test.rb
├── initializers
│ ├── cookies_serializer.rb
│ ├── filter_parameter_logging.rb
│ └── wrap_parameters.rb
├── routes.rb
├── secrets.yml
└── spring.rb
├── example_responses
└── complex.json
├── log
├── .gitignore
└── .keep
├── public
├── 404.html
├── 422.html
├── 500.html
├── apple-touch-icon-precomposed.png
├── apple-touch-icon.png
└── favicon.ico
└── tmp
└── .keep
/.gitignore:
--------------------------------------------------------------------------------
1 | Gemfile.lock
2 | *.gem
3 | .byebug_history
4 | .idea/
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | 2.6.1
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | script: "bundle exec rspec"
2 | cache: bundler
3 | rvm:
4 | - 2.2
5 | - 2.3
6 | - 2.4
7 | - 2.5
8 | - 2.6.1
9 | - 2.7.3
10 | gemfile:
11 | - gemfiles/rails_4.2.gemfile
12 | - gemfiles/rails_5.0.gemfile
13 | - gemfiles/rails_5.1.gemfile
14 | - gemfiles/rails_5.2.gemfile
15 | - gemfiles/rails_6.0.gemfile
16 | - gemfiles/rails_6.1.gemfile
17 |
18 | jobs:
19 | # Rails 6.0 requires 2.5 or newer
20 | exclude:
21 | - rvm: 2.2
22 | gemfile: gemfiles/rails_6.0.gemfile
23 | - rvm: 2.2
24 | gemfile: gemfiles/rails_6.1.gemfile
25 | - rvm: 2.3
26 | gemfile: gemfiles/rails_6.0.gemfile
27 | - rvm: 2.3
28 | gemfile: gemfiles/rails_6.1.gemfile
29 | - rvm: 2.4
30 | gemfile: gemfiles/rails_6.0.gemfile
31 | - rvm: 2.4
32 | gemfile: gemfiles/rails_6.1.gemfile
33 | - rvm: 2.7.3
34 | gemfile: gemfiles/rails_4.2.gemfile
--------------------------------------------------------------------------------
/Appraisals:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Will not work on Ruby 2.6.1
4 | # appraise 'rails-4.1' do
5 | # gem 'rails', '~> 4.1.16'
6 | # end
7 |
8 | appraise 'rails-4.2' do
9 | gem 'rails', '~> 4.2.11'
10 | end
11 |
12 | appraise 'rails-5.0' do
13 | gem 'rails', '~> 5.0.7.1'
14 | end
15 |
16 | appraise 'rails-5.1' do
17 | gem 'rails', '~> 5.1.6.1'
18 | end
19 |
20 | appraise 'rails-5.2' do
21 | gem 'rails', '~> 5.2.5'
22 | end
23 |
24 | appraise 'rails-6.0' do
25 | gem 'rails', '~> 6.0.3.6'
26 | end
27 |
28 | appraise 'rails-6.1' do
29 | gem 'rails', '~> 6.1.3.1'
30 | end
31 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | 4.0.0
2 | ------
3 | * [Remove Oj as a required dependency](https://github.com/vigetlabs/olive_branch/pull/44)
4 |
5 | 3.0.0
6 | ------
7 | * [Change default inflection header to Key-Inflection](https://github.com/vigetlabs/olive_branch/pull/35)
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | # Specify your gem's dependencies in olive_branch.gemspec
4 | gemspec
5 |
--------------------------------------------------------------------------------
/MIT-LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2016 Eli Fatsi (Viget)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OliveBranch
2 |
3 | [](https://codeclimate.com/github/vigetlabs/olive_branch)
4 | [](https://travis-ci.org/vigetlabs/olive_branch)
5 |
6 | This gem lets your API users pass in and receive camelCased or dash-cased keys, while your Rails app receives and produces snake_cased ones.
7 |
8 | ## Install
9 |
10 | 1. Add this to your Gemfile and then `bundle install`:
11 |
12 | ```ruby
13 | gem "olive_branch"
14 | ```
15 |
16 | 2. Add this to `config/applcation.rb` if you want the clients to control the transformation behaviour through the `Key-Inflection` HTTP header sent by the client:
17 |
18 | ```ruby
19 | config.middleware.use OliveBranch::Middleware
20 | ```
21 |
22 | Alternative, if you want to always convert between snake_case and camelCase for your API and only your API, to keep Rubyist and JavaScript developer's happy, use the following configuration:
23 |
24 | ```ruby
25 | excluded_routes = ->(env) { !env["PATH_INFO"].match(%r{^/api}) }
26 | config.middleware.use OliveBranch::Middleware,
27 | inflection: "camel",
28 | exclude_params: excluded_routes,
29 | exclude_response: excluded_routes
30 | ```
31 |
32 | in your `config/application.rb`.
33 |
34 | ## Use
35 |
36 | Include a `Key-Inflection` header with values of `camel`, `dash`, `snake` or `pascal` in your JSON API requests.
37 |
38 | For more examples, see [our blog post](https://www.viget.com/articles/introducing-olivebranch).
39 |
40 | ## Optimizations and configuration
41 |
42 | `OliveBranch` uses `multi_json`, which will automatically choose the fastest available JSON parsing library present in your application.
43 | Most Ruby applications default to using the JSON library that ships with Ruby. However, by including a coder that `multi_json` considers faster, like [Oj](https://github.com/ohler55/oj) in your gemfile, you can potentially save up to ~20% response time.
44 |
45 | The middleware can be initialized with custom camelize/dasherize implementations, so if you know you have a fixed size set of keys, you can save a considerable amount of time by providing a custom camelize that caches like so:
46 |
47 | ```ruby
48 | class FastCamel
49 | def self.camel_cache
50 | @camel_cache ||= {}
51 | end
52 |
53 | def self.camelize(string)
54 | camel_cache[string] ||= string.underscore.camelize(:lower)
55 | end
56 | end
57 |
58 |
59 | ...
60 |
61 | config.middleware.use OliveBranch::Middleware, camelize: FastCamel.method(:camelize)
62 | ```
63 |
64 | Default inflection header key can be changed like
65 |
66 | ```ruby
67 | config.middleware.use OliveBranch::Middleware, inflection_header: 'Inflect-With'
68 | ```
69 |
70 | A default inflection can be specified so you don't have to include the `Key-Inflection` header on every request. If you opt for default inflection, you may want to exclude the routes that Rails uses (see Filtering).
71 |
72 | ```ruby
73 | config.middleware.use OliveBranch::Middleware, inflection: 'camel'
74 | ```
75 |
76 | A benchmark of this compared to the standard implementation shows a saving of ~75% rails response times for a complex response payload, or a ~400% improvement, but there is a risk of memory usage ballooning if you have dynamic keys. You can make this method as complex as required, but keep in mind that it will end up being called a _lot_ in a busy app, so it's worth thinking about how to do what you need in the fastest manner possible.
77 |
78 | ### Filtering
79 |
80 | #### Content type
81 |
82 | It is also possible to include a custom content type check in the same manner
83 |
84 | ```ruby
85 | config.middleware.use OliveBranch::Middleware, content_type_check: -> (content_type) {
86 | content_type == "my/content-type"
87 | }
88 | ```
89 |
90 | #### Excluding URLs
91 |
92 | Additionally you can define a custom check by passing a proc
93 |
94 | For params transforming
95 |
96 | ```ruby
97 | config.middleware.use OliveBranch::Middleware, exclude_params: -> (env) {
98 | env['PATH_INFO'].match(/^\/do_not_transform/)
99 | }
100 | ```
101 |
102 | Or response transforming
103 |
104 | ```ruby
105 | config.middleware.use OliveBranch::Middleware, exclude_response: -> (env) {
106 | env['PATH_INFO'].match(/^\/do_not_transform/)
107 | }
108 | ```
109 |
110 | #### Rails routes & Action Text
111 |
112 | If you're using default inflection, exclude the routes that Rails uses
113 | ```ruby
114 | rails_routes = -> (env) { env['PATH_INFO'].match(/^\/rails/) }
115 | config.middleware.use OliveBranch::Middleware, inflection: "camel", exclude_params: rails_routes, exclude_response: rails_routes
116 | ```
117 |
118 | ## Upgrading to version 3
119 |
120 | Default inflection header changed from `X-Key-Inflection` to `Key-Inflection`.
121 |
122 | ## Troubleshooting
123 |
124 | We've seen folks raise issues that inbound transformations are not taking place. This is often due to the fact that OliveBranch, by default, is only transforming keys when a request's Content-Type is `application/json`.
125 |
126 | Note that your HTTP client library may suppress even a manually specified `Content-Type` header if the request body is empty (e.g. [Axios does this](https://github.com/axios/axios/issues/86)). This is a common gotcha for GET requests, the body of which are [often expected to be empty](https://stackoverflow.com/questions/978061/http-get-with-request-body) for reasons of caching. If you're seeing the middleware perform on POST or PATCH requests, but not GET requests, this may be your issue.
127 |
128 | You may choose to force inbound transformation on every request by overriding the `content_type_check` functionality:
129 |
130 | ```ruby
131 | config.middleware.use OliveBranch::Middleware, content_type_check: -> (content_type) { true }
132 | ```
133 |
134 | * * *
135 |
136 | OliveBranch is released under the [MIT License](http://www.opensource.org/licenses/MIT). See MIT-LICENSE for further details.
137 |
138 | * * *
139 |
140 |
141 |
142 |
143 |
144 | Visit [code.viget.com](http://code.viget.com) to see more projects from [Viget.](https://viget.com)
145 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require "bundler/gem_tasks"
2 |
3 | begin
4 | require "rspec/core/rake_task"
5 | RSpec::Core::RakeTask.new(:spec)
6 | task default: :spec
7 | rescue LoadError
8 | end
9 |
10 | task :benchmark do
11 | sh "BENCHMARK_REPETITIONS=1000 rspec spec/benchmark_spec.rb"
12 | end
13 |
--------------------------------------------------------------------------------
/gemfiles/.bundle/config:
--------------------------------------------------------------------------------
1 | ---
2 | BUNDLE_RETRY: "1"
3 |
--------------------------------------------------------------------------------
/gemfiles/.gitignore:
--------------------------------------------------------------------------------
1 | *.gemfile.lock
2 |
--------------------------------------------------------------------------------
/gemfiles/rails_4.1.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "rails", "~> 4.1.16"
6 |
7 | gemspec path: "../"
8 |
--------------------------------------------------------------------------------
/gemfiles/rails_4.2.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "rails", "~> 4.2.11"
6 |
7 | gemspec path: "../"
8 |
--------------------------------------------------------------------------------
/gemfiles/rails_5.0.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "rails", "~> 5.0.7.1"
6 |
7 | gemspec path: "../"
8 |
--------------------------------------------------------------------------------
/gemfiles/rails_5.1.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "rails", "~> 5.1.6.1"
6 |
7 | gemspec path: "../"
8 |
--------------------------------------------------------------------------------
/gemfiles/rails_5.2.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "rails", "~> 5.2.2"
6 |
7 | gemspec path: "../"
8 |
--------------------------------------------------------------------------------
/gemfiles/rails_5.2.gemfile~Ruby on Rails 5.2 & 6.0 and Ruby 2.6.1 testing:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # This file was generated by Appraisal
4 |
5 | source 'https://rubygems.org'
6 |
7 | gem 'rails', '~> 5.2.2'
8 |
9 | gemspec path: '../'
10 |
--------------------------------------------------------------------------------
/gemfiles/rails_6.0.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "rails", "~> 6.0.0.beta1"
6 |
7 | gemspec path: "../"
8 |
--------------------------------------------------------------------------------
/gemfiles/rails_6.1.gemfile:
--------------------------------------------------------------------------------
1 | # This file was generated by Appraisal
2 |
3 | source "https://rubygems.org"
4 |
5 | gem "rails", "~> 6.1.3"
6 |
7 | gemspec path: "../"
8 |
--------------------------------------------------------------------------------
/lib/olive_branch.rb:
--------------------------------------------------------------------------------
1 | module OliveBranch
2 | autoload :Middleware, "olive_branch/middleware"
3 | end
4 |
--------------------------------------------------------------------------------
/lib/olive_branch/middleware.rb:
--------------------------------------------------------------------------------
1 | require "multi_json"
2 |
3 | module OliveBranch
4 | class Checks
5 | def self.content_type_check(content_type)
6 | content_type =~ /application\/json/ || content_type =~ /application\/vnd\.api\+json/
7 | end
8 |
9 | def self.default_exclude(env)
10 | false
11 | end
12 | end
13 |
14 | class Transformations
15 | class << self
16 | def transform(value, transform_method)
17 | case value
18 | when Array then value.map { |item| transform(item, transform_method) }
19 | when Hash then value.deep_transform_keys! { |key| transform(key, transform_method) }
20 | when String then transform_method.call(value)
21 | else value
22 | end
23 | end
24 |
25 | def pascalize(string)
26 | string.underscore.camelize(:upper)
27 | end
28 |
29 | def camelize(string)
30 | string.underscore.camelize(:lower)
31 | end
32 |
33 | def dasherize(string)
34 | string.dasherize
35 | end
36 |
37 | def underscore_params(env)
38 | req = ActionDispatch::Request.new(env)
39 | req.request_parameters
40 | req.query_parameters
41 |
42 | env["action_dispatch.request.request_parameters"].deep_transform_keys!(&:underscore)
43 | env["action_dispatch.request.query_parameters"].deep_transform_keys!(&:underscore)
44 | end
45 | end
46 | end
47 |
48 | class Middleware
49 | def initialize(app, args = {})
50 | @app = app
51 | @camelize = args[:camelize] || Transformations.method(:camelize)
52 | @dasherize = args[:dasherize] || Transformations.method(:dasherize)
53 | @pascalize = args[:pascalize] || Transformations.method(:pascalize)
54 | @content_type_check = args[:content_type_check] || Checks.method(:content_type_check)
55 | @exclude_response = args[:exclude_response] || Checks.method(:default_exclude)
56 | @exclude_params = args[:exclude_params] || Checks.method(:default_exclude)
57 | @default_inflection = args[:inflection]
58 | @inflection_header = args.fetch(:inflection_header, 'Key-Inflection').gsub(/[^a-z0-9]/i, '_').upcase
59 | @inflection_header = "HTTP_#{@inflection_header}" unless @inflection_header.start_with?('HTTP_')
60 | end
61 |
62 | def call(env)
63 | Transformations.underscore_params(env) unless exclude_params?(env)
64 | status, headers, response = @app.call(env)
65 |
66 | return [status, headers, response] if exclude_response?(env, headers)
67 |
68 | new_responses = []
69 |
70 | response.each do |body|
71 | begin
72 | new_response = MultiJson.load(body)
73 | rescue MultiJson::ParseError
74 | new_responses << body
75 | next
76 | end
77 |
78 | Transformations.transform(new_response, inflection_method(env))
79 |
80 | new_responses << MultiJson.dump(new_response)
81 | end
82 |
83 | [status, headers, new_responses]
84 | end
85 |
86 | private
87 |
88 | def exclude_params?(env)
89 | exclude?(env, env["CONTENT_TYPE"], @exclude_params)
90 | end
91 |
92 | def exclude_response?(env, headers)
93 | exclude_rails_route?(env) ||
94 | exclude?(env, headers['Content-Type'], @exclude_response)
95 | end
96 |
97 | def exclude?(env, content_type, block)
98 | !inflection_type(env) || !valid_content_type?(content_type) || block.call(env)
99 | end
100 |
101 | def exclude_rails_route?(env)
102 | env['PATH_INFO'].to_s.start_with?('/rails')
103 | end
104 |
105 | def valid_content_type?(content_type)
106 | @content_type_check.call(content_type)
107 | end
108 |
109 | def inflection_type(env)
110 | env[@inflection_header] || @default_inflection
111 | end
112 |
113 | def inflection_method(env)
114 | inflection = inflection_type(env)
115 |
116 | if inflection == "camel"
117 | @camelize
118 | elsif inflection == "dash"
119 | @dasherize
120 | elsif inflection == 'pascal'
121 | @pascalize
122 | else
123 | # probably misconfigured, do nothing
124 | -> (string) { string }
125 | end
126 | end
127 | end
128 | end
129 |
--------------------------------------------------------------------------------
/lib/olive_branch/version.rb:
--------------------------------------------------------------------------------
1 | module OliveBranch
2 | VERSION = '4.0.1'
3 | end
4 |
--------------------------------------------------------------------------------
/olive_branch.gemspec:
--------------------------------------------------------------------------------
1 | $:.push File.expand_path("../lib", __FILE__)
2 |
3 | require "olive_branch/version"
4 |
5 | Gem::Specification.new do |s|
6 | s.name = "olive_branch"
7 | s.version = OliveBranch::VERSION
8 | s.summary = "Handle camel/snake/dash case conversion"
9 | s.description = "Handle camel/snake/dash case conversion"
10 | s.authors = ["Eli Fatsi", "David Eisinger"]
11 | s.email = ["eli.fatsi@viget.com", "david.eisinger@viget.com"]
12 | s.files = Dir["lib/**/*"] + ["MIT-LICENSE", "README.md"]
13 | s.homepage = "https://github.com/vigetlabs/olive_branch"
14 | s.license = "MIT"
15 |
16 | s.add_dependency "rails", ">= 4.0"
17 | s.add_dependency "multi_json"
18 |
19 | s.add_development_dependency "rspec", "~> 3.5.0"
20 | s.add_development_dependency "appraisal"
21 | s.add_development_dependency "rspec-rails"
22 | end
23 |
--------------------------------------------------------------------------------
/spec/benchmark_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | BENCHMARK_REPETITIONS ||= Integer(ENV["BENCHMARK_REPETITIONS"] || 0)
4 |
5 | if BENCHMARK_REPETITIONS > 0
6 | RSpec.describe 'Benchmark thingerer', :type => :request do
7 | let(:url) { '/posts/complex' }
8 | let(:headers) do
9 | { "CONTENT_TYPE" => "application/json", 'X-Key-Inflection' => 'camel' }
10 | end
11 |
12 | context "when the X-Key-Inflection HTTP header is set to 'camel'" do
13 | it "benchmarks 1000 repetitions" do
14 | Benchmark.bm do |x|
15 | x.report("time taken ") { BENCHMARK_REPETITIONS.times { get_request } }
16 | end
17 | end
18 | end
19 |
20 | def get_request
21 | if Rails::VERSION::MAJOR >= 5
22 | get url, headers: headers
23 | else
24 | get url, headers
25 | end
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/spec/integration_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe 'Integration Test', :type => :request do
4 | let(:url) { '/posts/1234?categoryFilter[categoryName][]=food' }
5 | let(:headers) do
6 | { "CONTENT_TYPE" => "application/json", 'Key-Inflection' => 'camel' }
7 | end
8 | let(:params) do
9 | { 'post' => { 'authorName' => 'John Smith' } }
10 | end
11 |
12 | context "when the Key-Inflection HTTP header is set to 'camel'" do
13 | it "should transform response keys to camel case" do
14 | put_request
15 |
16 | payload = JSON.parse(response.body)
17 |
18 | expect(payload['postAuthorName']).to eq 'John Smith'
19 | expect(payload['categoryFilterName']).to eq ['food']
20 | end
21 |
22 | it "should set the controller's params to be underscored for the request/query parameters" do
23 | put_request
24 |
25 | req_params = JSON.parse(request.env['params_spy'].to_json).with_indifferent_access
26 |
27 | expect(req_params).to include(post: { author_name: 'John Smith' }, category_filter: { category_name: ['food'] })
28 | end
29 |
30 | it "should NOT transform the path params in the controller's params" do
31 | put_request
32 |
33 | req_params = JSON.parse(request.env['params_spy'].to_json).with_indifferent_access
34 |
35 | expect(req_params).to include(postId: "1234")
36 | end
37 | end
38 |
39 | context "when the Key-Inflection HTTP header is not set" do
40 | let(:headers) { { "CONTENT_TYPE" => "application/json" } }
41 |
42 | it "should NOT transform response keys" do
43 | put_request
44 |
45 | payload = JSON.parse(response.body)
46 |
47 | expect(payload['postAuthorName']).to be_nil
48 | expect(payload['categoryFilterName']).to be_nil
49 | expect(payload).to include('post_author_name', 'category_filter_name')
50 | end
51 |
52 | it "should NOT transform the controller's params' keys" do
53 | put_request
54 |
55 | req_params = JSON.parse(request.env['params_spy'].to_json).with_indifferent_access
56 |
57 | expect(req_params).to include(params)
58 | end
59 |
60 | it "should NOT transform the path params in the controller's params" do
61 | put_request
62 |
63 | req_params = JSON.parse(request.env['params_spy'].to_json).with_indifferent_access
64 |
65 | expect(req_params).to include(postId: "1234")
66 | end
67 | end
68 |
69 | def put_request
70 | if Rails::VERSION::MAJOR >= 5
71 | put url, params: params.to_json, headers: headers
72 | else
73 | put url, params.to_json, headers
74 | end
75 | end
76 | end
77 |
--------------------------------------------------------------------------------
/spec/olive_branch/middleware_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | RSpec.describe OliveBranch::Middleware do
4 | describe "modifying request" do
5 | let(:params) do
6 | {
7 | "action_dispatch.request.request_parameters" => {
8 | "post" => {
9 | "authorName" => "Adam Smith"
10 | }
11 | }
12 | }
13 | end
14 |
15 | it "snake cases incoming params if content-type JSON and inflection header present" do
16 | incoming_params = nil
17 |
18 | app = -> (env) do
19 | incoming_params = env["action_dispatch.request.request_parameters"]
20 | [200, {}, ["{}"]]
21 | end
22 |
23 | env = params.merge(
24 | "CONTENT_TYPE" => "application/json",
25 | "HTTP_KEY_INFLECTION" => "camel"
26 | )
27 |
28 | described_class.new(app).call(env)
29 |
30 | expect(incoming_params["post"]["author_name"]).not_to be_nil
31 | end
32 |
33 | it "snake cases incoming query params if content-type JSON and inflection header present" do
34 | incoming_params = nil
35 |
36 | app = -> (env) do
37 | incoming_params = env["action_dispatch.request.query_parameters"]
38 | [200, {}, ["{}"]]
39 | end
40 |
41 | env = params.merge(
42 | "CONTENT_TYPE" => "application/json",
43 | "HTTP_KEY_INFLECTION" => "camel",
44 | "QUERY_STRING" => "categoryFilter[categoryName]=economics",
45 | )
46 |
47 | described_class.new(app).call(env)
48 |
49 | expect(incoming_params["category_filter"]["category_name"]).to eq "economics"
50 | end
51 |
52 | it 'snake cases incoming query with JSON and pascal inflection' do
53 | incoming_params = nil
54 |
55 | app = lambda do |env|
56 | incoming_params = env['action_dispatch.request.query_parameters']
57 | [200, {}, ['{}']]
58 | end
59 |
60 | env = params.merge(
61 | 'CONTENT_TYPE' => 'application/json',
62 | 'HTTP_KEY_INFLECTION' => 'pascal',
63 | 'QUERY_STRING' => 'CategoryFilter[CategoryName]=economics'
64 | )
65 |
66 | described_class.new(app).call(env)
67 |
68 | expect(
69 | incoming_params['category_filter']['category_name']
70 | ).to eq 'economics'
71 | end
72 |
73 | it "does not modify incoming params if content-type not JSON" do
74 | incoming_params = nil
75 |
76 | app = -> (env) do
77 | incoming_params = env["action_dispatch.request.request_parameters"]
78 | [200, {}, ["{}"]]
79 | end
80 |
81 | env = params.merge(
82 | "CONTENT_TYPE" => "text/html",
83 | "HTTP_KEY_INFLECTION" => "camel"
84 | )
85 |
86 | described_class.new(app).call(env)
87 |
88 | expect(incoming_params["post"]["authorName"]).not_to be_nil
89 | end
90 |
91 | it "does not modify incoming params if exclude returns true" do
92 | incoming_params = nil
93 |
94 | app = -> (env) do
95 | incoming_params = env["action_dispatch.request.request_parameters"]
96 | [200, {}, ["{}"]]
97 | end
98 |
99 | env = params.merge(
100 | "CONTENT_TYPE" => "application/json",
101 | "HTTP_KEY_INFLECTION" => "camel",
102 | "PATH_INFO" => "/do_not_transform"
103 | )
104 |
105 | exclude_params = proc do |env|
106 | path = env["PATH_INFO"]
107 | !!path.match(/^\/do_not_transform/)
108 | end
109 |
110 | described_class.new(app, exclude_params: exclude_params).call(env)
111 |
112 | expect(incoming_params["post"]["authorName"]).not_to be_nil
113 | end
114 |
115 | it "does not modify incoming params if inflection header missing" do
116 | incoming_params = nil
117 |
118 | app = -> (env) do
119 | incoming_params = env["action_dispatch.request.request_parameters"]
120 | [200, {}, ["{}"]]
121 | end
122 |
123 | env = params.merge("CONTENT_TYPE" => "application/json")
124 |
125 | described_class.new(app).call(env)
126 |
127 | expect(incoming_params["post"]["authorName"]).not_to be_nil
128 | end
129 |
130 | context "with a custom content type check" do
131 | let(:content_type_check) do
132 | ->(content_type) { content_type == "foo/type" }
133 | end
134 |
135 | it "snake cases incoming params if content-type matches the custom check" do
136 | incoming_params = nil
137 |
138 | app = -> (env) do
139 | incoming_params = env["action_dispatch.request.request_parameters"]
140 | [200, {}, ["{}"]]
141 | end
142 |
143 | env = params.merge(
144 | "CONTENT_TYPE" => "foo/type",
145 | "HTTP_KEY_INFLECTION" => "camel"
146 | )
147 |
148 | described_class.new(app, content_type_check: content_type_check).call(env)
149 |
150 | expect(incoming_params["post"]["author_name"]).not_to be_nil
151 | end
152 |
153 | it "does not modify incoming params if content-type not matching custom check" do
154 | incoming_params = nil
155 |
156 | app = -> (env) do
157 | incoming_params = env["action_dispatch.request.request_parameters"]
158 | [200, {}, ["{}"]]
159 | end
160 |
161 | env = params.merge(
162 | "CONTENT_TYPE" => "application/json",
163 | "HTTP_KEY_INFLECTION" => "camel"
164 | )
165 |
166 | described_class.new(app, content_type_check: content_type_check).call(env)
167 |
168 | expect(incoming_params["post"]["authorName"]).not_to be_nil
169 | end
170 | end
171 | end
172 |
173 | describe "modifying response" do
174 | it "camel-cases response if JSON and inflection header present" do
175 | app = -> (env) do
176 | [
177 | 200,
178 | { "Content-Type" => "application/json" },
179 | ['{"post":{"author_name":"Adam Smith","author-hobby":"Economics"}}']
180 | ]
181 | end
182 |
183 | request = Rack::MockRequest.new(described_class.new(app))
184 |
185 | response = request.get("/", "HTTP_KEY_INFLECTION" => "camel")
186 |
187 | expect(JSON.parse(response.body)["post"]["authorName"]).not_to be_nil
188 | expect(JSON.parse(response.body)["post"]["authorHobby"]).not_to be_nil
189 | end
190 |
191 | it 'camel-cases array response if JSON and inflection header present' do
192 | app = lambda do |_env|
193 | [
194 | 200,
195 | { 'Content-Type' => 'application/json' },
196 | ['[{"author_name":"Adam Smith","author-hobby":"Economics"}]']
197 | ]
198 | end
199 |
200 | request = Rack::MockRequest.new(described_class.new(app))
201 |
202 | response = request.get('/', 'HTTP_KEY_INFLECTION' => 'camel')
203 |
204 | expect(JSON.parse(response.body)[0]['authorName']).not_to be_nil
205 | expect(JSON.parse(response.body)[0]['authorHobby']).not_to be_nil
206 | end
207 |
208 | it "dash-cases response if JSON and inflection header present" do
209 | app = -> (env) do
210 | [
211 | 200,
212 | { "Content-Type" => "application/json" },
213 | ['{"post":{"author_name":"Adam Smith"}}']
214 | ]
215 | end
216 |
217 | request = Rack::MockRequest.new(described_class.new(app))
218 |
219 | response = request.get("/", "HTTP_KEY_INFLECTION" => "dash")
220 |
221 | expect(JSON.parse(response.body)["post"]["author-name"]).not_to be_nil
222 | end
223 |
224 | it 'dash-cases array response if JSON and inflection header present' do
225 | app = lambda do |_env|
226 | [
227 | 200,
228 | { 'Content-Type' => 'application/json' },
229 | ['[{"author_name":"Adam Smith"}]']
230 | ]
231 | end
232 |
233 | request = Rack::MockRequest.new(described_class.new(app))
234 |
235 | response = request.get('/', 'HTTP_KEY_INFLECTION' => 'dash')
236 |
237 | expect(JSON.parse(response.body)[0]['author-name']).not_to be_nil
238 | end
239 |
240 | it 'pascal-cases response if JSON and inflection header are present' do
241 | app = lambda do |_env|
242 | [
243 | 200,
244 | { 'Content-Type' => 'application/json' },
245 | ['{"post":{"author_name":"Adam Smith"}}']
246 | ]
247 | end
248 |
249 | request = Rack::MockRequest.new(described_class.new(app))
250 |
251 | response = request.get('/', 'HTTP_KEY_INFLECTION' => 'pascal')
252 | expect(JSON.parse(response.body)['Post']['AuthorName']).not_to be_nil
253 | end
254 |
255 | it 'pascal-cases array response if JSON and inflection header present' do
256 | app = lambda do |_env|
257 | [
258 | 200,
259 | { 'Content-Type' => 'application/json' },
260 | ['[{"author_name":"Adam Smith","author-hobby":"Economics"}]']
261 | ]
262 | end
263 |
264 | request = Rack::MockRequest.new(described_class.new(app))
265 |
266 | response = request.get('/', 'HTTP_KEY_INFLECTION' => 'pascal')
267 |
268 | expect(JSON.parse(response.body)[0]['AuthorName']).not_to be_nil
269 | expect(JSON.parse(response.body)[0]['AuthorHobby']).not_to be_nil
270 | end
271 |
272 | it "does not modify response if exclude returns true" do
273 | app = -> (env) do
274 | [
275 | 200,
276 | { "Content-Type" => "application/json" },
277 | ['{"post":{"author_name":"Adam Smith"}}']
278 | ]
279 | end
280 |
281 | exclude_response = proc do |env|
282 | path = env["PATH_INFO"]
283 | !!path.match(/^\/do_not_transform/)
284 | end
285 |
286 | request = Rack::MockRequest.new(described_class.new(app, exclude_response: exclude_response))
287 |
288 | response = request.get("/do_not_transform", "HTTP_KEY_INFLECTION" => "camel")
289 |
290 | expect(JSON.parse(response.body)["post"]["author_name"]).not_to be_nil
291 | end
292 |
293 | it 'excludes rails routes by default' do
294 | app = lambda do |_env|
295 | [
296 | 200,
297 | { 'Content-Type' => 'application/json' },
298 | ['{"direct_upload_token": "value1", "attachment_name": "value2"}']
299 | ]
300 | end
301 |
302 | request = Rack::MockRequest.new(described_class.new(app))
303 |
304 | response = request.get('/rails', 'HTTP_KEY_INFLECTION' => 'camel')
305 |
306 | expect(JSON.parse(response.body)['direct_upload_token']).to eq 'value1'
307 | expect(JSON.parse(response.body)['attachment_name']).to eq 'value2'
308 | end
309 |
310 | it "does not modify response if not JSON " do
311 | app = -> (env) do
312 | [
313 | 200,
314 | { "Content-Type" => "text/html" },
315 | ['{"post":{"author_name":"Adam Smith"}}']
316 | ]
317 | end
318 |
319 | request = Rack::MockRequest.new(described_class.new(app))
320 |
321 | response = request.get("/", "HTTP_KEY_INFLECTION" => "camel")
322 |
323 | expect(JSON.parse(response.body)["post"]["author_name"]).not_to be_nil
324 | end
325 |
326 | it "does not modify response if inflection header missing" do
327 | app = -> (env) do
328 | [
329 | 200,
330 | { "Content-Type" => "application/json" },
331 | ['{"post":{"author_name":"Adam Smith"}}']
332 | ]
333 | end
334 |
335 | request = Rack::MockRequest.new(described_class.new(app))
336 |
337 | response = request.get("/")
338 |
339 | expect(JSON.parse(response.body)["post"]["author_name"]).not_to be_nil
340 | end
341 |
342 | it "does not modify response if invalid JSON" do
343 | app = -> (env) do
344 | [
345 | 200,
346 | { "Content-Type" => "application/json" },
347 | ['{"post":{"author_name":"Adam Smith"}']
348 | ]
349 | end
350 |
351 | request = Rack::MockRequest.new(described_class.new(app))
352 |
353 | response = request.get("/", "HTTP_KEY_INFLECTION" => "camel")
354 |
355 | expect(response.body =~ /author_name/).not_to be_nil
356 | end
357 |
358 | context "with custom camelize method" do
359 | let(:camelize) do
360 | ->(string) { "camel#{string}" }
361 | end
362 |
363 | it "uses the custom camelize method" do
364 | app = -> (env) do
365 | [
366 | 200,
367 | { "Content-Type" => "application/json" },
368 | ['{"post":{"author_name":"Adam Smith","author-hobby":"Economics"}}']
369 | ]
370 | end
371 |
372 | request = Rack::MockRequest.new(described_class.new(app, camelize: camelize))
373 |
374 | response = request.get("/", "HTTP_KEY_INFLECTION" => "camel")
375 |
376 | expect(JSON.parse(response.body)["camelpost"]["camelauthor_name"]).not_to be_nil
377 | expect(JSON.parse(response.body)["camelpost"]["camelauthor-hobby"]).not_to be_nil
378 | end
379 | end
380 |
381 | context "with custom dasherize method" do
382 | let(:dasherize) do
383 | ->(string) { "dash#{string}" }
384 | end
385 |
386 | it "uses the custom dasherize method" do
387 | app = -> (env) do
388 | [
389 | 200,
390 | { "Content-Type" => "application/json" },
391 | ['{"post":{"author_name":"Adam Smith","author-hobby":"Economics"}}']
392 | ]
393 | end
394 |
395 | request = Rack::MockRequest.new(described_class.new(app, dasherize: dasherize))
396 |
397 | response = request.get("/", "HTTP_KEY_INFLECTION" => "dash")
398 |
399 | expect(JSON.parse(response.body)["dashpost"]["dashauthor_name"]).not_to be_nil
400 | expect(JSON.parse(response.body)["dashpost"]["dashauthor-hobby"]).not_to be_nil
401 | end
402 | end
403 |
404 | context "with a default inflection" do
405 | it "uses the default inflection" do
406 | app = -> (env) do
407 | [
408 | 200,
409 | { "Content-Type" => "application/json" },
410 | ['{"post":{"author_name":"Adam Smith"}}']
411 | ]
412 | end
413 |
414 | request = Rack::MockRequest.new(described_class.new(app, inflection: 'camel'))
415 |
416 | response = request.get("/")
417 |
418 | expect(JSON.parse(response.body)["post"]["authorName"]).not_to be_nil
419 | end
420 | end
421 |
422 | context "with frozen strings" do
423 | it "dups the string before replacing" do
424 | app = -> (env) do
425 | [
426 | 200,
427 | { "Content-Type" => "application/json" },
428 | ['{"post":{"author_name":"Adam Smith"}}'.freeze]
429 | ]
430 | end
431 |
432 | request = Rack::MockRequest.new(described_class.new(app, inflection: 'camel'))
433 |
434 | response = request.get("/")
435 |
436 | expect(JSON.parse(response.body)["post"]["authorName"]).not_to be_nil
437 | end
438 | end
439 | end
440 | end
441 |
--------------------------------------------------------------------------------
/spec/rails_helper.rb:
--------------------------------------------------------------------------------
1 | # This file is copied to spec/ when you run 'rails generate rspec:install'
2 | require 'spec_helper'
3 | ENV['RAILS_ENV'] ||= 'test'
4 | require File.expand_path('../test_app/config/environment', __FILE__)
5 | abort("The Rails environment is running in production mode!") if Rails.env.production?
6 | require 'rspec/rails'
7 |
8 | RSpec.configure do |config|
9 | config.infer_spec_type_from_file_location!
10 | config.filter_rails_from_backtrace!
11 | end
12 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | require 'olive_branch'
2 |
3 | # This file was generated by the `rails generate rspec:install` command. Conventionally, all
4 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
5 | # The generated `.rspec` file contains `--require spec_helper` which will cause
6 | # this file to always be loaded, without a need to explicitly require it in any
7 | # files.
8 | #
9 | # Given that it is always loaded, you are encouraged to keep this file as
10 | # light-weight as possible. Requiring heavyweight dependencies from this file
11 | # will add to the boot time of your test suite on EVERY test run, even for an
12 | # individual file that may not need all of that loaded. Instead, consider making
13 | # a separate helper file that requires the additional dependencies and performs
14 | # the additional setup, and require it from the spec files that actually need
15 | # it.
16 | #
17 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
18 | RSpec.configure do |config|
19 | # rspec-expectations config goes here. You can use an alternate
20 | # assertion/expectation library such as wrong or the stdlib/minitest
21 | # assertions if you prefer.
22 | config.expect_with :rspec do |expectations|
23 | # This option will default to `true` in RSpec 4. It makes the `description`
24 | # and `failure_message` of custom matchers include text for helper methods
25 | # defined using `chain`, e.g.:
26 | # be_bigger_than(2).and_smaller_than(4).description
27 | # # => "be bigger than 2 and smaller than 4"
28 | # ...rather than:
29 | # # => "be bigger than 2"
30 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true
31 | end
32 |
33 | # rspec-mocks config goes here. You can use an alternate test double
34 | # library (such as bogus or mocha) by changing the `mock_with` option here.
35 | config.mock_with :rspec do |mocks|
36 | # Prevents you from mocking or stubbing a method that does not exist on
37 | # a real object. This is generally recommended, and will default to
38 | # `true` in RSpec 4.
39 | mocks.verify_partial_doubles = true
40 | end
41 |
42 | # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
43 | # have no way to turn it off -- the option exists only for backwards
44 | # compatibility in RSpec 3). It causes shared context metadata to be
45 | # inherited by the metadata hash of host groups and examples, rather than
46 | # triggering implicit auto-inclusion in groups with matching metadata.
47 | config.shared_context_metadata_behavior = :apply_to_host_groups
48 |
49 | # The settings below are suggested to provide a good initial experience
50 | # with RSpec, but feel free to customize to your heart's content.
51 | =begin
52 | # This allows you to limit a spec run to individual examples or groups
53 | # you care about by tagging them with `:focus` metadata. When nothing
54 | # is tagged with `:focus`, all examples get run. RSpec also provides
55 | # aliases for `it`, `describe`, and `context` that include `:focus`
56 | # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
57 | config.filter_run_when_matching :focus
58 |
59 | # Allows RSpec to persist some state between runs in order to support
60 | # the `--only-failures` and `--next-failure` CLI options. We recommend
61 | # you configure your source control system to ignore this file.
62 | config.example_status_persistence_file_path = "spec/examples.txt"
63 |
64 | # Limits the available syntax to the non-monkey patched syntax that is
65 | # recommended. For more details, see:
66 | # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
67 | # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
68 | # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
69 | config.disable_monkey_patching!
70 |
71 | # Many RSpec users commonly either run the entire suite or an individual
72 | # file, and it's useful to allow more verbose output when running an
73 | # individual spec file.
74 | if config.files_to_run.one?
75 | # Use the documentation formatter for detailed output,
76 | # unless a formatter has already been configured
77 | # (e.g. via a command-line flag).
78 | config.default_formatter = "doc"
79 | end
80 |
81 | # Print the 10 slowest examples and example groups at the
82 | # end of the spec run, to help surface which specs are running
83 | # particularly slow.
84 | config.profile_examples = 10
85 |
86 | # Run specs in random order to surface order dependencies. If you find an
87 | # order dependency and want to debug it, you can fix the order by providing
88 | # the seed, which is printed after each run.
89 | # --seed 1234
90 | config.order = :random
91 |
92 | # Seed global randomization in this process using the `--seed` CLI option.
93 | # Setting this allows you to use `--seed` to deterministically reproduce
94 | # test failures related to randomization by passing the same `--seed` value
95 | # as the one that triggered the failure.
96 | Kernel.srand config.seed
97 | =end
98 | end
99 |
--------------------------------------------------------------------------------
/spec/test_app/.gitignore:
--------------------------------------------------------------------------------
1 | tmp/pids/*
2 |
--------------------------------------------------------------------------------
/spec/test_app/Rakefile:
--------------------------------------------------------------------------------
1 | require_relative 'config/application'
2 |
3 | Rails.application.load_tasks
4 |
--------------------------------------------------------------------------------
/spec/test_app/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | # ApplicationController
2 | class ApplicationController < ActionController::Base; end
3 |
--------------------------------------------------------------------------------
/spec/test_app/app/controllers/posts_controller.rb:
--------------------------------------------------------------------------------
1 | # PostsController
2 | class PostsController < ApplicationController
3 | COMPLEX_RESPONSE ||= JSON.parse(
4 | File.read(Rails.root.join('example_responses/complex.json'))
5 | )
6 |
7 | def update
8 | request.env['params_spy'] = params
9 |
10 | payload = {
11 | post_author_name: params[:post][:author_name],
12 | category_filter_name: (params[:category_filter] || {})[:category_name]
13 | }
14 |
15 | render json: payload
16 | end
17 |
18 | def complex
19 | render json: COMPLEX_RESPONSE
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/spec/test_app/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/spec/test_app/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | APP_PATH = File.expand_path('../config/application', __dir__)
3 | require_relative '../config/boot'
4 | require 'rails/commands'
5 |
--------------------------------------------------------------------------------
/spec/test_app/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require_relative '../config/boot'
3 | require 'rake'
4 | Rake.application.run
5 |
--------------------------------------------------------------------------------
/spec/test_app/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require_relative 'config/environment'
4 |
5 | run Rails.application
6 |
--------------------------------------------------------------------------------
/spec/test_app/config/application.rb:
--------------------------------------------------------------------------------
1 | require_relative 'boot'
2 |
3 | require 'action_controller/railtie'
4 | require 'olive_branch'
5 |
6 | Bundler.require(*Rails.groups)
7 |
8 | module TestApp
9 | # Application
10 | class Application < Rails::Application
11 | # Initialize configuration defaults for originally generated Rails version.
12 | config.load_defaults 5.1 if config.respond_to?(:load_defaults)
13 |
14 | config.middleware.use OliveBranch::Middleware
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/spec/test_app/config/boot.rb:
--------------------------------------------------------------------------------
1 | # Set up gems listed in the Gemfile.
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__)
3 |
4 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5 | $LOAD_PATH.unshift File.expand_path('../../../lib', __dir__)
6 |
--------------------------------------------------------------------------------
/spec/test_app/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require_relative 'application'
3 |
4 | # Initialize the Rails application.
5 | Rails.application.initialize!
6 |
--------------------------------------------------------------------------------
/spec/test_app/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | config.cache_classes = false
3 | config.eager_load = false
4 | config.consider_all_requests_local = true
5 | config.active_support.deprecation = :log
6 | end
7 |
--------------------------------------------------------------------------------
/spec/test_app/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | config.cache_classes = true
3 | config.eager_load = true
4 | config.consider_all_requests_local = false
5 | config.action_controller.perform_caching = true
6 | config.read_encrypted_secrets = true
7 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
8 | config.log_level = :debug
9 | config.log_tags = [:request_id]
10 | config.i18n.fallbacks = true
11 | config.active_support.deprecation = :notify
12 | config.log_formatter = ::Logger::Formatter.new
13 | end
14 |
--------------------------------------------------------------------------------
/spec/test_app/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | Rails.application.configure do
2 | config.cache_classes = true
3 | config.eager_load = false
4 | config.consider_all_requests_local = true
5 | config.action_controller.perform_caching = false
6 | config.action_dispatch.show_exceptions = false
7 | config.action_controller.allow_forgery_protection = false
8 | config.active_support.deprecation = :stderr
9 | end
10 |
--------------------------------------------------------------------------------
/spec/test_app/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Specify a serializer for the signed and encrypted cookie jars.
4 | # Valid options are :json, :marshal, and :hybrid.
5 | Rails.application.config.action_dispatch.cookies_serializer = :json
6 |
--------------------------------------------------------------------------------
/spec/test_app/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Configure sensitive parameters which will be filtered from the log file.
4 | Rails.application.config.filter_parameters += [:password]
5 |
--------------------------------------------------------------------------------
/spec/test_app/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | ActiveSupport.on_load(:action_controller) do
2 | wrap_parameters format: [:json]
3 | end
4 |
--------------------------------------------------------------------------------
/spec/test_app/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | # NOTE: The camelized path parameter is used to test that we do *not* apply
3 | # any transformations on path parameters.
4 | put 'posts/:postId', format: :json, to: 'posts#update'
5 | get 'posts/complex', format: :json, to: 'posts#complex'
6 | end
7 |
--------------------------------------------------------------------------------
/spec/test_app/config/secrets.yml:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key is used for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 |
6 | # Make sure the secret is at least 30 characters and all random,
7 | # no regular words or you'll be exposed to dictionary attacks.
8 | # You can use `rails secret` to generate a secure secret key.
9 |
10 | # Make sure the secrets in this file are kept private
11 | # if you're sharing your code publicly.
12 |
13 | # Shared secrets are available across all environments.
14 |
15 | # shared:
16 | # api_key: a1B2c3D4e5F6
17 |
18 | # Environmental secrets are only available for that specific environment.
19 |
20 | development:
21 | secret_key_base: df191712ea642f3dde713d27fb8e7936557b490ed82cc8da8904623290594a5376a50ac46a33a7c6804fc16f59f11a87efbef31805c4305b43b1bc2175c217b8
22 |
23 | test:
24 | secret_key_base: 7911e48bffad7dddbaa6faf1fa71af8190046bf0847632ce70555faf7dc42079148f822ed4d081442d0a406771d0befdc6662d642ceaeb5e632323ec3191b21f
25 |
26 | # Do not keep production secrets in the unencrypted secrets file.
27 | # Instead, either read values from the environment.
28 | # Or, use `bin/rails secrets:setup` to configure encrypted secrets
29 | # and move the `production:` environment over there.
30 |
31 | production:
32 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
33 |
--------------------------------------------------------------------------------
/spec/test_app/config/spring.rb:
--------------------------------------------------------------------------------
1 | %w[
2 | .ruby-version
3 | .rbenv-vars
4 | tmp/restart.txt
5 | tmp/caching-dev.txt
6 | ].each { |path| Spring.watch(path) }
7 |
--------------------------------------------------------------------------------
/spec/test_app/example_responses/complex.json:
--------------------------------------------------------------------------------
1 | {"data":{"id":"","type":"","attributes":{"max_score":null,"current_page":1,"total_pages":2,"total_items":38,"start_index":1,"end_index":24,"aggregations":{"categories":[{"key":"","doc_count":6719},{"key":"","doc_count":4478},{"key":"","doc_count":3001},{"key":"","doc_count":2397},{"key":"","doc_count":2188},{"key":"","doc_count":2179},{"key":"","doc_count":1822},{"key":"","doc_count":1288},{"key":"","doc_count":1104},{"key":"","doc_count":1024},{"key":"","doc_count":817},{"key":"","doc_count":780},{"key":"","doc_count":751},{"key":"","doc_count":731},{"key":"","doc_count":686},{"key":"","doc_count":489},{"key":"","doc_count":466},{"key":"","doc_count":464},{"key":"","doc_count":364},{"key":"","doc_count":233},{"key":"","doc_count":206},{"key":"","doc_count":190},{"key":"","doc_count":187},{"key":"","doc_count":155},{"key":"","doc_count":143},{"key":"","doc_count":121},{"key":"","doc_count":98},{"key":"","doc_count":83},{"key":"","doc_count":74},{"key":"","doc_count":73},{"key":"","doc_count":72},{"key":"","doc_count":63},{"key":"","doc_count":59},{"key":"","doc_count":50},{"key":"","doc_count":48},{"key":"","doc_count":46},{"key":"","doc_count":32},{"key":"","doc_count":29},{"key":"","doc_count":25},{"key":"","doc_count":14},{"key":"","doc_count":8},{"key":"","doc_count":6},{"key":"","doc_count":4}],"item_attributes":{"retina_ready":[],"add_ons_applications_supported":[],"columns":[],"graphics_applications_supported":[],"min_browser_version":[],"graphic_templates_applications_supported":[{"key":"","doc_count":36}],"colors":[],"is_tileable":[],"email_platforms":[],"spacing":[],"sizes":[],"html_templates_file_types":[],"has_documentation":[{"key":1,"key_as_string":"","doc_count":34},{"key":0,"key_as_string":"","doc_count":1}],"psd_files_included":[],"presentation_templates_file_types":[],"dpi":[{"key":300,"doc_count":20},{"key":72,"doc_count":6},{"key":150,"doc_count":2},{"key":350,"doc_count":2}],"color_space":[{"key":"","doc_count":38}],"web_templates_file_types":[],"orientation":[{"key":"","doc_count":34},{"key":"","doc_count":1},{"key":"","doc_count":1}],"presentation_templates_applications_supported":[],"optimum_size":[],"fonts_file_types":[],"serif_sans_serif":[],"sketch_files_included":[],"graphics_file_types":[],"is_webfont":[],"layout":[],"add_ons_file_types":[],"graphic_templates_file_types":[{"key":"","doc_count":37},{"key":"","doc_count":2},{"key":"","doc_count":2},{"key":"","doc_count":2}],"background":[],"preview_url":[],"responsive":[],"is_layered":[{"key":1,"key_as_string":"","doc_count":37}],"is_vector":[{"key":1,"key_as_string":"","doc_count":1}],"ecommerce_ready":[],"dimensions":[]},"tags":[],"item_type":{"graphic-templates":10123,"3d":6719,"graphics":5952,"fonts":1301,"web-templates":1014,"presentation-templates":731,"add-ons":653,"cms-templates":604,"photos":0},"total_library_size":27097},"items":[{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":[""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":220712478,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":[""],"item_attributes":{"orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":155630782,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":["",""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_vector":"","is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":56637739,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":[""],"item_attributes":{"orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":56274348,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","",""],"categories":[""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":97720223,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":["",""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":685945639,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":["",""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":65654090,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":[""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":71500197,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":["",""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":999403649,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":["",""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":803774132,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":[""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":377501157,"market_item":{"id":"","demo_url":null,"legacy_id":19872404},"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":[""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":["","",""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":438813458,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":[""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":378215054,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":[""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":["",""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":2950706606,"market_item":{"id":"","demo_url":null,"legacy_id":14771025},"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","",""],"categories":[""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":324307632,"market_item":{"id":"","demo_url":null,"legacy_id":19757621},"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":null,"description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":["",""],"item_attributes":{"orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":177486091,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":["",""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":580924352,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":["",""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":785042196,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":["",""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":103014265,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":[""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":690117106,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":["",""],"item_attributes":{"dpi":"","dimensions":{"width":"","height":"","unit":""},"graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":922304110,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":["",""],"item_attributes":{"dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":26296645,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":["",""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":560458794,"market_item":null,"pixelsquid_product":null},{"id":"","item_uuid":"","slug":"","title":"","sub_title":"","description":"","item_type":"","item_type_name":"","saleable":true,"published_at":"","updated_at":"","tags":["","","","","","","","","","","","","","",""],"categories":[""],"item_attributes":{"dpi":"","orientation":"","dimensions":{"width":"","height":"","unit":""},"is_layered":"","graphic_templates_applications_supported":[""],"has_documentation":"","graphic_templates_file_types":[""],"color_space":""},"cover_image":{"id":"","signed_image_set_sizes":{"w140":"","w174":"","w316":"","w355":"","w433":"","w632":"","w710":"","w866":"","w900":"","w1019":"","w1170":"","w1370":"","w2038":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":"","og1200x800":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},"preview_images":[{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""},{"id":"","signed_image_set_sizes":{"w316":"","w632":"","w900":"","w1170":"","w1370":"","w2740":"","tn60x40":"","tn120x80":"","tn316x211":"","tn632x421":""},"file_extension":"","s3_bucket_name":"","cdn_subdomain":"","provider_cloud_name":""}],"contributor_username":"","file_name":"","file_size_bytes":141776759,"market_item":{"id":"","demo_url":null,"legacy_id":13563329},"pixelsquid_product":null}]}}}
2 |
--------------------------------------------------------------------------------
/spec/test_app/log/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 |
--------------------------------------------------------------------------------
/spec/test_app/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vigetlabs/olive_branch/8bd792610945ff3dc7b379a0aa7e039aa79a4e94/spec/test_app/log/.keep
--------------------------------------------------------------------------------
/spec/test_app/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
You may have mistyped the address or the page may have moved.
63 |If you are the application owner check the logs for more information.
65 |Maybe you tried to change something you didn't have access to.
63 |If you are the application owner check the logs for more information.
65 |If you are the application owner check the logs for more information.
64 |