[
  {
    "path": ".gitignore",
    "content": ".build*\n.DS_store\n.aws_keys.txt\n"
  },
  {
    "path": ".npm/package/.gitignore",
    "content": "node_modules\n"
  },
  {
    "path": ".npm/package/README",
    "content": "This directory and the files immediately inside it are automatically generated\nwhen you change this package's NPM dependencies. Commit the files in this\ndirectory (npm-shrinkwrap.json, .gitignore, and this README) to source control\nso that others run the same versions of sub-dependencies.\n\nYou should NOT check in the node_modules directory that Meteor automatically\ncreates; if you are using git, the .gitignore file tells git to ignore it.\n"
  },
  {
    "path": ".npm/package/npm-shrinkwrap.json",
    "content": "{\n  \"lockfileVersion\": 1,\n  \"dependencies\": {\n    \"aws-sdk\": {\n      \"version\": \"2.1.14\",\n      \"resolved\": \"https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1.14.tgz\",\n      \"integrity\": \"sha1-cPct9Y1GaiItTDK/IbYarX5QRpg=\",\n      \"dependencies\": {\n        \"xml2js\": {\n          \"version\": \"0.2.6\",\n          \"resolved\": \"https://registry.npmjs.org/xml2js/-/xml2js-0.2.6.tgz\",\n          \"integrity\": \"sha1-0gnE5N2h/JxFIUHvQcB39a399sQ=\",\n          \"dependencies\": {\n            \"sax\": {\n              \"version\": \"0.4.2\",\n              \"resolved\": \"https://registry.npmjs.org/sax/-/sax-0.4.2.tgz\",\n              \"integrity\": \"sha1-OfO2AXM9a+yXEFskKipA/Wl4rDw=\"\n            }\n          }\n        },\n        \"xmlbuilder\": {\n          \"version\": \"0.4.2\",\n          \"resolved\": \"https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-0.4.2.tgz\",\n          \"integrity\": \"sha1-F3bWXz/brUcKCNhgTN6xxOVA/4M=\"\n        }\n      }\n    },\n    \"crypto-js\": {\n      \"version\": \"3.1.6\",\n      \"resolved\": \"https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.6.tgz\",\n      \"integrity\": \"sha1-YUJlGyMtu469+pcWpwooiDWdpsk=\"\n    },\n    \"knox\": {\n      \"version\": \"0.9.2\",\n      \"resolved\": \"https://registry.npmjs.org/knox/-/knox-0.9.2.tgz\",\n      \"integrity\": \"sha1-NzZZNmniTwJP2vcjtqHcSv2DmnE=\",\n      \"dependencies\": {\n        \"debug\": {\n          \"version\": \"1.0.4\",\n          \"resolved\": \"https://registry.npmjs.org/debug/-/debug-1.0.4.tgz\",\n          \"integrity\": \"sha1-W5wla9VLbsAigxdvqKDt5tFUy/g=\",\n          \"dependencies\": {\n            \"ms\": {\n              \"version\": \"0.6.2\",\n              \"resolved\": \"https://registry.npmjs.org/ms/-/ms-0.6.2.tgz\",\n              \"integrity\": \"sha1-2JwhJMb9wTU9Zai3e/GqxLGTcIw=\"\n            }\n          }\n        },\n        \"mime\": {\n          \"version\": \"1.3.4\",\n          \"resolved\": \"https://registry.npmjs.org/mime/-/mime-1.3.4.tgz\",\n          \"integrity\": \"sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=\"\n        },\n        \"once\": {\n          \"version\": \"1.3.1\",\n          \"resolved\": \"https://registry.npmjs.org/once/-/once-1.3.1.tgz\",\n          \"integrity\": \"sha1-8/Pk2lt9J7XHMpae4+Z+cpRXsx8=\",\n          \"dependencies\": {\n            \"wrappy\": {\n              \"version\": \"1.0.1\",\n              \"resolved\": \"https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz\",\n              \"integrity\": \"sha1-HmWWmWXMvC20VIxrhKbyxa7dRzk=\"\n            }\n          }\n        },\n        \"stream-counter\": {\n          \"version\": \"1.0.0\",\n          \"resolved\": \"https://registry.npmjs.org/stream-counter/-/stream-counter-1.0.0.tgz\",\n          \"integrity\": \"sha1-kc8lac5NxQYf6816yyY5SloRR1E=\"\n        },\n        \"xml2js\": {\n          \"version\": \"0.4.5\",\n          \"resolved\": \"https://registry.npmjs.org/xml2js/-/xml2js-0.4.5.tgz\",\n          \"integrity\": \"sha1-/EJnUbfPiQqqkJp1bu3jHH84qPw=\",\n          \"dependencies\": {\n            \"sax\": {\n              \"version\": \"0.6.1\",\n              \"resolved\": \"https://registry.npmjs.org/sax/-/sax-0.6.1.tgz\",\n              \"integrity\": \"sha1-VjsZx8HeiS4Jv8Ty/DDjwn8JUrk=\"\n            },\n            \"xmlbuilder\": {\n              \"version\": \"2.6.1\",\n              \"resolved\": \"https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-2.6.1.tgz\",\n              \"integrity\": \"sha1-umkhZQEz5YCCiPNdyrDbaWqbqaA=\",\n              \"dependencies\": {\n                \"lodash\": {\n                  \"version\": \"3.3.1\",\n                  \"resolved\": \"https://registry.npmjs.org/lodash/-/lodash-3.3.1.tgz\",\n                  \"integrity\": \"sha1-O5FNShuyfvzuB24N+lgVIBjiBC4=\"\n                }\n              }\n            }\n          }\n        }\n      }\n    },\n    \"moment\": {\n      \"version\": \"2.13.0\",\n      \"resolved\": \"https://registry.npmjs.org/moment/-/moment-2.13.0.tgz\",\n      \"integrity\": \"sha1-JBYtmVIebUD5muaTnoBtITnqrFI=\"\n    },\n    \"stream-buffers\": {\n      \"version\": \"2.1.0\",\n      \"resolved\": \"https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.1.0.tgz\",\n      \"integrity\": \"sha1-gsG8imgVvwAQje2I6lU/D4vLOzo=\"\n    }\n  }\n}\n"
  },
  {
    "path": ".versions",
    "content": "accounts-base@1.4.2\nallow-deny@1.1.0\nautoupdate@1.4.0\nbabel-compiler@7.0.4\nbabel-runtime@1.2.0\nbase64@1.0.10\nbinary-heap@1.0.10\nboilerplate-generator@1.4.0\ncaching-compiler@1.1.9\ncallback-hook@1.1.0\ncheck@1.3.0\ncoffeescript@1.0.17\nddp@1.4.0\nddp-client@2.3.1\nddp-common@1.4.0\nddp-rate-limiter@1.0.7\nddp-server@2.1.2\ndiff-sequence@1.1.0\ndynamic-import@0.3.0\necmascript@0.10.0\necmascript-runtime@0.5.0\necmascript-runtime-client@0.6.0\necmascript-runtime-server@0.5.0\nejson@1.1.0\nes5-shim@4.7.3\ngeojson-utils@1.0.10\nhot-code-push@1.0.4\nhttp@1.4.0\nid-map@1.1.0\nlepozepo:s3@5.2.8\nlivedata@1.0.18\nlocalstorage@1.2.0\nlogging@1.1.19\nmeteor@1.8.2\nmeteor-base@1.3.0\nminimongo@1.4.3\nmodules@0.11.3\nmodules-runtime@0.9.1\nmongo@1.4.2\nmongo-dev-server@1.1.0\nmongo-id@1.0.6\nnpm-mongo@2.2.33\nordered-dict@1.1.0\npromise@0.10.1\nrandom@1.1.0\nrate-limit@1.0.8\nreactive-var@1.0.11\nreload@1.2.0\nretry@1.1.0\nroutepolicy@1.0.12\nserver-render@0.3.0\nservice-configuration@1.0.11\nshim-common@0.1.0\nsocket-stream-client@0.1.0\ntracker@1.1.3\nunderscore@1.0.10\nurl@1.2.0\nwebapp@1.5.0\nwebapp-hashing@1.0.9\n"
  },
  {
    "path": "LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Marcelo Reyna\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Amazon S3 Uploader\nS3 provides a simple way for uploading files to the Amazon S3 service with a progress bar. This is useful for uploading images and files that you want accesible to the public. S3 is built on [Knox](https://github.com/LearnBoost/knox) and [AWS-SDK](https://github.com/aws/aws-sdk-js). Both modules are made available on the server after installing this package.\n\nIf you want to keep using the older version of this package (pre 0.9.0) check it out using `meteor add lepozepo:s3@=3.0.1`\n\nIf you want to keep using the version of this package that uses server resources to upload files check it out using `meteor add lepozepo:s3@=4.1.3`\n\n**S3 now uploads directly from the client to Amazon. Client files will not touch your server.**\n\n# Show your support!\nStar my code in github or atmosphere if you like my code or shoot me a dollar or two!\n\n[DONATE HERE](https://cash.me/$lepozepo)\n\n## Moving Forward\nIn line with Meteor's move towards NPM, I'm moving this package to NPM. Along with this move, I'll resolve issues with importing the uploader and making it easy to use in React and React Native. I've already started migrating but I'm only half way there, have a look at the repo [here](https://github.com/Lepozepo/S3-uploader)\n\n## NEW IN 5.2.1\n* AWS Signature V4!! This means more regions can use this package\n\n## Installation\n\n``` sh\n$ meteor add lepozepo:s3\n```\n\n## How to use\n\n### Step 1\nDefine your Amazon S3 credentials. SERVER SIDE.\n\n``` javascript\nS3.config = {\n\tkey: 'amazonKey',\n\tsecret: 'amazonSecret',\n\tbucket: 'bucketName',\n\tregion: 'eu-west-1' // Only needed if not \"us-east-1\" or \"us-standard\"\n};\n```\n\n### Step 2\nCreate a file input and progress indicator. CLIENT SIDE.\n\n``` handlebars\n<template name=\"s3_tester\">\n\t<input type=\"file\" class=\"file_bag\">\n\t<button class=\"upload\">Upload</button>\n\n\t{{#each files}}\n\t\t<p>{{percent_uploaded}}</p>\n\t{{/each}}\n</template>\n```\n\n### Step 3\nCreate a function to upload the files and a helper to see the uploads progress. CLIENT SIDE.\n\n``` javascript\nTemplate.s3_tester.events({\n\t\"click button.upload\": function(){\n\t\tvar files = $(\"input.file_bag\")[0].files\n\n\t\tS3.upload({\n\t\t\t\tfiles:files,\n\t\t\t\tpath:\"subfolder\"\n\t\t\t},function(e,r){\n\t\t\t\tconsole.log(r);\n\t\t});\n\t}\n})\n\nTemplate.s3_tester.helpers({\n\t\"files\": function(){\n\t\treturn S3.collection.find();\n\t}\n})\n```\n\n## Create your Amazon S3\n\nFor all of this to work you need to create an aws account.\n\n### 1. Create an S3 bucket in your preferred region.\n\n### 2. Access Key Id and Secret Key\n\n1. Navigate to your bucket\n2. On the top right side you'll see your account name. Click it and go to Security Credentials.\n3. Create a new access key under the Access Keys (Access Key ID and Secret Access Key) tab.\n4. Enter this information into your app as defined in \"How to Use\" \"Step 1\".\n5. Your region can be found under \"Properties\" button and \"Static Website Hosting\" tab.\n\t* bucketName.s3-website-**eu-west-1**.amazonaws.com.\n\t* If your region is \"us-east-1\" or \"us-standard\" then you don't need to specify this in the config.\n\n### 3. Hosting\n\n1. Upload a blank `index.html` file (anywhere is ok, I put it in root).\n2. Select the bucket's properties by clicking on the bucket (from All Buckets) then the \"Properties\" button at the top right.\n3. Click **\"Static Website Hosting\"** tab.\n4. Click **Enable Website Hosting**.\n5. Fill the `Index Document` input with the path to your `index.html` without a trailing slash. E.g. `afolder/index.html`, `index.html`\n6. **Click \"Save\"**\n\n### 4. CORS\n\nYou need to set permissions so that everyone can see what's in there.\n\n1. Select the bucket's properties and go to the \"Permissions\" tab.\n2. Click \"Edit CORS Configuration\" and paste this:\n\n\t``` xml\n\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t<CORSConfiguration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">\n\t\t<CORSRule>\n\t\t\t<AllowedOrigin>*</AllowedOrigin>\n\t\t\t<AllowedMethod>PUT</AllowedMethod>\n\t\t\t<AllowedMethod>POST</AllowedMethod>\n\t\t\t<AllowedMethod>GET</AllowedMethod>\n\t\t\t<AllowedMethod>HEAD</AllowedMethod>\n\t\t\t<MaxAgeSeconds>3000</MaxAgeSeconds>\n\t\t\t<AllowedHeader>*</AllowedHeader>\n\t\t</CORSRule>\n\t</CORSConfiguration>\n\t```\n\n5. Click \"Edit bucket policy\" and paste this (**Replace the bucket name with your own**):\n\n\t``` javascript\n\t{\n\t\t\"Version\": \"2008-10-17\",\n\t\t\"Statement\": [\n\t\t\t{\n\t\t\t\t\"Sid\": \"AllowPublicRead\",\n\t\t\t\t\"Effect\": \"Allow\",\n\t\t\t\t\"Principal\": {\n\t\t\t\t\t\"AWS\": \"*\"\n\t\t\t\t},\n\t\t\t\t\"Action\": \"s3:GetObject\",\n\t\t\t\t\"Resource\": \"arn:aws:s3:::YOURBUCKETNAMEHERE/*\"\n\t\t\t}\n\t\t]\n\t}\n\t```\n\n7. **Click Save**\n\n### Note\n\nIt might take a couple of hours before you can actually start uploading to S3. Amazon takes some time to make things work.\n\nEnjoy, this took me a long time to figure out and I'm sharing it so that nobody has to go through all that.\n\n## API\n\n### S3 (CLIENT SIDE)\n\n#### S3.collection\nThis is a null Meteor.Collection that exists only on the users client. After the user leaves the page or refreshes, the collection disappears forever.\n\n#### S3.upload(ops,callback)\nThis is the upload function that manages all the dramatic things you need to do for something so essentially simple.\n\n__Parameters:__\n*\t__ops.file [OPTIONAL]:__ Must be a File object. You can create this via ```new File()```.  Either this otpion or 'files' just be provided.\n*\t__ops.files [OPTIONAL]:__ Must be a FileList object. You can get this via jQuery via $(\"input[type='file']\")[0].files.\n*\t__ops.path [DEFAULT: \"\"]:__ Must be in this format (\"folder/other_folder\"). So basically never start with \"/\" and never end with \"/\". Defaults to ROOT folder.\n*\t__ops.unique_name [DEFAULT: true]:__ If set to true, the uploaded file name will be set to a uuid without changing the files' extension. If set to false, the uploaded file name will be set to the original name of the file.\n*\t__ops.encoding [OPTIONAL: \"base64\"]:__ If set to \"base64\", the uploaded file will be uploaded as a base64 string. The uploader will enforce a unique_name if this option is set.\n*\t__ops.expiration [DEFAULT: 1800000 (30 mins)]:__ Defines how much time the file has before Amazon denies the upload. Must be in milliseconds. Defaults to 1800000 (30 minutes).\n*\t__ops.uploader [DEFAULT: \"default\"]:__ Defines the name of the uploader. Useful for forms that use multiple uploaders.\n*\t__ops.acl [DEFAULT: \"public-read\"]:__ Access Control List. Describes who has access to the file. Can only be one of the following options:\n\t* \"private\"\n\t* \"public-read\"\n\t* \"public-read-write\"\n\t* \"authenticated-read\"\n\t* \"bucket-owner-read\"\n\t* \"bucket-owner-full-control\"\n\t* \"log-delivery-write\"\n\t* __Support for signed GET is still pending so uploads that require authentication won't be easily reachable__\n*\t__ops.bucket [DEFAULT: SERVER SETTINGS]:__ Overrides the bucket that will be used for the upload.\n*\t__ops.region [DEFAULT: SERVER SETTINGS]:__ Overrides the region that will be used for the upload. Only accepts the following regions:\n\t* \"us-west-2\"\n\t* \"us-west-1\"\n\t* \"eu-west-1\"\n\t* \"eu-central-1\"\n\t* \"ap-southeast-1\"\n\t* \"ap-southeast-2\"\n\t* \"ap-northeast-1\"\n\t* \"sa-east-1\"\n\t* __file.upload_name [OPTIONAL]:__ A function that returns the name with which you want to upload the file. It takes the file object as the only parameter. eg.\n\t\t``` javascript\n\t\t// The following function simply replicates the default behavior.\n\t\tfunction(f) {\n\t\t\tvar extension = f.type.split(\"/\")[1];\n\t\t\treturn Meteor.uuid() + \".\" + extension;\n\t\t}\n\t\t```\n*\t__callback:__ A function that is run after the upload is complete returning an Error as the first parameter (if there is one), and a Result as the second.\n*\t__Result:__ The returned value of the callback function if there is no error. It returns an object with these keys:\n\t*\t__loaded:__ Integer (bytes)\n\t*\t__total:__ Integer (bytes)\n\t*\t__percent_uploaded:__ Integer (out of 100)\n\t*\t__uploader:__ String (describes which uploader was used to upload the file)\n\t*\t__url:__ String (S3 hosted URL)\n\t*\t__secure_url:__ String (S3 hosted URL for https)\n\t*\t__relative_url:__ String (S3 URL for delete operations, this is what you should save in your DB to control delete)\n\n#### S3.delete(path,callback)\nThis function permanently destroys a file located in your S3 bucket.\n\n__Parameters:__\n*\t__path:__ Must be in this format (\"/folder/other_folder/file.extension\"). So basically always start with \"/\" and never end with \"/\". This is required.\n*\t__callback:__ A function that is run after the delete operation is complete returning an Error as the first parameter (if there is one), and a Result as the second.\n\n### S3 (SERVER SIDE)\n\n#### S3.config(ops)\nThis is where you define your key, secret, bucket, and other account wide settings.\n\n__Parameters:__\n*\t__ops.key [REQUIRED]:__ Your Amazon AWS Key.\n*\t__ops.secret [REQUIRED]:__ Your Amazon AWS Secret.\n*\t__ops.bucket [REQUIRED]:__ Your Amazon AWS S3 bucket.\n*\t__ops.denyDelete [DEFAULT: undefined]:__ If set to true, will block delete calls. This is to enable secure deployment of this package before a more granular permissions system is developed.\n*\t__ops.region [DEFAULT: \"us-east-1\"]:__ Your Amazon AWS S3 Region. Defaults to US Standard. Can be any of the following:\n\t* \"us-west-2\"\n\t* \"us-west-1\"\n\t* \"eu-west-1\"\n\t* \"eu-central-1\"\n\t* \"ap-southeast-1\"\n\t* \"ap-southeast-2\"\n\t* \"ap-northeast-1\"\n\t* \"sa-east-1\"\n\n``` javascript\nS3.config = {\n\tkey: 'amazonKey',\n\tsecret: 'amazonSecret',\n\tbucket: 'bucketName'\n};\n```\n\n#### S3.rules\n##### S3.rules.delete\nThis is a function that runs every time someone uses the delete function on the client side. The context of `this` for the function has access to the `path` and `this` from a Meteor.method.\n\n#### S3.knox\nThe current knox client.\n\n#### S3.aws\nThe current aws-sdk client.\n\n#### Developer Notes\nhttp://docs.aws.amazon.com/AWSJavaScriptSDK/latest/frames.html\nhttps://github.com/Differential/meteor-uploader/blob/master/lib/UploaderFile.coffee#L169-L178\n\nhttp://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-auth-using-authorization-header.html\nhttp://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html\nhttps://github.com/CulturalMe/meteor-slingshot/blob/master/services/aws-s3.js\n"
  },
  {
    "path": "client/functions.coffee",
    "content": "@S3 =\n\tcollection: new Meteor.Collection(null)\n\t\t# file.name\n\t\t# file.type\n\t\t# file.size\n\t\t# loaded\n\t\t# total\n\t\t# percent_uploaded\n\t\t# uploader\n\t\t# status: [\"signing\",\"uploading\",\"complete\"]\n\t\t# url\n\t\t# secure_url\n\t\t# relative_url\n\n\tupload: (ops = {},callback) ->\n\t\t# ops.files [OPTIONAL]\n\t\t\t# each needs to run file.type, store in a variable, then send. Either files or ops.file must be provided.\n\t\t# ops.file [OPTIONAL]\n\t\t\t# single file upload of javascript type File\n\t\t# ops.path [DEFAULT: \"\"]\n\t\t\t# the folder to upload to: blank string for root folder \"\"\n\t\t# ops.unique_name [DEFAULT: true]\n\t\t\t# modifies the file name to a unique string, if false takes the name of the file. Uploads will overwrite existing files instead.\n\t\t# ops.encoding [OPTIONAL: only supports \"base64\"]\n\t\t\t# overrides file encoding, only supports base64 right now\n\t\t# ops.content_disposition [DEFAULT: \"inline\"]\n\t\t\t# overrides file disposition (inline or attachment)\n\t\t# ops.server_side_encryption\n\t\t\t# if true, use server side encryption\n\t\t# ops.expiration [DEFAULT: 1800000 (30 mins)]\n\t\t\t# How long before uploads to the file are disabled in ms\n\t\t# ops.acl [DEFAULT: \"public-read\"]\n\t\t\t# Access Control List. Describes who has access to the file. Any of these options:\n\t\t\t\t# \"private\",\n\t\t\t\t# \"public-read\",\n\t\t\t\t# \"public-read-write\",\n\t\t\t\t# \"authenticated-read\",\n\t\t\t\t# \"bucket-owner-read\",\n\t\t\t\t# \"bucket-owner-full-control\",\n\t\t\t\t# \"log-delivery-write\"\n\t\t# ops.bucket [OVERRIDE REQUIRED SERVER-SIDE]\n\t\t# ops.region [OVERRIDE DEFAULT: \"us-east-1\"]\n\t\t\t# Accepts the following regions:\n\t\t\t\t# \"us-west-2\"\n\t\t\t\t# \"us-west-1\"\n\t\t\t\t# \"eu-west-1\"\n\t\t\t\t# \"eu-central-1\"\n\t\t\t\t# \"ap-southeast-1\"\n\t\t\t\t# \"ap-southeast-2\"\n\t\t\t\t# \"ap-northeast-1\"\n\t\t\t\t# \"sa-east-1\"\n\t\t# ops.uploader [DEFAULT: \"default\"]\n\t\t\t# key to differentiate multiple uploaders on the same form\n\n\t\t_.defaults ops,\n\t\t\texpiration:1800000\n\t\t\tpath:\"\"\n\t\t\tacl:\"public-read\"\n\t\t\tuploader:\"default\"\n\t\t\tunique_name:true\n\t\t\tconnection:Meteor\n\t\t\tserver_side_encryption:false\n\t\t\tcontent_disposition:\"inline\"\n\n\t\tif ops.file\n\t\t\tuploadFile(ops.file, ops, callback)\n\t\telse\n\t\t\t_.each ops.files, (file) ->\n\t\t\t\tuploadFile(file, ops, callback)\n\n\tdelete: (path, callback, connection) ->\n\t\tconn = if connection then connection else Meteor\n\t\tconn.call \"_s3_delete\", path, callback\n\n\tb64toBlob: (b64Data, contentType, sliceSize) ->\n\t\tdata = b64Data.split(\"base64,\")\n\t\tif not contentType\n\t\t\tcontentType = data[0].replace(\"data:\",\"\").replace(\";\",\"\")\n\n\t\tcontentType = contentType\n\t\tsliceSize = sliceSize or 512\n\n\t\tbyteCharacters = atob data[1]\n\t\tbyteArrays = []\n\n\t\tfor offset in [0...byteCharacters.length] by sliceSize\n\t\t\tslice = byteCharacters.slice offset, offset + sliceSize\n\t\t\tbyteNumbers = new Array slice.length\n\n\t\t\tfor i in [0...slice.length]\n\t\t\t\tbyteNumbers[i] = slice.charCodeAt(i)\n\n\t\t\tbyteArray = new Uint8Array byteNumbers\n\n\t\t\tbyteArrays.push byteArray\n\n\t\tblob = new Blob(byteArrays, {type: contentType})\n\t\treturn blob\n\nuploadFile = (file, ops, callback) ->\n\tif ops.encoding is \"base64\"\n\t\tif _.isString file\n\t\t\tfile = S3.b64toBlob file\n\n\tif ops.unique_name or ops.encoding is \"base64\"\n\t\textension = _.last file.name?.split(\".\")\n\t\tif not extension\n\t\t\textension = file.type.split(\"/\")[1] # a library of extensions based on MIME types would be better\n\n\t\tfile_name = \"#{Random.id()}.#{extension}\"\n\telse\n\t\tif _.isFunction(file.upload_name)\n\t\t\tfile_name = file.upload_name(file)\n\t\telse if !_.isEmpty(file.upload_name)\n\t\t\tfile_name = file.upload_name\n\t\telse\n\t\t\tfile_name = file.name\n\n\tinitial_file_data =\n\t\tfile:\n\t\t\tname:file_name\n\t\t\ttype:file.type\n\t\t\tsize:file.size\n\t\t\toriginal_name:file.name\n\t\tloaded:0\n\t\ttotal:file.size\n\t\tpercent_uploaded:0\n\t\tuploader:ops.uploader\n\t\tstatus:\"signing\"\n\n\tid = S3.collection.insert initial_file_data\n\n\tops.connection.call \"_s3_sign\",\n\t\tpath:ops.path\n\t\tfile_name: initial_file_data.file.name\n\t\tfile_type:file.type\n\t\tfile_size:file.size\n\t\tacl:ops.acl\n\t\tbucket:ops.bucket\n\t\tregion:ops.region\n\t\texpiration:ops.expiration\n\t\tserver_side_encryption:ops.server_side_encryption\n\t\tcontent_disposition:ops.content_disposition\n\t\t(error,result) ->\n\t\t\tif result\n\t\t\t\t# Mark as signed\n\t\t\t\tS3.collection.update id,\n\t\t\t\t\t$set:\n\t\t\t\t\t\tstatus:\"uploading\"\n\n\t\t\t\t# Prepare data\n\t\t\t\tform_data = new FormData()\n\t\t\t\tform_data.append \"key\", result.key\n\t\t\t\tform_data.append \"acl\", result.acl\n\t\t\t\tform_data.append \"Content-Type\", result.file_type\n\t\t\t\tif ops.content_disposition\n\t\t\t\t\tform_data.append \"Content-Disposition\", ops.content_disposition\n\t\t\t\tform_data.append \"X-Amz-Date\", result.meta_date\n\t\t\t\tif ops.server_side_encryption\n\t\t\t\t\tform_data.append \"x-amz-server-side-encryption\", \"AES256\"\n\t\t\t\tform_data.append \"x-amz-meta-uuid\", result.meta_uuid\n\t\t\t\tform_data.append \"X-Amz-Algorithm\", \"AWS4-HMAC-SHA256\"\n\t\t\t\tform_data.append \"X-Amz-Credential\", result.meta_credential\n\t\t\t\tform_data.append \"X-Amz-Signature\",result.signature\n\n\t\t\t\tform_data.append \"Policy\",result.policy\n\n\t\t\t\tform_data.append \"file\",file\n\n\t\t\t\t# Send data\n\t\t\t\txhr = new XMLHttpRequest()\n\n\t\t\t\txhr.upload.addEventListener \"progress\", (event) ->\n\t\t\t\t\t\tS3.collection.update id,\n\t\t\t\t\t\t\t$set:\n\t\t\t\t\t\t\t\tstatus:\"uploading\"\n\t\t\t\t\t\t\t\tloaded:event.loaded\n\t\t\t\t\t\t\t\ttotal:event.total\n\t\t\t\t\t\t\t\tpercent_uploaded: Math.floor ((event.loaded / event.total) * 100)\n\t\t\t\t\t,false\n\n\t\t\t\txhr.addEventListener \"load\", ->\n\t\t\t\t\tif xhr.status < 400\n\t\t\t\t\t\tS3.collection.update id,\n\t\t\t\t\t\t\t$set:\n\t\t\t\t\t\t\t\tstatus:\"complete\"\n\t\t\t\t\t\t\t\tpercent_uploaded: 100\n\t\t\t\t\t\t\t\turl:result.url\n\t\t\t\t\t\t\t\tsecure_url:result.secure_url\n\t\t\t\t\t\t\t\trelative_url:result.relative_url\n\n\t\t\t\t\t\tcallback and callback null,S3.collection.findOne id\n\t\t\t\t\telse\n\t\t\t\t\t\tcallback and callback true,null\n\n\t\t\t\txhr.addEventListener \"error\", ->\n\t\t\t\t\tcallback and callback true,null\n\n\t\t\t\txhr.addEventListener \"abort\", ->\n\t\t\t\t\tconsole.log \"aborted by user\"\n\n\t\t\t\txhr.open \"POST\",result.post_url,true\n\n\t\t\t\txhr.send form_data\n\t\t\telse\n\t\t\t\tcallback and callback error,null\n"
  },
  {
    "path": "coffeelint.json",
    "content": "{\n  \"arrow_spacing\": {\n    \"level\": \"error\"\n  },\n  \"braces_spacing\": {\n    \"level\": \"error\",\n    \"spaces\": 0,\n    \"empty_object_spaces\": 0\n  },\n  \"camel_case_classes\": {\n    \"level\": \"error\"\n  },\n  \"coffeescript_error\": {\n    \"level\": \"error\"\n  },\n  \"colon_assignment_spacing\": {\n    \"level\": \"ignore\",\n    \"spacing\": {\n      \"left\": 0,\n      \"right\": 0\n    }\n  },\n  \"cyclomatic_complexity\": {\n    \"level\": \"ignore\",\n    \"value\": 10\n  },\n  \"duplicate_key\": {\n    \"level\": \"error\"\n  },\n  \"empty_constructor_needs_parens\": {\n    \"level\": \"ignore\"\n  },\n  \"ensure_comprehensions\": {\n    \"level\": \"warn\"\n  },\n  \"eol_last\": {\n    \"level\": \"ignore\"\n  },\n  \"indentation\": {\n    \"value\": 1,\n    \"level\": \"error\"\n  },\n  \"line_endings\": {\n    \"level\": \"ignore\",\n    \"value\": \"unix\"\n  },\n  \"max_line_length\": {\n    \"value\": 80,\n    \"level\": \"ignore\",\n    \"limitComments\": true\n  },\n  \"missing_fat_arrows\": {\n    \"level\": \"ignore\",\n    \"is_strict\": false\n  },\n  \"newlines_after_classes\": {\n    \"value\": 3,\n    \"level\": \"ignore\"\n  },\n  \"no_backticks\": {\n    \"level\": \"error\"\n  },\n  \"no_debugger\": {\n    \"level\": \"warn\",\n    \"console\": false\n  },\n  \"no_empty_functions\": {\n    \"level\": \"ignore\"\n  },\n  \"no_empty_param_list\": {\n    \"level\": \"ignore\"\n  },\n  \"no_implicit_braces\": {\n    \"level\": \"ignore\",\n    \"strict\": true\n  },\n  \"no_implicit_parens\": {\n    \"level\": \"ignore\",\n    \"strict\": true\n  },\n  \"no_interpolation_in_single_quotes\": {\n    \"level\": \"ignore\"\n  },\n  \"no_nested_string_interpolation\": {\n    \"level\": \"warn\"\n  },\n  \"no_plusplus\": {\n    \"level\": \"ignore\"\n  },\n  \"no_private_function_fat_arrows\": {\n    \"level\": \"warn\"\n  },\n  \"no_stand_alone_at\": {\n    \"level\": \"ignore\"\n  },\n  \"no_tabs\": {\n    \"level\": \"ignore\"\n  },\n  \"no_this\": {\n    \"level\": \"ignore\"\n  },\n  \"no_throwing_strings\": {\n    \"level\": \"error\"\n  },\n  \"no_trailing_semicolons\": {\n    \"level\": \"error\"\n  },\n  \"no_trailing_whitespace\": {\n    \"level\": \"error\",\n    \"allowed_in_comments\": false,\n    \"allowed_in_empty_lines\": true\n  },\n  \"no_unnecessary_double_quotes\": {\n    \"level\": \"ignore\"\n  },\n  \"no_unnecessary_fat_arrows\": {\n    \"level\": \"warn\"\n  },\n  \"non_empty_constructor_needs_parens\": {\n    \"level\": \"ignore\"\n  },\n  \"prefer_english_operator\": {\n    \"level\": \"ignore\",\n    \"doubleNotLevel\": \"ignore\"\n  },\n  \"space_operators\": {\n    \"level\": \"ignore\"\n  },\n  \"spacing_after_comma\": {\n    \"level\": \"ignore\"\n  },\n  \"transform_messes_up_line_numbers\": {\n    \"level\": \"warn\"\n  }\n}\n"
  },
  {
    "path": "example/basic/.meteor/.finished-upgraders",
    "content": "# This file contains information which helps Meteor properly upgrade your\n# app when you run 'meteor update'. You should check it into version control\n# with your project.\n\nnotices-for-0.9.0\nnotices-for-0.9.1\n0.9.4-platform-file\nnotices-for-facebook-graph-api-2\n1.2.0-standard-minifiers-package\n1.2.0-meteor-platform-split\n1.2.0-cordova-changes\n1.2.0-breaking-changes\n1.3.0-split-minifiers-package\n1.4.0-remove-old-dev-bundle-link\n1.4.1-add-shell-server-package\n"
  },
  {
    "path": "example/basic/.meteor/.gitignore",
    "content": "local\n"
  },
  {
    "path": "example/basic/.meteor/.id",
    "content": "# This file contains a token that is unique to your project.\n# Check it into your repository along with the rest of this directory.\n# It can be used for purposes such as:\n#   - ensuring you don't accidentally deploy one app on top of another\n#   - providing package authors with aggregated statistics\n\nn8dvpiz2lro616zjewc\n"
  },
  {
    "path": "example/basic/.meteor/packages",
    "content": "# Meteor packages used by this project, one per line.\n#\n# 'meteor add' and 'meteor remove' will edit this file for you,\n# but you can also edit it by hand.\n\nstandard-app-packages@1.0.9\nautopublish@1.0.7\ninsecure@1.0.7\ncoffeescript@1.11.1_4\nlepozepo:s3\n\nstandard-minifier-css\nstandard-minifier-js\nshell-server\n"
  },
  {
    "path": "example/basic/.meteor/platforms",
    "content": "server\nbrowser\n"
  },
  {
    "path": "example/basic/.meteor/release",
    "content": "METEOR@1.4.2.3\n"
  },
  {
    "path": "example/basic/.meteor/versions",
    "content": "accounts-base@1.2.14\nallow-deny@1.0.5\nautopublish@1.0.7\nautoupdate@1.3.12\nbabel-compiler@6.13.0\nbabel-runtime@1.0.1\nbase64@1.0.10\nbinary-heap@1.0.10\nblaze@2.2.0\nblaze-tools@1.0.10\nboilerplate-generator@1.0.11\ncaching-compiler@1.1.9\ncaching-html-compiler@1.0.7\ncallback-hook@1.0.10\ncheck@1.2.4\ncoffeescript@1.11.1_4\nddp@1.2.5\nddp-client@1.3.2\nddp-common@1.2.8\nddp-rate-limiter@1.0.6\nddp-server@1.3.12\ndeps@1.0.12\ndiff-sequence@1.0.7\necmascript@0.6.1\necmascript-runtime@0.3.15\nejson@1.0.13\nfastclick@1.0.13\ngeojson-utils@1.0.10\nhot-code-push@1.0.4\nhtml-tools@1.0.11\nhtmljs@1.0.11\nhttp@1.2.10\nid-map@1.0.9\ninsecure@1.0.7\njquery@1.11.10\nlaunch-screen@1.1.0\nlepozepo:s3@5.2.4\nlivedata@1.0.18\nlocalstorage@1.0.12\nlogging@1.1.16\nmeteor@1.6.0\nmeteor-base@1.0.4\nmeteor-platform@1.2.6\nminifier-css@1.2.15\nminifier-js@1.2.15\nminimongo@1.0.19\nmobile-status-bar@1.0.13\nmodules@0.7.7\nmodules-runtime@0.7.7\nmongo@1.1.14\nmongo-id@1.0.6\nnpm-mongo@2.2.11_2\nobserve-sequence@1.0.14\nordered-dict@1.0.9\npromise@0.8.8\nrandom@1.0.10\nrate-limit@1.0.6\nreactive-dict@1.1.8\nreactive-var@1.0.11\nreload@1.1.11\nretry@1.0.9\nroutepolicy@1.0.12\nservice-configuration@1.0.11\nsession@1.1.7\nshell-server@0.2.1\nspacebars@1.0.13\nspacebars-compiler@1.0.13\nstandard-app-packages@1.0.9\nstandard-minifier-css@1.3.2\nstandard-minifier-js@1.2.1\ntemplating@1.2.15\ntemplating-compiler@1.2.15\ntemplating-runtime@1.2.15\ntemplating-tools@1.0.5\ntracker@1.1.1\nui@1.0.12\nunderscore@1.0.10\nurl@1.0.11\nwebapp@1.3.12\nwebapp-hashing@1.0.9\n"
  },
  {
    "path": "example/basic/basic.coffee",
    "content": "if Meteor.isClient\n\tTemplate.basic.helpers\n\t\t\"files\": -> S3.collection.find()\n\n\tTemplate.basic.events\n\t\t\"click button.upload\": (event) ->\n\t\t\tS3.upload\n\t\t\t\tfiles:$(\"input.file_bag\")[0].files\n\t\t\t\t(error,result) ->\n\t\t\t\t\tif error\n\t\t\t\t\t\tconsole.log \"Unable to upload\"\n\t\t\t\t\telse\n\t\t\t\t\t\tconsole.log result\n\n\t\t\"click button.delete\": (event) ->\n\t\t\tS3.delete @relative_url, (error,res) =>\n\t\t\t\tif not error\n\t\t\t\t\tconsole.log res\n\t\t\t\t\tS3.collection.remove @_id\n\t\t\t\telse\n\t\t\t\t\tconsole.log error\n\nif Meteor.isServer\n\tS3.config =\n\t\tkey:\"yourkey\"\n\t\tsecret:\"yoursecret\"\n\t\tbucket:\"yourbucket\"\n\t\t# region:\"us-standard\" #default\n\n\n\n\n"
  },
  {
    "path": "example/basic/basic.html",
    "content": "<head>\n  <title>basic</title>\n</head>\n\n<body>\n  {{> basic}}\n</body>\n\n<template name=\"basic\">\n\n\t<input type=\"file\" class=\"file_bag\" multiple>\n\t<button class=\"upload\">upload it</button>\n\n\t{{#each files}}\n\t\t<p>{{percent_uploaded}}</p>\n\t\t<img src=\"{{secure_url}}\" height=\"250px\">\n\t\t<button class=\"delete\">Delete</button>\n\t{{/each}}\n\n</template>\n"
  },
  {
    "path": "example/basic/packages/.gitignore",
    "content": "/s3\n"
  },
  {
    "path": "example/mdg_camera/.meteor/.finished-upgraders",
    "content": "# This file contains information which helps Meteor properly upgrade your\n# app when you run 'meteor update'. You should check it into version control\n# with your project.\n\nnotices-for-0.9.0\nnotices-for-0.9.1\n0.9.4-platform-file\n"
  },
  {
    "path": "example/mdg_camera/.meteor/.gitignore",
    "content": "local\n"
  },
  {
    "path": "example/mdg_camera/.meteor/.id",
    "content": "# This file contains a token that is unique to your project.\n# Check it into your repository along with the rest of this directory.\n# It can be used for purposes such as:\n#   - ensuring you don't accidentally deploy one app on top of another\n#   - providing package authors with aggregated statistics\n\nn8dvpiz2lro616zjewc\n"
  },
  {
    "path": "example/mdg_camera/.meteor/cordova-plugins",
    "content": "\n"
  },
  {
    "path": "example/mdg_camera/.meteor/packages",
    "content": "# Meteor packages used by this project, one per line.\n#\n# 'meteor add' and 'meteor remove' will edit this file for you,\n# but you can also edit it by hand.\n\nstandard-app-packages\nautopublish\ninsecure\ncoffeescript\nlepozepo:s3\nmdg:camera\n\n"
  },
  {
    "path": "example/mdg_camera/.meteor/platforms",
    "content": "server\nbrowser\nios\n"
  },
  {
    "path": "example/mdg_camera/.meteor/release",
    "content": "METEOR@1.0.4.1\n"
  },
  {
    "path": "example/mdg_camera/.meteor/versions",
    "content": "accounts-base@1.2.0\nautopublish@1.0.3\nautoupdate@1.2.0\nbase64@1.0.3\nbinary-heap@1.0.3\nblaze@2.1.0\nblaze-tools@1.0.3\nboilerplate-generator@1.0.3\ncallback-hook@1.0.3\ncheck@1.0.5\ncoffeescript@1.0.6\nddp@1.1.0\ndeps@1.0.7\nejson@1.0.6\nfastclick@1.0.3\ngeojson-utils@1.0.3\nhtml-tools@1.0.4\nhtmljs@1.0.4\nhttp@1.1.0\nid-map@1.0.3\ninsecure@1.0.3\njquery@1.11.3_2\njson@1.0.3\nlaunch-screen@1.0.2\nlepozepo:s3@5.1.0\nless@1.0.13\nlivedata@1.0.13\nlocalstorage@1.0.3\nlogging@1.0.7\nmdg:camera@1.1.4\nmeteor@1.1.5\nmeteor-platform@1.2.2\nminifiers@1.1.4\nminimongo@1.0.7\nmobile-status-bar@1.0.3\nmongo@1.1.0\nobserve-sequence@1.0.5\nordered-dict@1.0.3\nrandom@1.0.3\nreactive-dict@1.1.0\nreactive-var@1.0.5\nreload@1.1.3\nretry@1.0.3\nroutepolicy@1.0.5\nservice-configuration@1.0.4\nsession@1.1.0\nspacebars@1.0.6\nspacebars-compiler@1.0.5\nstandard-app-packages@1.0.5\ntemplating@1.1.0\ntracker@1.0.6\nui@1.0.6\nunderscore@1.0.3\nurl@1.0.4\nwebapp@1.2.0\nwebapp-hashing@1.0.3\n"
  },
  {
    "path": "example/mdg_camera/mdg_camera.coffee",
    "content": "if Meteor.isClient\n\tTemplate.basic.helpers\n\t\t\"files\": -> S3.collection.find()\n\n\tTemplate.basic.events\n\t\t\"click button.upload\": (event) ->\n\t\t\tS3.upload\n\t\t\t\tfiles:[$(\"textarea\").val()]\n\t\t\t\tpath:\"tester\"\n\t\t\t\tencoding:\"base64\"\n\t\t\t\t(error,result) ->\n\t\t\t\t\tif error\n\t\t\t\t\t\tconsole.log error\n\t\t\t\t\telse\n\t\t\t\t\t\tconsole.log result\n\n\t\t\"click button.delete\": (event) ->\n\t\t\tS3.delete @relative_url, (error,res) ->\n\t\t\t\tif not error\n\t\t\t\t\tconsole.log res\n\t\t\t\telse\n\t\t\t\t\tconsole.log error\n\nif Meteor.isServer\n\tS3.config =\n\t\tkey:\"yourkey\"\n\t\tsecret:\"yousecret\"\n\t\tbucket:\"yourbucket\"\n\n\n"
  },
  {
    "path": "example/mdg_camera/mdg_camera.html",
    "content": "<head>\n  <title>mdg:camera</title>\n</head>\n\n<body>\n  {{> basic}}\n</body>\n\n<template name=\"basic\">\n\n\t<img src=\"data:image/gif;base64,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\">\n\n\t<textarea rows=\"4\">\ndata:image/gif;base64,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\n\t</textarea>\n\n\t<br>\n\t<button class=\"upload\">upload the base64 image</button>\n\n\t{{#each files}}\n\t\t<p>{{percent_uploaded}}</p>\n\t\t<img src=\"{{secure_url}}\" height=\"250px\">\n\t\t<button class=\"delete\">Delete</button>\n\t{{/each}}\n\n</template>\n"
  },
  {
    "path": "example/mdg_camera/packages/.gitignore",
    "content": "/s3\n"
  },
  {
    "path": "package.js",
    "content": "Package.describe({\n\tname:\"lepozepo:s3\",\n\tsummary: \"Upload files to S3. Allows use of Knox Server-Side.\",\n\tversion:\"5.2.8\",\n\tgit:\"https://github.com/Lepozepo/S3\"\n});\n\nNpm.depends({\n\tknox: \"0.9.2\",\n\t\"stream-buffers\":\"2.1.0\",\n\t\"aws-sdk\":\"2.1.14\",\n\t\"crypto-js\":\"3.1.6\",\n\t\"moment\":\"2.13.0\"\n});\n\nPackage.on_use(function (api) {\n\tapi.versionsFrom('METEOR@1.0');\n\n\tapi.use([\"meteor-base@1.0.1\",\"coffeescript\",\"service-configuration\"], [\"client\", \"server\"]);\n\tapi.use([\"check\",\"random\"], [\"client\",\"server\"]);\n\n\t// Client\n\tapi.add_files(\"client/functions.coffee\", \"client\");\n\n\t// Server\n\tapi.add_files(\"server/startup.coffee\", \"server\");\n\tapi.add_files(\"server/sign_request.coffee\", \"server\");\n\tapi.add_files(\"server/delete_object.coffee\", \"server\");\n\n\t//Allows user access to Knox\n\tapi.export && api.export(\"Knox\",\"server\");\n\n\t//Allows user access to AWS-SDK\n\tapi.export && api.export(\"AWS\",\"server\");\n});\n"
  },
  {
    "path": "server/delete_object.coffee",
    "content": "Future = Npm.require 'fibers/future'\n\nMeteor.methods\n\t_s3_delete: (path) ->\n\t\t@unblock()\n\t\tcheck path,String\n\n\t\tfuture = new Future()\n\n\t\tif S3.rules?.delete\n\t\t\tdelete_context = _.extend this,\n\t\t\t\ts3_delete_path:path\n\n\t\t\tauth_function = _.bind S3.rules.delete,delete_context\n\t\t\tif not auth_function()\n\t\t\t\tthrow new Meteor.Error \"Unauthorized\", \"Delete not allowed\"\n\n\t\tS3.knox.deleteFile path, (e,r) ->\n\t\t\tif e\n\t\t\t\tfuture.return e\n\t\t\telse\n\t\t\t\tfuture.return true\n\n\t\tfuture.wait()\n"
  },
  {
    "path": "server/sign_request.coffee",
    "content": "Meteor.methods\n\t_s3_sign: (ops={}) ->\n\t\t@unblock()\n\t\t# ops.expiration: the signature expires after x milliseconds | defaults to 30 minutes\n\t\t# ops.path\n\t\t# ops.file_type\n\t\t# ops.file_name\n\t\t# ops.file_size\n\t\t# ops.acl\n\t\t# ops.bucket\n\t\t# ops.server_side_encryption\n\t\t# ops.content_disposition\n\n\t\t_.defaults ops,\n\t\t\texpiration:1800000\n\t\t\tpath:\"\"\n\t\t\tbucket:S3.config.bucket\n\t\t\tacl:\"public-read\"\n\t\t\tregion:S3.config.region\n\t\t\tserver_side_encryption:false\n\t\t\tcontent_disposition:\"inline\"\n\n\t\tcheck ops,\n\t\t\texpiration:Number\n\t\t\tpath:String\n\t\t\tbucket:String\n\t\t\tacl:String\n\t\t\tregion:String\n\t\t\tserver_side_encryption:Boolean\n\t\t\tfile_type:String\n\t\t\tfile_name:String\n\t\t\tfile_size:Number\n\t\t\tcontent_disposition:String\n\n\t\texpiration = new Date Date.now() + ops.expiration\n\t\texpiration = expiration.toISOString()\n\n\t\tif _.isEmpty ops.path\n\t\t\tkey = \"#{ops.file_name}\"\n\t\telse\n\t\t\tkey = \"#{ops.path}/#{ops.file_name}\"\n\n\t\tmeta_uuid = Random.id()\n\t\tmeta_date = \"#{moment().format('YYYYMMDD')}T000000Z\"\n\t\tmeta_credential = \"#{S3.config.key}/#{moment().format('YYYYMMDD')}/#{ops.region}/s3/aws4_request\"\n\t\tpolicy =\n\t\t\t\"expiration\":expiration\n\t\t\t\"conditions\":[\n\t\t\t\t[\"content-length-range\",0,ops.file_size]\n\t\t\t\t{\"key\":key}\n\t\t\t\t{\"bucket\":ops.bucket}\n\t\t\t\t{\"Content-Type\":ops.file_type}\n\t\t\t\t{\"acl\":ops.acl}\n\t\t\t\t{\"x-amz-algorithm\": \"AWS4-HMAC-SHA256\"}\n\t\t\t\t{\"x-amz-credential\": meta_credential}\n\t\t\t\t{\"x-amz-date\": meta_date }\n\t\t\t\t{\"x-amz-meta-uuid\": meta_uuid}\n\t\t\t]\n\t\tif ops.content_disposition\n\t\t\tpolicy[\"conditions\"].push({\"Content-Disposition\": ops.content_disposition})\n\t\tif ops.server_side_encryption\n\t\t\tpolicy[\"conditions\"].push({\"x-amz-server-side-encryption\": \"AES256\"})\n\n\t\t# Encode the policy\n\t\tpolicy = new Buffer(JSON.stringify(policy), \"utf-8\").toString(\"base64\")\n\n\t\t# Sign the policy\n\t\tsignature = calculate_signature policy, ops.region\n\n\t\t# Identify post_url\n\t\tif ops.region is \"us-east-1\" or ops.region is \"us-standard\"\n\t\t\tpost_url = \"https://s3.amazonaws.com/#{ops.bucket}\"\n\t\telse\n\t\t\tpost_url = \"https://s3-#{ops.region}.amazonaws.com/#{ops.bucket}\"\n\n\t\t# Return results\n\t\tpolicy:policy\n\t\tsignature:signature\n\t\taccess_key:S3.config.key\n\t\tpost_url:post_url\n\t\turl:\"#{post_url}/#{key}\".replace(\"https://\",\"http://\")\n\t\tsecure_url:\"#{post_url}/#{key}\"\n\t\trelative_url:\"/#{key}\"\n\t\tbucket:ops.bucket\n\t\tacl:ops.acl\n\t\tkey:key\n\t\tfile_type:ops.file_type\n\t\tfile_name:ops.file_name\n\t\tmeta_uuid:meta_uuid\n\t\tmeta_date:meta_date\n\t\tmeta_credential:meta_credential\n\n\n# crypto = Npm.require(\"crypto\")\nCrypto = Npm.require \"crypto-js\"\nmoment = Npm.require \"moment\"\n{HmacSHA256} = Crypto\n\ncalculate_signature = (policy, region) ->\n\tkDate = HmacSHA256(moment().format(\"YYYYMMDD\"), \"AWS4\" + S3.config.secret);\n\tkRegion = HmacSHA256(region, kDate);\n\tkService = HmacSHA256(\"s3\", kRegion);\n\tsignature_key = HmacSHA256(\"aws4_request\", kService);\n\n\tHmacSHA256 policy, signature_key\n\t\t.toString Crypto.enc.Hex\n\n\n"
  },
  {
    "path": "server/startup.coffee",
    "content": "#Get Knox and AWS libraries\nKnox = Npm.require \"knox\"\n\nprocessBrowser = process.browser\nprocess.browser = false\nAWS = Npm.require \"aws-sdk\"\nprocess.browser = processBrowser\n\n#Server side configuration variables\n@S3 =\n\tconfig:{}\n\tknox:{}\n\taws:{}\n\trules:{}\n\nMeteor.startup ->\n\tif not _.has S3.config,\"key\"\n\t\tconsole.log \"S3: AWS key is undefined\"\n\n\tif not _.has S3.config,\"secret\"\n\t\tconsole.log \"S3: AWS secret is undefined\"\n\n\tif not _.has S3.config,\"bucket\"\n\t\tconsole.log \"S3: AWS bucket is undefined\"\n\n\tif not _.has(S3.config,\"bucket\") or not _.has(S3.config,\"secret\") or not _.has(S3.config,\"key\")\n\t\treturn\n\n\t_.defaults S3.config,\n\t\tregion:\"us-east-1\" # us-standard\n\n\tS3.knox = Knox.createClient S3.config\n\tS3.aws = new AWS.S3\n\t\taccessKeyId:S3.config.key\n\t\tsecretAccessKey:S3.config.secret\n\t\tregion:S3.config.region\n\n"
  },
  {
    "path": "versions.json",
    "content": "{\n  \"dependencies\": [\n    [\n      \"accounts-base\",\n      \"1.1.2\"\n    ],\n    [\n      \"application-configuration\",\n      \"1.0.3\"\n    ],\n    [\n      \"base64\",\n      \"1.0.1\"\n    ],\n    [\n      \"binary-heap\",\n      \"1.0.1\"\n    ],\n    [\n      \"callback-hook\",\n      \"1.0.1\"\n    ],\n    [\n      \"check\",\n      \"1.0.2\"\n    ],\n    [\n      \"coffeescript\",\n      \"1.0.4\"\n    ],\n    [\n      \"ddp\",\n      \"1.0.11\"\n    ],\n    [\n      \"ejson\",\n      \"1.0.4\"\n    ],\n    [\n      \"follower-livedata\",\n      \"1.0.2\"\n    ],\n    [\n      \"geojson-utils\",\n      \"1.0.1\"\n    ],\n    [\n      \"id-map\",\n      \"1.0.1\"\n    ],\n    [\n      \"json\",\n      \"1.0.1\"\n    ],\n    [\n      \"localstorage\",\n      \"1.0.1\"\n    ],\n    [\n      \"logging\",\n      \"1.0.5\"\n    ],\n    [\n      \"meteor\",\n      \"1.1.3\"\n    ],\n    [\n      \"minimongo\",\n      \"1.0.5\"\n    ],\n    [\n      \"mongo\",\n      \"1.0.8\"\n    ],\n    [\n      \"ordered-dict\",\n      \"1.0.1\"\n    ],\n    [\n      \"random\",\n      \"1.0.1\"\n    ],\n    [\n      \"retry\",\n      \"1.0.1\"\n    ],\n    [\n      \"service-configuration\",\n      \"1.0.2\"\n    ],\n    [\n      \"tracker\",\n      \"1.0.3\"\n    ],\n    [\n      \"underscore\",\n      \"1.0.1\"\n    ]\n  ],\n  \"pluginDependencies\": [],\n  \"toolVersion\": \"meteor-tool@1.0.35\",\n  \"format\": \"1.0\"\n}"
  }
]