From 1126d9b9a9708bec5b3f4939e60768899d089e1b Mon Sep 17 00:00:00 2001 From: guange <8863824@gmail.com> Date: Mon, 23 Mar 2015 18:06:53 +0800 Subject: [PATCH 1/3] =?UTF-8?q?#2082=20IE8=E6=B5=8F=E8=A7=88=E5=99=A8--?= =?UTF-8?q?=E4=BB=BB=E6=84=8F=E6=A8=A1=E5=9D=97=E4=B8=8A=E4=BC=A0=E9=99=84?= =?UTF-8?q?=E4=BB=B6=EF=BC=9A=E4=B8=8A=E4=BC=A0=E9=99=84=E4=BB=B6=E5=90=8E?= =?UTF-8?q?=EF=BC=8C=E2=80=9C=E6=9C=AA=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E2=80=9D=E5=AD=97=E6=A0=B7=E5=B9=B6=E6=9C=AA=E9=9A=8F=E7=9D=80?= =?UTF-8?q?=E9=99=84=E4=BB=B6=E7=9A=84=E4=B8=8A=E4=BC=A0=E5=8F=98=E6=88=90?= =?UTF-8?q?=E2=80=9C=E5=B7=B2=E4=B8=8A=E4=BC=A0X=E4=B8=AA=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/javascripts/attachments.js | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/public/javascripts/attachments.js b/public/javascripts/attachments.js index 8fbaa5981..bbaf18bb4 100644 --- a/public/javascripts/attachments.js +++ b/public/javascripts/attachments.js @@ -12,6 +12,17 @@ function postUpMsg(attachmentId) }) } + +function reload(fileSpan) { + fileSpan.remove(); + $('#upload_file_count').html("未上传文件"); + $old_file = $("#_file"); + $new_file = $old_file.clone(true); + $old_file.replaceWith($new_file); + $new_file.show(); + +} + function addFile(inputEl, file, eagerUpload) { if ($('#attachments_fields').children().length < 10) { @@ -25,7 +36,17 @@ function addFile(inputEl, file, eagerUpload) { $('', { 'type': 'text', 'class': 'description', 'name': 'attachments[' + attachmentId + '][description]', 'maxlength': 254, 'placeholder': $(inputEl).data('description-placeholder') } ).toggle(!eagerUpload), $('公开:').attr({ 'class': 'ispublic-label' }) , $('', { 'type': 'checkbox', 'class': 'is_public_checkbox','value':1, 'name': 'attachments[' + attachmentId + '][is_public_checkbox]', checked:'checked' } ).toggle(!eagerUpload), - $(' ').attr({ 'href': "#", 'class': 'remove-upload', 'data-confirm' : "您确定要删除吗?" }).click(removeFile).toggle(!eagerUpload), + $(' ').attr({ 'href': "#", 'class': 'remove-upload' }).click(function(){ + if(confirm('您确定要删除吗?')){ + removeFile(); + if(!eagerUpload){ + (function(e){ + reload(e); + })(fileSpan); + } + } + + }).toggle(!eagerUpload), $('
', { 'class': 'div_attachments', 'name': 'div_'+'attachments_' + attachmentId} ) ).appendTo('#attachments_fields'); @@ -168,14 +189,15 @@ function addInputFiles(inputEl) { if (inputEl.files) { // upload files using ajax uploadAndAttachFiles(inputEl.files, inputEl); - // $(inputEl).remove(); + // $(inputEl).remove(); } else { // browser not supporting the file API, upload on form submission var attachmentId; var aFilename = inputEl.value.split(/\/|\\/); attachmentId = addFile(inputEl, { name: aFilename[ aFilename.length - 1 ] }, false); if (attachmentId) { - $(inputEl).attr({ name: 'attachments[' + attachmentId + '][file]', style: 'display:none;' }).appendTo('#attachments_' + attachmentId); + $(inputEl).attr({ name: 'attachments[' + attachmentId + '][file]'}).hide(); + $('#upload_file_count').html("已上传"+""+1+""+"个文件"); } } From 15accd7d9f019acfc25baf8387dfd4148e757f6b Mon Sep 17 00:00:00 2001 From: guange <8863824@gmail.com> Date: Tue, 10 Mar 2015 09:31:30 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E4=BC=98=E5=8C=96,=20=E5=8A=9F=E8=83=BD=E5=B7=B2=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Gemfile | 2 - app/controllers/attachments_controller.rb | 6 +- app/controllers/zipdown_controller.rb | 63 +++++++++++++++++-- app/views/settings/_general.html.erb | 1 + app/views/zipdown/assort.html.erb | 13 +++- config/locales/en.yml | 1 + config/locales/zh.yml | 1 + config/routes.rb | 1 + config/settings.yml | 5 +- ...dd_pack_attachment_max_size_to_settings.rb | 11 ++++ db/schema.rb | 2 +- 11 files changed, 95 insertions(+), 11 deletions(-) create mode 100644 db/migrate/20150309090143_add_pack_attachment_max_size_to_settings.rb diff --git a/Gemfile b/Gemfile index 29b2716a9..362be8642 100644 --- a/Gemfile +++ b/Gemfile @@ -58,8 +58,6 @@ group :test do #end end - # gem 'rspec-rails' , '2.13.1' - # gem 'guard-rspec','2.5.0' # Gems used only for assets and not required # in production environments by default. group :assets do diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb index 23b080d94..23d4c3a16 100644 --- a/app/controllers/attachments_controller.rb +++ b/app/controllers/attachments_controller.rb @@ -108,7 +108,7 @@ class AttachmentsController < ApplicationController end rescue => e - redirect_to "http://" + (Setting.host_name.to_s) +"/file_not_found.html" + redirect_to "http: //" + (Setting.host_name.to_s) +"/file_not_found.html" end #更新资源文件类型 @@ -182,6 +182,8 @@ class AttachmentsController < ApplicationController return end + + logger.debug "upload ..... " @attachment = Attachment.new(:file => request.raw_post) @attachment.author = User.current if !params[:project].nil? @@ -190,6 +192,8 @@ class AttachmentsController < ApplicationController end @attachment.filename = params[:filename].presence || Redmine::Utils.random_hex(16) saved = @attachment.save + logger.debug "upload save ..... " + logger.debug @attchement respond_to do |format| format.js diff --git a/app/controllers/zipdown_controller.rb b/app/controllers/zipdown_controller.rb index 6c5385115..75ffe75bd 100644 --- a/app/controllers/zipdown_controller.rb +++ b/app/controllers/zipdown_controller.rb @@ -7,6 +7,14 @@ class ZipdownController < ApplicationController SAVE_FOLDER = "#{Rails.root}/files" OUTPUT_FOLDER = "#{Rails.root}/tmp/archiveZip" + #统一下载功能 + def download + begin + send_file "#{OUTPUT_FOLDER}/#{params[:file]}", :filename => params[:filename], :type => detect_content_type(params[:file]) + rescue => e + render file: 'public/no_file_found.html' + end + end def assort if params[:obj_class] == "Bid" @@ -21,8 +29,14 @@ class ZipdownController < ApplicationController else logger.error "[ZipDown#assort] ===> #{params[:obj_class]} unKown !!" end - send_file zipfile, :filename => bid.name + ".zip", :type => detect_content_type(zipfile) if zipfile + if zipfile + if zipfile.length > 1 + @mut_down_files = zipfile.map{|x| File.basename(x)} + else + send_file zipfile, :filename => bid.name + ".zip", :type => detect_content_type(zipfile) + end + end #rescue Exception => e # render file: 'public/no_file_found.html' end @@ -71,7 +85,14 @@ class ZipdownController < ApplicationController bid_homework_path << zip_homework_by_user(homeattach) end end - zipping "#{Time.now.to_i}_#{bid.name}.zip", bid_homework_path, OUTPUT_FOLDER + + zips = split_pack_files(bid_homework_path, Setting.pack_attachment_max_size.to_i) + x = 0 + + zips.map { |o| + x += 1 + zipping "#{Time.now.to_i}_#{bid.name}_#{x}.zip", o, OUTPUT_FOLDER + } end def zip_homework_by_user(homeattach) @@ -93,15 +114,21 @@ class ZipdownController < ApplicationController def zipping(zip_name_refer, files_paths, output_path, is_attachment=false, not_exist_file=[]) # 输入待打包的文件列表,已经打包文件定位到ouput_path ic = Iconv.new('GBK//IGNORE', 'UTF-8//IGNORE') - input_filename = files_paths rename_zipfile = zip_name_refer ||= "#{Time.now.to_i.to_s}.zip" zipfile_name = "#{output_path}/#{rename_zipfile}" Dir.mkdir(File.dirname(zipfile_name)) unless File.exist?(File.dirname(zipfile_name)) + unless is_attachment + #都是zip合并,没必要再费力压缩了 + Zip.default_compression = Zlib::NO_COMPRESSION + else + Zip.default_compression = Zlib::DEFAULT_COMPRESSION + end + Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile| - input_filename.each do |filename| + files_paths.each do |filename| flag = true index = 1 rename_file = ic.iconv( (File.basename(filename)) ).to_s @@ -128,6 +155,34 @@ class ZipdownController < ApplicationController # logger.error "[zipdown#zipping] ===> #{e}" # @error = e end + + # 合理分配文件打包 + # 如果小于 pack_attachment_max_size, 则返回单个文件 + # 反之则切分为多个文件组返回 + def split_pack_files(files, pack_attachment_max_size) + max_size = 0 + last_files = [] + ret_files = [] + files.each do |f| + if (max_size += File.size(f)) > pack_attachment_max_size + max_size = 0 + if last_files.empty? #如果单个文件超过大小,也将此文件作为一组 + ret_files << [f] + last_files.clear + else + ret_files << last_files + last_files.clear + redo + end + else + last_files << f + end + end + + ret_files << last_files unless last_files.empty? + ret_files + end + def detect_content_type(name) content_type = Redmine::MimeType.of(name) content_type.to_s diff --git a/app/views/settings/_general.html.erb b/app/views/settings/_general.html.erb index ebb3904da..763b65515 100644 --- a/app/views/settings/_general.html.erb +++ b/app/views/settings/_general.html.erb @@ -7,6 +7,7 @@ <%= wikitoolbar_for 'settings_welcome_text' %>

<%= setting_text_field :attachment_max_size, :size => 6 %> <%= l(:"number.human.storage_units.units.kb") %>

+

<%= setting_text_field :pack_attachment_max_size, :size => 6 %> <%= l(:"number.human.storage_units.units.kb") %>

<%= setting_text_field :per_page_options, :size => 20 %> <%= l(:text_comma_separated) %>

diff --git a/app/views/zipdown/assort.html.erb b/app/views/zipdown/assort.html.erb index c9056b4fa..3cf873226 100644 --- a/app/views/zipdown/assort.html.erb +++ b/app/views/zipdown/assort.html.erb @@ -1,2 +1,11 @@ -

Download Status:

-<%= @error.class %> \ No newline at end of file +<% unless @mut_down_files %> +

Download Status:

+ <%= @error.class %> +<% else %> +

下载文件包太大,分成<%= @mut_down_files.count %>个下载包

+ +<% end %> \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index 910eb0f98..1430e5df1 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -177,6 +177,7 @@ en: setting_login_required: Authentication required setting_self_registration: Self-registration setting_attachment_max_size: Maximum attachment size + setting_pack_attachment_max_size: Maximum pack attachment size setting_issues_export_limit: Issues export limit setting_mail_from: Emission email address setting_bcc_recipients: Blind carbon copy recipients (bcc) diff --git a/config/locales/zh.yml b/config/locales/zh.yml index f3879421a..282218905 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -196,6 +196,7 @@ zh: setting_login_required: 要求认证 setting_self_registration: 允许自注册 setting_attachment_max_size: 附件大小限制 + setting_pack_attachment_max_size: 附件打包最大限制 setting_issues_export_limit: 问题导出条目的限制 setting_mail_from: 邮件发件人地址 setting_bcc_recipients: 使用密件抄送 (bcc) diff --git a/config/routes.rb b/config/routes.rb index 3ec814839..1417231b2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -105,6 +105,7 @@ RedmineApp::Application.routes.draw do namespace :zipdown do match 'assort' match 'download_user_homework', :as => :download_user_homework + match 'download' end namespace :test do match 'courselist' diff --git a/config/settings.yml b/config/settings.yml index 381e8a302..56cb8ac6c 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -46,7 +46,10 @@ session_timeout: default: 2880 attachment_max_size: format: int - default: 5120 + default: 51200 +pack_attachment_max_size: + format: int + default: 51200 issues_export_limit: format: int default: 500 diff --git a/db/migrate/20150309090143_add_pack_attachment_max_size_to_settings.rb b/db/migrate/20150309090143_add_pack_attachment_max_size_to_settings.rb new file mode 100644 index 000000000..95887a3e2 --- /dev/null +++ b/db/migrate/20150309090143_add_pack_attachment_max_size_to_settings.rb @@ -0,0 +1,11 @@ +class AddPackAttachmentMaxSizeToSettings < ActiveRecord::Migration + def up + Setting.where(name: 'attachment_max_size').update_all(value: 51200) + Setting.create(name: 'pack_attachment_max_size', value: 51200 ) + end + + def down + Setting.delete(name: 'pack_attachment_max_size') + Setting.where(name: 'attachment_max_size').update_all(value: 204800) + end +end diff --git a/db/schema.rb b/db/schema.rb index bad1cf2ae..71d91560e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20150305081132) do +ActiveRecord::Schema.define(:version => 20150309090143) do create_table "activities", :force => true do |t| t.integer "act_id", :null => false From 4b636d8be6a0287d8ad0650b93f067f0ac87aef6 Mon Sep 17 00:00:00 2001 From: guange <8863824@gmail.com> Date: Wed, 25 Mar 2015 13:13:09 +0800 Subject: [PATCH 3/3] =?UTF-8?q?#1801=20=E6=89=93=E5=8C=85=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E5=88=86=E4=B8=AA=E6=95=B0=E4=B8=8B=E8=BD=BD=E5=AE=8C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/attachments_controller.rb | 4 --- app/controllers/zipdown_controller.rb | 39 ++++++++++++++------- app/views/bids/_homework_list.html.erb | 15 +++++++- public/javascripts/application.js | 28 +++++++++++++++ public/stylesheets/css.css | 14 ++++++-- public/stylesheets/images/img_floatbox.png | Bin 0 -> 1012 bytes 6 files changed, 80 insertions(+), 20 deletions(-) create mode 100644 public/stylesheets/images/img_floatbox.png diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb index 23d4c3a16..d458b73e4 100644 --- a/app/controllers/attachments_controller.rb +++ b/app/controllers/attachments_controller.rb @@ -182,8 +182,6 @@ class AttachmentsController < ApplicationController return end - - logger.debug "upload ..... " @attachment = Attachment.new(:file => request.raw_post) @attachment.author = User.current if !params[:project].nil? @@ -192,8 +190,6 @@ class AttachmentsController < ApplicationController end @attachment.filename = params[:filename].presence || Redmine::Utils.random_hex(16) saved = @attachment.save - logger.debug "upload save ..... " - logger.debug @attchement respond_to do |format| format.js diff --git a/app/controllers/zipdown_controller.rb b/app/controllers/zipdown_controller.rb index 75ffe75bd..9880a6382 100644 --- a/app/controllers/zipdown_controller.rb +++ b/app/controllers/zipdown_controller.rb @@ -25,17 +25,25 @@ class ZipdownController < ApplicationController zipfile = zip_bid bid else render file: 'public/no_file_found.html' + return end else logger.error "[ZipDown#assort] ===> #{params[:obj_class]} unKown !!" end - if zipfile - if zipfile.length > 1 - @mut_down_files = zipfile.map{|x| File.basename(x)} - else - send_file zipfile, :filename => bid.name + ".zip", :type => detect_content_type(zipfile) - end + # if zipfile + # if zipfile.length > 1 + # @mut_down_files = zipfile #zipfile.each{|x| File.basename(x)} + # else + # send_file zipfile.first[:real_file], :filename => bid.name + ".zip", :type => detect_content_type(zipfile.first[:real_file]) + # return + # end + # end + + respond_to do |format| + format.json { + render json: zipfile.to_json + } end #rescue Exception => e # render file: 'public/no_file_found.html' @@ -86,13 +94,18 @@ class ZipdownController < ApplicationController end end - zips = split_pack_files(bid_homework_path, Setting.pack_attachment_max_size.to_i) + zips = split_pack_files(bid_homework_path, Setting.pack_attachment_max_size.to_i*1024) x = 0 - zips.map { |o| + + zips.each { |o| x += 1 - zipping "#{Time.now.to_i}_#{bid.name}_#{x}.zip", o, OUTPUT_FOLDER + file = zipping "#{Time.now.to_i}_#{bid.name}_#{x}.zip", o[:files], OUTPUT_FOLDER + o[:real_file] = file + o[:file] = File.basename(file) + o[:size] = (File.size(file) / 1024.0 / 1024.0).round(2) } + end def zip_homework_by_user(homeattach) @@ -163,14 +176,14 @@ class ZipdownController < ApplicationController max_size = 0 last_files = [] ret_files = [] - files.each do |f| + files.each_with_index do |f,i| if (max_size += File.size(f)) > pack_attachment_max_size max_size = 0 if last_files.empty? #如果单个文件超过大小,也将此文件作为一组 - ret_files << [f] + ret_files << {files: [f], count: 1, index: ret_files.count+1} last_files.clear else - ret_files << last_files + ret_files << {files:last_files, count: last_files.count, index: ret_files.count+1} last_files.clear redo end @@ -179,7 +192,7 @@ class ZipdownController < ApplicationController end end - ret_files << last_files unless last_files.empty? + ret_files << {files:last_files, count: last_files.count, index: ret_files.count+1} unless last_files.empty? ret_files end diff --git a/app/views/bids/_homework_list.html.erb b/app/views/bids/_homework_list.html.erb index 6572ee2c9..7ac686e09 100644 --- a/app/views/bids/_homework_list.html.erb +++ b/app/views/bids/_homework_list.html.erb @@ -23,7 +23,7 @@ (<%= @jours_count %>)
  • - <%= link_to "作品打包下载", zipdown_assort_path(obj_class: @bid.class, obj_id: @bid), class: "tb_all" unless @bid.homeworks.empty? %> + <%= link_to "作品打包下载", zipdown_assort_path(obj_class: @bid.class, obj_id: @bid, format: :json), remote: true, class: "tb_all" unless @bid.homeworks.empty? %>
  • <% else %> @@ -63,6 +63,19 @@
    + +
    + + +
    +

    下载文件包太大,分成多个下载包

    + +
    +
    +
    +
    diff --git a/public/javascripts/application.js b/public/javascripts/application.js index 5d2423238..a18a282e4 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -864,4 +864,32 @@ $(function(){ $(this).parent('p').remove(); console.log("delete complete."); }); + + $('a.tb_all').bind('ajax:complete', function (event, data, status, xhr) { + if(status == 'success'){ + var res = JSON.parse(data.responseText); + if(res.length<1){ + return; + } + + if(res.length==1){ + location.href = '/zipdown/download?file='+res[0].file;return; + } + + document.getElementById('light').style.display='block'; + $container = $('#light .upload_box_ul'); + $container.empty(); + for(var i = 0; i 1){ + des = '第'+res[i].index+'-'+(res[i].count+res[i].index-1)+'个学生的作品下载'; + } else { + des = '第'+res[i].index+'个学生的作品下载'; + } + $('
  • '+(i+1)+'. '+des+'  (共'+res[i].size+'M)
  • ').appendTo($container); + + } + } + + }) }); diff --git a/public/stylesheets/css.css b/public/stylesheets/css.css index 2319d1f59..0f51322df 100644 --- a/public/stylesheets/css.css +++ b/public/stylesheets/css.css @@ -149,8 +149,18 @@ a:hover.tijiao{ background:#0f99a9 !important;} .ni_con p{ color:#808181;} .ni_con a:hover{ text-decoration:none;} - - +/*弹框*/ +.black_overlay{display:none;position:absolute;top:0%;left:0%;width:100%;height:100%;background-color:black;z-index:1001;-moz-opacity:0.3;opacity:.30;filter:alpha(opacity=30);} +.upload_box{display:none;position:absolute;top:25%;left:35%;width:30%;height: auto;padding:5px;border:3px solid #15bccf; background:#fff;z-index:1002;overflow:auto;} +.close{background:url(images/img_floatbox.png) 0 0 no-repeat; width:16px; height:16px; display:block; float:right;} +.close:hover{background:url(images/img_floatbox.png) -22px 0 no-repeat; width:16px; height:16px; display:block; float:right;} +.upload_box_tit{ font-size:16px; color:#15bccf; text-align:center; } +.upload_box_{ margin-left:10%; margin-bottom:5px; margin-right:10%;} +.upload_box_ul{ margin-bottom:10px;} +.upload_box_ul a{ color:#09658c;} +.upload_box_ul a:hover{ color:#15bccf;} +.upload_box_span{ color: #333; font-weight: bold;} +.c_grey{ color:#A7A7A7;} diff --git a/public/stylesheets/images/img_floatbox.png b/public/stylesheets/images/img_floatbox.png new file mode 100644 index 0000000000000000000000000000000000000000..b2167f5ffffb44e15fa2aa86f6e816dadab940f7 GIT binary patch literal 1012 zcmV(_`g8%^e{{R4h=>PzAFaQARU;qF*m;eA5Z<1fd zMgRZfy+RDBcRZ>YIIFMFfw3b-O#rB zqfK+bbKooRO98b6JOFxuzGnRp+E$Hj8p`y8SU0q-K2jIY0?!msOTeUzOz(M38roKk zZUiM^CS_z|-E<@>zzcc!C-6odx&)M3t(?%dYIIFMh;>8Ts?k;DbryIE90ODGv%YrA zSw^ZxH%e0@Ab=|}Z6^}O_)Bf3MptEY)kQCXhq48{0)Au|{anlR1Ep>ns;GdOk_L`) zdjdR?P(8qDi!f8tz$N)vtZVu~PiR}G=?E<L)Ds8gnaG>`_;KpIE`X`pTaavW#N zahxFcCunuPyL}N6Dt1a(Mz=^*w0>?rKtJ5AT@#i_@ro31MvnltK@-X!T zum_B$p%O5oa?ibnfASs2sR9Tg3T>oqP!6Hd#p6IV1yfF@v{0#3wpuXoR+RG=pvZ!0 zCuL1XO$c!)BNL@B69%9tgc$2o$`Y&E;C+6bT4CTl;0Cavsy-uUm~o(-fI8C>j2vOg zLWo1@n{rl5=wyV}vka_&T5ksEgM78Rz60A?)s%qRmV5Qn4-KS&G>`_;KpN=304nb9 z?<>FXJZ}rAx~{97E{2DP^=#kPnwgo2XM5Lmk210l&-U~4^ZCv8@?sUt#m)9fs07TJ z*}h{yuIr{J)=kgz1{E;nWJ(Lu)6*@@_EFBWR#d&7=hdCTxG87 zj%8FpRSN!Fv%SJI@ocZEJ|kzCGqZgf%E%F>?7Hru^i4UdCFC~SCk?EC%6GO`RZ{{= i&-NNf1O4AXzXt%Mbf5S7A4@j?0000