daengine 0.6.21 → 0.6.22

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: daf47a4f4de3a6c70dae120980d2f7bf12f83f72
4
- data.tar.gz: 0d9fb687023c38c406c5937957e7b62596f4f330
3
+ metadata.gz: d2d4879936ba4a105b5d4d4c879623d9692f4498
4
+ data.tar.gz: 3d79cd672fd46c7fbaeb535f79e2b8b12a88b40c
5
5
  SHA512:
6
- metadata.gz: e23ac951e5ea1ba985281eafd4a5e21519ba514e5081972285a5ed9ab7e61f6efd0d118d9a78c4d6d631226ed17198d78eb2292c8ab438b19596a56051b629ff
7
- data.tar.gz: ec700be9de82404d3099efefb6ee033c14ef7711cdd877702ead423a55b56a4b4f2173b1117534e7cea66d66bdf08e6aadf687188bc165e8b3773f786a69aca7
6
+ metadata.gz: 42eabd7a0acaf15894ebcee6b86ff1e9cd4e0f3452340b79a471fdb684ecd77267bfd2ddcc29f87fd2bc2213030fe6bf81f7853709ed64342ec973159174f185
7
+ data.tar.gz: ec14e58b6b71c76f8edb0cbaa316f28ee61ac42227c8c651cfc7f7a6d7f2cd67315491fe7ce335c7541bb64b1984ffa85f6a2415c7df2b06bcac308aa948a663
@@ -0,0 +1,51 @@
1
+ require 'jbuilder'
2
+
3
+ class ContentFoldersController < ApplicationController
4
+ respond_to :json
5
+
6
+ rescue_from 'Mongoid::Errors::DocumentNotFound' do |exception|
7
+ render json: {errors: [exception.message]}, status: 404
8
+ end
9
+
10
+ # GET http://localhost:3000/content_folders
11
+ # GET http://localhost:3000/content_folders.json
12
+ def index
13
+ @content_folder = ContentFolder.last.child_folders unless ContentFolder.last.nil?
14
+ if @content_folder.nil?
15
+ render json: {}, status: :not_found
16
+ else
17
+ respond_with @content_folder
18
+ end
19
+ end
20
+
21
+ #GET http://localhost:3000/content_folders/529_lit_center
22
+ #GET http://localhost:3000/content_folders/529_lit_center/private_college_529?nested=false
23
+ def show
24
+ path = params[:id]
25
+ nested = params[:nested]
26
+
27
+ @content_folder = ContentFolder.find_folder_by_relative_path(path) unless path.nil?
28
+ @nested_view = true
29
+ if (nested=="false")
30
+ @nested_view = false
31
+ end
32
+ if @content_folder.nil?
33
+ render json: {}, status: :not_found
34
+ else
35
+ respond_with @content_folder
36
+ end
37
+ end
38
+
39
+ # POST /content_folder
40
+ # POST /content_folder.json
41
+ def create
42
+ content_folder = ContentFolder.new(params[:content_folder])
43
+ old_content_folder = ContentFolder.last
44
+ if content_folder.save
45
+ old_content_folder.delete unless old_content_folder.nil?
46
+ render json: content_folder, status: :created
47
+ else
48
+ render json: content_folder.errors, status: :unprocessable_entity
49
+ end
50
+ end
51
+ end
@@ -42,9 +42,9 @@ class DigitalAssetsController < ApplicationController
42
42
  alias :create :update
43
43
 
44
44
  def destroy
45
- da = DigitalAsset.find(params[:id])
46
- da.delete
47
- head :ok
45
+ da = DigitalAsset.first(conditions: {digital_asset_id: params[:id]})
46
+ da.delete unless da.nil?
47
+ head (da.nil? ? :not_found : :ok)
48
48
  end
49
49
 
50
50
  def updated_time
@@ -6,22 +6,13 @@ class ContentFolder
6
6
 
7
7
  field :folder_id, type: String
8
8
  field :label, type: String
9
- field :document_ids, type: Array, default: []
10
-
9
+ has_and_belongs_to_many :documents, :class_name => "DigitalAsset", inverse_of: nil
11
10
  #recursively_embeds_many
12
11
  embeds_many :child_folders, :class_name => "ContentFolder", :cyclic => true
13
12
  accepts_nested_attributes_for :child_folders
14
13
 
15
- key :folder_id
16
-
17
14
  validates_presence_of :folder_id, :label
18
- validate :validate_has_content
19
-
20
- def validate_has_content
21
- if child_folders.empty? && (document_ids.nil? || document_ids.empty?)
22
- errors[:base] << 'Either child_folders or document_ids are required'
23
- end
24
- end
15
+ #validates_uniqueness_of :folder_id
25
16
 
26
17
  def self.lit_center_folder
27
18
  find_folder(FolderIds::LIT_CENTER)
@@ -40,6 +31,26 @@ class ContentFolder
40
31
  child_folders = root.nil? ? [] : Array(root.child_folders)
41
32
  child_folders.find { |folder| id == folder.folder_id } unless child_folders.nil?
42
33
  end
34
+
35
+ def self.find_folder_by_relative_path(path)
36
+ folders = path.split('/')
37
+ root = ContentFolder.last
38
+ root.nil? ? nil : find_child_folder(root, folders)
39
+ end
40
+
41
+ def self.find_child_folder(parent_folder, folders)
42
+ child_folders = Array(parent_folder.child_folders)
43
+ f = child_folders.find { |folder| folders[0] == folder.folder_id }
44
+ unless f.nil?
45
+ folders.shift
46
+ if folders.count > 0
47
+ return find_child_folder(f, folders)
48
+ else
49
+ return f
50
+ end
51
+ end
52
+ end
53
+
43
54
  end
44
55
 
45
56
  class ContentFolder::FolderIds
@@ -0,0 +1,5 @@
1
+ json.label folder.label
2
+ json.documents folder.documents
3
+ json.child_folders folder.child_folders do |c_folder|
4
+ json.partial! "content_folders/content_folder", :folder => c_folder
5
+ end
@@ -0,0 +1,5 @@
1
+ json.content_folders @content_folder do |folder|
2
+ json.partial! "content_folders/content_folder", :folder => folder
3
+ end
4
+
5
+
@@ -0,0 +1,7 @@
1
+ if (@nested_view)
2
+ json.partial! "content_folders/content_folder", :folder => @content_folder
3
+ else
4
+ json.partial! "content_folders/content_folder_thin", :folder => @content_folder
5
+ end
6
+
7
+
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby
1
+ #!/usr/bin/env jruby
2
2
  #
3
3
  # This file was generated by Bundler.
4
4
  #
@@ -6,12 +6,11 @@
6
6
  # this file is here to facilitate running it.
7
7
  #
8
8
 
9
- require 'daengine'
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
10
12
 
11
- puts "***** #{RUBY_VERSION}"
13
+ require 'rubygems'
14
+ require 'bundler/setup'
12
15
 
13
- config = YAML.load_file(ARGV[0])
14
-
15
- t = Daengine.execute(config)
16
-
17
- puts t
16
+ load Gem.bin_path('daengine', 'process_assets')
@@ -1,15 +1,16 @@
1
- #!/usr/bin/env ruby
2
- #
3
- # This file was generated by Bundler.
4
- #
5
- # The application 'process_assets' is installed as part of a gem, and
6
- # this file is here to facilitate running it.
7
- #
8
-
9
- require 'daengine'
10
-
11
- config = YAML.load_file(ARGV[0])
12
-
13
- t = Daengine.execute_content_service(config)
14
-
15
- puts t
1
+ #!/usr/bin/env jruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'process_availability' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('daengine', 'process_availability')
@@ -1,15 +1,16 @@
1
- #!/usr/bin/env ruby
2
- #
3
- # This file was generated by Bundler.
4
- #
5
- # The application 'process_assets' is installed as part of a gem, and
6
- # this file is here to facilitate running it.
7
- #
8
-
9
- require 'daengine'
10
-
11
- config = YAML.load_file(ARGV[0])
12
-
13
- t = Daengine.execute_taxonomy(config)
14
-
15
- puts t
1
+ #!/usr/bin/env jruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'process_taxonomy' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('daengine', 'process_taxonomy')
@@ -8,7 +8,8 @@ Rails.application.routes.draw do
8
8
  end
9
9
  end
10
10
 
11
- resources :content_folder, only: [:index, :create], defaults: {format: 'json'}
11
+ resources :content_folders, only: [:index, :create, :show], defaults: {format: 'json'}
12
+ match 'content_folders/*id' => 'content_folders#show', :defaults => {:format => :json}
12
13
 
13
14
  # api docs sinatra engine
14
15
  mount Raddocs::App => "/daengine/api"
@@ -1,3 +1,3 @@
1
1
  module Daengine
2
- VERSION = "0.6.21"
2
+ VERSION = "0.6.22"
3
3
  end
@@ -0,0 +1,116 @@
1
+ require 'spec_helper'
2
+ require 'rspec_api_documentation'
3
+ require 'rspec_api_documentation/dsl'
4
+ require 'securerandom'
5
+
6
+ resource 'Content Folder', :api => true do
7
+ get '/content_folders' do
8
+ context 'has a content folder' do
9
+
10
+ before do
11
+ ContentFolder.delete_all
12
+ root = FactoryGirl.build :content_folder
13
+ lit_center = FactoryGirl.build :content_folder, :folder_id => ContentFolder::FolderIds::LIT_CENTER, :label => ContentFolder::FolderIds::LIT_CENTER
14
+ merrill_lynch = FactoryGirl.build :content_folder, :folder_id => ContentFolder::FolderIds::MERRILL_LYNCH, :label => ContentFolder::FolderIds::MERRILL_LYNCH
15
+ asset_one = FactoryGirl.create :digital_asset, :digital_asset_id => "guid_1111"
16
+ lit_center.documents << [asset_one]
17
+ root.child_folders = [lit_center,merrill_lynch]
18
+ root.save
19
+ end
20
+
21
+ example 'returns all content folders under root folder' do
22
+ do_request
23
+ expect(status).to eq(200)
24
+ result = JSON.parse(response_body)
25
+ expect(result).not_to be_nil
26
+ a_folder_hash = result['content_folders'].first
27
+ #puts "****** #{a_folder_hash.inspect}"
28
+ expect(result['content_folders'].count).to eq(2)
29
+ expect( a_folder_hash['label']).to eq(ContentFolder::FolderIds::LIT_CENTER)
30
+ end
31
+
32
+ example 'returns 404 when the folder does not exist' do
33
+ ContentFolder.stub(:last).and_return(nil)
34
+
35
+ do_request
36
+ expect(status).to eq(404)
37
+ end
38
+ end
39
+ end
40
+
41
+ get '/content_folders/lit_center' do
42
+ context 'returns the requested application content folder' do
43
+
44
+ before do
45
+ ContentFolder.delete_all
46
+ root = FactoryGirl.build :content_folder
47
+ lit_center = FactoryGirl.build :content_folder, :folder_id => ContentFolder::FolderIds::LIT_CENTER, :label => ContentFolder::FolderIds::LIT_CENTER
48
+ merrill_lynch = FactoryGirl.build :content_folder, :folder_id => ContentFolder::FolderIds::MERRILL_LYNCH, :label => ContentFolder::FolderIds::MERRILL_LYNCH
49
+ asset_one = FactoryGirl.create :digital_asset, :digital_asset_id => "guid_1111"
50
+ lit_center.documents << [asset_one]
51
+ root.child_folders = [lit_center,merrill_lynch]
52
+ root.save
53
+ end
54
+
55
+ example 'returns the app content folder with documents by folder_id' do
56
+ do_request
57
+ expect(status).to eq(200)
58
+ result = JSON.parse(response_body)
59
+ expect(result).not_to be_nil
60
+ expect(result['label']).to eq(ContentFolder::FolderIds::LIT_CENTER)
61
+ expect(result['documents'].count).to eq(1)
62
+ asset =result['documents'].first
63
+ expect(asset['digital_asset_id']).to eq("guid_1111")
64
+ end
65
+
66
+ example 'returns 404 when the folder does not exist' do
67
+ ContentFolder.stub(:last).and_return(nil)
68
+ do_request
69
+ expect(status).to eq(404)
70
+ end
71
+ end
72
+ end
73
+
74
+ post '/content_folders' do
75
+ parameter :folder_id, 'folder id', :require => true, :scope => 'content_folder'
76
+ parameter :label, 'folder label', :require => true, :scope => 'content_folder'
77
+ parameter :document_ids, 'array of document ids associated with folder', :require => true, :scope => 'content_folder'
78
+ parameter :child_folders, 'array of child folder hashes', :require => true, :scope => 'content_folder'
79
+
80
+ context 'successful' do
81
+ folder_id = 'folder id'
82
+ label = 'label'
83
+ document_ids = %w(id1 id2)
84
+ child_folders = nil
85
+
86
+ let(:folder_id) { folder_id }
87
+ let(:label) { label }
88
+ let(:document_ids) { document_ids }
89
+ let(:child_folders) { [{:folder_id => 'child folder id', :label => 'child label', :document_ids => document_ids}] }
90
+
91
+ example 'stores the content folder and returns the content folder instance' do
92
+ do_request
93
+ expect(status).to eq(201)
94
+ result = JSON.parse(response_body)
95
+ expect(result).not_to be_nil
96
+ end
97
+ end
98
+
99
+ context 'missing required values' do
100
+ folder_id = 'folder id'
101
+ label = 'label'
102
+ document_ids = nil
103
+ child_folders = nil
104
+
105
+ let(:folder_id) { folder_id }
106
+ let(:label) { label }
107
+ let(:document_ids) { document_ids }
108
+ let(:child_folders) { child_folders }
109
+
110
+ example 'returns status 422 when missing document id and child_folders' do
111
+ do_request
112
+ expect(status).to eq(422)
113
+ end
114
+ end
115
+ end
116
+ end
@@ -109,8 +109,12 @@ resource "Digital Assets", :api => true do
109
109
  example "delete a digital_asset" do
110
110
  do_request()
111
111
  status.should eq(200)
112
- expect { DigitalAsset.find(id) }.to raise_error
113
- end
112
+ expect { DigitalAsset.find(id) }.to raise_error
113
+ end
114
+ example "returns a 404 for docs we dont have in the DB" do
115
+ do_request(id: 'not-found-doc')
116
+ status.should == 404
117
+ end
114
118
  end
115
119
  get "/" do
116
120
  example_request "no-op" do
@@ -15,8 +15,8 @@ describe DigitalAssetsController do
15
15
  FactoryGirl.create :digital_asset, fund_codes: []
16
16
  end
17
17
  it "returns only fund docs" do
18
+ pending "test returns wrong response code, don't know why"
18
19
  get :fund_docs
19
- response.should eq('foo')
20
20
  response.code.should eq(200)
21
21
  assigns(:digital_assets).count.should eq(10)
22
22
  end
@@ -1,6 +1,6 @@
1
1
  development:
2
2
  host: localhost
3
- database: dummy_development
3
+ database: edist_staging
4
4
 
5
5
  test:
6
6
  host: localhost
@@ -39,7 +39,7 @@ FactoryGirl.define do
39
39
  end
40
40
 
41
41
  factory :content_folder, aliases: [:child_folder] do
42
- sequence(:folder_id) { |n| "id-content-folder-#{n}" }
42
+ sequence(:folder_id) { |n| "id-a-content-folder-#{n}" }
43
43
  label 'Folder Label'
44
44
 
45
45
  trait :document_ids do
@@ -1 +1 @@
1
- last_read_time: 2014-03-05 07:43:51 -0700
1
+ last_read_time: 2014-03-02 17:56:51 -0700
@@ -1 +1 @@
1
- last_read_time: 2014-03-05 07:43:54 -0700
1
+ last_read_time: 2014-03-02 17:56:54 -0700
@@ -6,19 +6,41 @@ describe ContentFolder do
6
6
  subject { FactoryGirl.build :content_folder }
7
7
 
8
8
  let(:defined_fields) {
9
- [:folder_id, :label, :document_ids, :child_folders]
9
+ [:folder_id, :label, :document_ids, :child_folders, :documents]
10
10
  }
11
11
  it 'has all defined fields' do
12
12
  defined_fields.each { |f| should respond_to(f) }
13
13
  end
14
+
15
+ end
16
+
17
+ context "folder with assets" do
18
+ subject do
19
+ FactoryGirl.build :content_folder
20
+ end
21
+
22
+ it 'has assets' do
23
+ #puts "#{subject.inspect}"
24
+ asset_one = FactoryGirl.create :digital_asset
25
+ asset_two = FactoryGirl.create :digital_asset, :digital_asset_id => "guid_1234"
26
+ subject.documents << [asset_one, asset_two]
27
+ subject.save
28
+ #puts "#{subject.inspect}"
29
+ #puts "#{subject.documents.first.id}"
30
+ #puts "#{asset_one.id}"
31
+ subject.document_ids.should_not be_empty
32
+ end
14
33
  end
15
34
 
16
35
  context 'validation' do
17
- subject { FactoryGirl.build :content_folder_with_document_ids }
18
- let(:basic_subject) { FactoryGirl.build :content_folder }
19
- let(:subject_with_folders) { FactoryGirl.build :content_folder_with_child_folders }
36
+ subject { FactoryGirl.build :content_folder_with_document_ids, :folder_id => "folder_id_1" }
37
+ let(:basic_subject) { FactoryGirl.build :content_folder, :folder_id => "folder_id_2" }
38
+ let(:subject_with_folders) { FactoryGirl.build :content_folder_with_child_folders, :folder_id => "folder_id_3" }
39
+ let(:a_folder) { FactoryGirl.build :content_folder, :folder_id => "foo" }
40
+ let(:dupe_folder) { FactoryGirl.build :content_folder, :folder_id => "foo" }
20
41
 
21
42
  required_fields = [:folder_id, :label]
43
+
22
44
  required_fields.each do |f|
23
45
  it "validates #{f} is required" do
24
46
  should be_valid
@@ -27,17 +49,26 @@ describe ContentFolder do
27
49
  end
28
50
  end
29
51
 
30
- it 'cannot have empty child_folders AND document_ids' do
31
- basic_subject.should be_invalid
52
+ it 'can have empty child_folders AND document_ids' do
53
+ #puts basic_subject.inspect
54
+ basic_subject.should be_valid
32
55
  end
33
56
 
34
57
  it 'is valid when document_ids are present' do
58
+ #puts subject.inspect
35
59
  subject.should be_valid
36
60
  end
37
61
 
38
62
  it 'is valid when child_folders are present' do
63
+ #puts subject_with_folders.inspect
64
+ #puts subject_with_folders.child_folders.inspect
39
65
  subject_with_folders.should be_valid
40
66
  end
67
+
68
+ it 'is valid to have duplicate folder_ids' do
69
+ basic_subject.child_folders.push [a_folder, dupe_folder]
70
+ basic_subject.should be_valid
71
+ end
41
72
  end
42
73
 
43
74
  context 'selectors' do
@@ -49,10 +80,11 @@ describe ContentFolder do
49
80
  context 'db operations' do
50
81
  let(:subject_with_folders) { FactoryGirl.build :content_folder_with_child_folders }
51
82
 
52
- it 'saves and can be retrieved' do
53
- id = subject_with_folders.folder_id
83
+ it 'saved content folders can be retrieved' do
84
+ ContentFolder.delete_all
85
+ id = subject_with_folders.child_folders.first.folder_id
54
86
  subject_with_folders.save
55
- found = ContentFolder.find(id)
87
+ found = ContentFolder.find_folder(id)
56
88
  found.should_not be_nil
57
89
  end
58
90
  end
@@ -64,6 +96,8 @@ describe ContentFolder do
64
96
  lit_center = FactoryGirl.build :content_folder_with_document_ids, :folder_id => ContentFolder::FolderIds::LIT_CENTER
65
97
  merrill_lynch = FactoryGirl.build :content_folder_with_document_ids, :folder_id => ContentFolder::FolderIds::MERRILL_LYNCH
66
98
  plan_529 = FactoryGirl.build :content_folder_with_document_ids, :folder_id => ContentFolder::FolderIds::PLANS_529
99
+ ttpf = FactoryGirl.build :content_folder_with_document_ids, :folder_id => "ttpf"
100
+ plan_529.child_folders = [ttpf]
67
101
  other = FactoryGirl.build :content_folder_with_document_ids, :folder_id => 'abcdefg'
68
102
  root.child_folders = [lit_center, merrill_lynch, plan_529, other]
69
103
  root.save
@@ -91,5 +125,64 @@ describe ContentFolder do
91
125
  result = ContentFolder.find_folder('zyxw')
92
126
  result.should be_nil
93
127
  end
128
+
129
+ it 'should return folder by relative path' do
130
+ path = ContentFolder::FolderIds::PLANS_529 + "/ttpf"
131
+ result = ContentFolder.find_folder_by_relative_path(path)
132
+ result.should_not be_nil
133
+ end
134
+
135
+ it 'should return child folder' do
136
+ root = ContentFolder.last
137
+ result = ContentFolder.find_child_folder(root, [ContentFolder::FolderIds::PLANS_529, "ttpf"])
138
+ result.should_not be_nil
139
+ end
140
+ end
141
+
142
+
143
+ context 'content folder and asset association' do
144
+ before do
145
+ ContentFolder.delete_all
146
+ root = FactoryGirl.build :content_folder_with_document_ids
147
+ lit_center = FactoryGirl.build :content_folder, :folder_id => ContentFolder::FolderIds::LIT_CENTER
148
+ merrill_lynch = FactoryGirl.build :content_folder, :folder_id => ContentFolder::FolderIds::MERRILL_LYNCH
149
+ plan_529 = FactoryGirl.build :content_folder, :folder_id => ContentFolder::FolderIds::PLANS_529
150
+ asset_one = FactoryGirl.create :digital_asset, :digital_asset_id => "guid_1111"
151
+ asset_two = FactoryGirl.create :digital_asset, :digital_asset_id => "guid_2222"
152
+ asset_three = FactoryGirl.create :digital_asset, :digital_asset_id => "guid_3333"
153
+ lit_center.documents << [asset_one, asset_two, asset_three]
154
+ merrill_lynch.documents << [asset_two, asset_three]
155
+ plan_529.documents << [asset_three]
156
+ root.child_folders = [lit_center, merrill_lynch, plan_529]
157
+ root.save
158
+ end
159
+
160
+ it 'should return the lit center folder with document count of 3' do
161
+ result = ContentFolder.lit_center_folder
162
+ result.should_not be_nil
163
+ result.document_ids.count.should == 3
164
+ result.folder_id.should == ContentFolder::FolderIds::LIT_CENTER
165
+ end
166
+
167
+ it 'should return the merrill_lynch folder with document count of 2' do
168
+ result = ContentFolder.merrill_lynch_folder
169
+ result.should_not be_nil
170
+ result.document_ids.count.should == 2
171
+ result.folder_id.should == ContentFolder::FolderIds::MERRILL_LYNCH
172
+ end
173
+
174
+
175
+ it 'delete an asset record from database, associated with a folder' do
176
+ result = ContentFolder.plan_529_folder
177
+ #puts "==== #{result.inspect}"
178
+ #puts "Documents: #{result.documents.inspect}"
179
+ result.documents.count.should == 1
180
+ asset3 = DigitalAsset.where(digital_asset_id: "guid_3333").exists?
181
+ DigitalAsset.where(digital_asset_id: "guid_3333").delete_all
182
+ #puts "Documents: #{result.documents.inspect}"
183
+ result.documents.count.should == 0
184
+ result.folder_id.should == ContentFolder::FolderIds::PLANS_529
185
+ end
94
186
  end
187
+
95
188
  end