From 39c71ecc809f46a6111599515462bd3e7e19c1ab Mon Sep 17 00:00:00 2001 From: Louie McConnell Date: Thu, 21 Sep 2017 23:55:41 -0700 Subject: [PATCH] submitting --- .DS_Store | Bin 0 -> 6148 bytes Podfile | 11 + Podfile.lock | 25 + Pods/HanekeSwift/Haneke/CGSize+Swift.swift | 35 + Pods/HanekeSwift/Haneke/Cache.swift | 311 ++++++ Pods/HanekeSwift/Haneke/CryptoSwiftMD5.swift | 229 +++++ Pods/HanekeSwift/Haneke/Data.swift | 129 +++ Pods/HanekeSwift/Haneke/DiskCache.swift | 237 +++++ Pods/HanekeSwift/Haneke/DiskFetcher.swift | 92 ++ Pods/HanekeSwift/Haneke/Fetch.swift | 89 ++ Pods/HanekeSwift/Haneke/Fetcher.swift | 41 + Pods/HanekeSwift/Haneke/Format.swift | 93 ++ Pods/HanekeSwift/Haneke/Haneke.swift | 55 ++ Pods/HanekeSwift/Haneke/Log.swift | 38 + .../Haneke/NSFileManager+Haneke.swift | 65 ++ .../Haneke/NSHTTPURLResponse+Haneke.swift | 22 + .../Haneke/NSURLResponse+Haneke.swift | 22 + Pods/HanekeSwift/Haneke/NetworkFetcher.swift | 105 +++ Pods/HanekeSwift/Haneke/String+Haneke.swift | 49 + Pods/HanekeSwift/Haneke/UIButton+Haneke.swift | 234 +++++ Pods/HanekeSwift/Haneke/UIImage+Haneke.swift | 81 ++ .../Haneke/UIImageView+Haneke.swift | 139 +++ Pods/HanekeSwift/Haneke/UIView+Haneke.swift | 48 + Pods/HanekeSwift/LICENSE | 201 ++++ Pods/HanekeSwift/README.md | 249 +++++ Pods/Local Podspecs/HanekeSwift.podspec.json | 20 + Pods/Manifest.lock | 25 + Pods/ObjectMapper/LICENSE | 8 + Pods/ObjectMapper/README-CN.md | 502 ++++++++++ .../Sources/CustomDateFormatTransform.swift | 40 + Pods/ObjectMapper/Sources/DataTransform.swift | 50 + .../Sources/DateFormatterTransform.swift | 54 ++ Pods/ObjectMapper/Sources/DateTransform.swift | 55 ++ .../Sources/DictionaryTransform.swift | 58 ++ Pods/ObjectMapper/Sources/EnumOperators.swift | 91 ++ Pods/ObjectMapper/Sources/EnumTransform.swift | 50 + Pods/ObjectMapper/Sources/FromJSON.swift | 181 ++++ .../Sources/HexColorTransform.swift | 126 +++ .../Sources/ISO8601DateTransform.swift | 47 + .../Sources/ImmutableMappable.swift | 315 +++++++ .../Sources/IntegerOperators.swift | 145 +++ Pods/ObjectMapper/Sources/Map.swift | 181 ++++ Pods/ObjectMapper/Sources/MapError.swift | 68 ++ Pods/ObjectMapper/Sources/Mappable.swift | 136 +++ Pods/ObjectMapper/Sources/Mapper.swift | 446 +++++++++ .../Sources/NSDecimalNumberTransform.swift | 52 + Pods/ObjectMapper/Sources/Operators.swift | 377 ++++++++ Pods/ObjectMapper/Sources/ToJSON.swift | 179 ++++ Pods/ObjectMapper/Sources/TransformOf.swift | 48 + .../Sources/TransformOperators.swift | 617 ++++++++++++ Pods/ObjectMapper/Sources/TransformType.swift | 35 + Pods/ObjectMapper/Sources/URLTransform.swift | 67 ++ Pods/Pods.xcodeproj/project.pbxproj | 890 ++++++++++++++++++ .../xcschemes/HanekeSwift.xcscheme | 71 ++ .../xcschemes/ObjectMapper.xcscheme | 60 ++ .../xcschemes/Pods-Pokedex.xcscheme | 71 ++ .../xcschemes/xcschememanagement.plist | 42 + .../HanekeSwift/HanekeSwift-dummy.m | 5 + .../HanekeSwift/HanekeSwift-prefix.pch | 12 + .../HanekeSwift/HanekeSwift-umbrella.h | 16 + .../HanekeSwift/HanekeSwift.modulemap | 6 + .../HanekeSwift/HanekeSwift.xcconfig | 10 + .../HanekeSwift/Info.plist | 26 + .../ObjectMapper/Info.plist | 26 + .../ObjectMapper/ObjectMapper-dummy.m | 5 + .../ObjectMapper/ObjectMapper-prefix.pch | 12 + .../ObjectMapper/ObjectMapper-umbrella.h | 16 + .../ObjectMapper/ObjectMapper.modulemap | 6 + .../ObjectMapper/ObjectMapper.xcconfig | 11 + .../Pods-Pokedex/Info.plist | 26 + .../Pods-Pokedex-acknowledgements.markdown | 219 +++++ .../Pods-Pokedex-acknowledgements.plist | 257 +++++ .../Pods-Pokedex/Pods-Pokedex-dummy.m | 5 + .../Pods-Pokedex/Pods-Pokedex-frameworks.sh | 114 +++ .../Pods-Pokedex/Pods-Pokedex-resources.sh | 106 +++ .../Pods-Pokedex/Pods-Pokedex-umbrella.h | 16 + .../Pods-Pokedex/Pods-Pokedex.debug.xcconfig | 11 + .../Pods-Pokedex/Pods-Pokedex.modulemap | 6 + .../Pods-Pokedex.release.xcconfig | 11 + Pokedex.xcodeproj/project.pbxproj | 674 +++++++++++++ .../contents.xcworkspacedata | 7 + .../UserInterfaceState.xcuserstate | Bin 0 -> 50344 bytes .../UserInterfaceState.xcuserstate | Bin 0 -> 29483 bytes .../UserInterfaceState.xcuserstate | Bin 0 -> 13236 bytes .../UserInterfaceState.xcuserstate | Bin 0 -> 13693 bytes .../xcschemes/Pokedex.xcscheme | 111 +++ .../xcschemes/xcschememanagement.plist | 32 + .../xcdebugger/Breakpoints_v2.xcbkptlist | 23 + .../xcschemes/Pokedex.xcscheme | 111 +++ .../xcschemes/xcschememanagement.plist | 32 + .../xcschemes/Pokedex.xcscheme | 111 +++ .../xcschemes/xcschememanagement.plist | 32 + .../xcdebugger/Breakpoints_v2.xcbkptlist | 23 + .../xcschemes/Pokedex.xcscheme | 111 +++ .../xcschemes/xcschememanagement.plist | 32 + Pokedex.xcworkspace/contents.xcworkspacedata | 10 + .../UserInterfaceState.xcuserstate | Bin 0 -> 38575 bytes .../xcdebugger/Breakpoints_v2.xcbkptlist | 151 +++ Pokedex/.DS_Store | Bin 0 -> 10244 bytes Pokedex/AppDelegate.swift | 46 + Pokedex/Assets.xcassets/.DS_Store | Bin 0 -> 6148 bytes .../AppIcon.appiconset/Contents.json | 48 + Pokedex/Assets.xcassets/Contents.json | 6 + .../image.imageset/Contents.json | 21 + .../image.imageset/unnamed.png | Bin 0 -> 56320 bytes .../pokeball.imageset/Contents.json | 21 + .../pokeball.imageset/pokeball.png | Bin 0 -> 8837 bytes Pokedex/Base.lproj/LaunchScreen.storyboard | 27 + Pokedex/Base.lproj/Main.storyboard | 222 +++++ Pokedex/CategorySelectionViewController.swift | 300 ++++++ Pokedex/FavoritesViewController.swift | 126 +++ Pokedex/GoogleSearchWebViewController.swift | 29 + Pokedex/Info.plist | 43 + Pokedex/OpeningViewController.swift | 127 +++ Pokedex/Pokemon.swift | 78 ++ Pokedex/PokemonCollectionViewCell.swift | 47 + Pokedex/PokemonCollectionViewCell.swift.orig | 42 + Pokedex/PokemonGenerator.swift | 62 ++ Pokedex/PokemonProfileViewController.swift | 203 ++++ Pokedex/PokemonTableViewCell.swift | 57 ++ Pokedex/PokemonTableViewController.swift | 94 ++ Pokedex/SearchBarViewController.swift | 88 ++ Pokedex/SearchResultsViewController.swift | 243 +++++ Pokedex/TypeSelectorViewController.swift | 131 +++ Pokedex/TypeTableViewCell.swift | 29 + Pokedex/TypeTwoTableViewCell.swift | 29 + Pokedex/Utils.swift | 21 + Pokedex/imageFromURLRef.swift | 43 + Pokedex/pokeData.json | 1 + PokedexTests/Info.plist | 22 + PokedexTests/PokedexTests.swift | 36 + PokedexUITests/Info.plist | 22 + PokedexUITests/PokedexUITests.swift | 36 + README.md | 7 +- 134 files changed, 12390 insertions(+), 6 deletions(-) create mode 100644 .DS_Store create mode 100644 Podfile create mode 100644 Podfile.lock create mode 100644 Pods/HanekeSwift/Haneke/CGSize+Swift.swift create mode 100644 Pods/HanekeSwift/Haneke/Cache.swift create mode 100755 Pods/HanekeSwift/Haneke/CryptoSwiftMD5.swift create mode 100644 Pods/HanekeSwift/Haneke/Data.swift create mode 100644 Pods/HanekeSwift/Haneke/DiskCache.swift create mode 100644 Pods/HanekeSwift/Haneke/DiskFetcher.swift create mode 100644 Pods/HanekeSwift/Haneke/Fetch.swift create mode 100644 Pods/HanekeSwift/Haneke/Fetcher.swift create mode 100644 Pods/HanekeSwift/Haneke/Format.swift create mode 100644 Pods/HanekeSwift/Haneke/Haneke.swift create mode 100644 Pods/HanekeSwift/Haneke/Log.swift create mode 100644 Pods/HanekeSwift/Haneke/NSFileManager+Haneke.swift create mode 100644 Pods/HanekeSwift/Haneke/NSHTTPURLResponse+Haneke.swift create mode 100644 Pods/HanekeSwift/Haneke/NSURLResponse+Haneke.swift create mode 100644 Pods/HanekeSwift/Haneke/NetworkFetcher.swift create mode 100644 Pods/HanekeSwift/Haneke/String+Haneke.swift create mode 100644 Pods/HanekeSwift/Haneke/UIButton+Haneke.swift create mode 100644 Pods/HanekeSwift/Haneke/UIImage+Haneke.swift create mode 100644 Pods/HanekeSwift/Haneke/UIImageView+Haneke.swift create mode 100644 Pods/HanekeSwift/Haneke/UIView+Haneke.swift create mode 100644 Pods/HanekeSwift/LICENSE create mode 100644 Pods/HanekeSwift/README.md create mode 100644 Pods/Local Podspecs/HanekeSwift.podspec.json create mode 100644 Pods/Manifest.lock create mode 100644 Pods/ObjectMapper/LICENSE create mode 100644 Pods/ObjectMapper/README-CN.md create mode 100644 Pods/ObjectMapper/Sources/CustomDateFormatTransform.swift create mode 100644 Pods/ObjectMapper/Sources/DataTransform.swift create mode 100644 Pods/ObjectMapper/Sources/DateFormatterTransform.swift create mode 100644 Pods/ObjectMapper/Sources/DateTransform.swift create mode 100644 Pods/ObjectMapper/Sources/DictionaryTransform.swift create mode 100644 Pods/ObjectMapper/Sources/EnumOperators.swift create mode 100644 Pods/ObjectMapper/Sources/EnumTransform.swift create mode 100755 Pods/ObjectMapper/Sources/FromJSON.swift create mode 100644 Pods/ObjectMapper/Sources/HexColorTransform.swift create mode 100644 Pods/ObjectMapper/Sources/ISO8601DateTransform.swift create mode 100644 Pods/ObjectMapper/Sources/ImmutableMappable.swift create mode 100644 Pods/ObjectMapper/Sources/IntegerOperators.swift create mode 100644 Pods/ObjectMapper/Sources/Map.swift create mode 100644 Pods/ObjectMapper/Sources/MapError.swift create mode 100644 Pods/ObjectMapper/Sources/Mappable.swift create mode 100755 Pods/ObjectMapper/Sources/Mapper.swift create mode 100644 Pods/ObjectMapper/Sources/NSDecimalNumberTransform.swift create mode 100755 Pods/ObjectMapper/Sources/Operators.swift create mode 100644 Pods/ObjectMapper/Sources/ToJSON.swift create mode 100644 Pods/ObjectMapper/Sources/TransformOf.swift create mode 100644 Pods/ObjectMapper/Sources/TransformOperators.swift create mode 100644 Pods/ObjectMapper/Sources/TransformType.swift create mode 100644 Pods/ObjectMapper/Sources/URLTransform.swift create mode 100644 Pods/Pods.xcodeproj/project.pbxproj create mode 100644 Pods/Pods.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/HanekeSwift.xcscheme create mode 100644 Pods/Pods.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/ObjectMapper.xcscheme create mode 100644 Pods/Pods.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/Pods-Pokedex.xcscheme create mode 100644 Pods/Pods.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 Pods/Target Support Files/HanekeSwift/HanekeSwift-dummy.m create mode 100644 Pods/Target Support Files/HanekeSwift/HanekeSwift-prefix.pch create mode 100644 Pods/Target Support Files/HanekeSwift/HanekeSwift-umbrella.h create mode 100644 Pods/Target Support Files/HanekeSwift/HanekeSwift.modulemap create mode 100644 Pods/Target Support Files/HanekeSwift/HanekeSwift.xcconfig create mode 100644 Pods/Target Support Files/HanekeSwift/Info.plist create mode 100644 Pods/Target Support Files/ObjectMapper/Info.plist create mode 100644 Pods/Target Support Files/ObjectMapper/ObjectMapper-dummy.m create mode 100644 Pods/Target Support Files/ObjectMapper/ObjectMapper-prefix.pch create mode 100644 Pods/Target Support Files/ObjectMapper/ObjectMapper-umbrella.h create mode 100644 Pods/Target Support Files/ObjectMapper/ObjectMapper.modulemap create mode 100644 Pods/Target Support Files/ObjectMapper/ObjectMapper.xcconfig create mode 100644 Pods/Target Support Files/Pods-Pokedex/Info.plist create mode 100644 Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-acknowledgements.markdown create mode 100644 Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-acknowledgements.plist create mode 100644 Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-dummy.m create mode 100755 Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-frameworks.sh create mode 100755 Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-resources.sh create mode 100644 Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-umbrella.h create mode 100644 Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex.debug.xcconfig create mode 100644 Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex.modulemap create mode 100644 Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex.release.xcconfig create mode 100644 Pokedex.xcodeproj/project.pbxproj create mode 100644 Pokedex.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Pokedex.xcodeproj/project.xcworkspace/xcuserdata/Annie.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 Pokedex.xcodeproj/project.xcworkspace/xcuserdata/louie_mc.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 Pokedex.xcodeproj/project.xcworkspace/xcuserdata/sahillamba.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 Pokedex.xcodeproj/project.xcworkspace/xcuserdata/sameersuresh.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 Pokedex.xcodeproj/xcuserdata/Annie.xcuserdatad/xcschemes/Pokedex.xcscheme create mode 100644 Pokedex.xcodeproj/xcuserdata/Annie.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 Pokedex.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist create mode 100644 Pokedex.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/Pokedex.xcscheme create mode 100644 Pokedex.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 Pokedex.xcodeproj/xcuserdata/sahillamba.xcuserdatad/xcschemes/Pokedex.xcscheme create mode 100644 Pokedex.xcodeproj/xcuserdata/sahillamba.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 Pokedex.xcodeproj/xcuserdata/sameersuresh.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist create mode 100644 Pokedex.xcodeproj/xcuserdata/sameersuresh.xcuserdatad/xcschemes/Pokedex.xcscheme create mode 100644 Pokedex.xcodeproj/xcuserdata/sameersuresh.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 Pokedex.xcworkspace/contents.xcworkspacedata create mode 100644 Pokedex.xcworkspace/xcuserdata/louie_mc.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 Pokedex.xcworkspace/xcuserdata/louie_mc.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist create mode 100644 Pokedex/.DS_Store create mode 100644 Pokedex/AppDelegate.swift create mode 100644 Pokedex/Assets.xcassets/.DS_Store create mode 100644 Pokedex/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 Pokedex/Assets.xcassets/Contents.json create mode 100644 Pokedex/Assets.xcassets/image.imageset/Contents.json create mode 100644 Pokedex/Assets.xcassets/image.imageset/unnamed.png create mode 100644 Pokedex/Assets.xcassets/pokeball.imageset/Contents.json create mode 100644 Pokedex/Assets.xcassets/pokeball.imageset/pokeball.png create mode 100644 Pokedex/Base.lproj/LaunchScreen.storyboard create mode 100644 Pokedex/Base.lproj/Main.storyboard create mode 100644 Pokedex/CategorySelectionViewController.swift create mode 100644 Pokedex/FavoritesViewController.swift create mode 100644 Pokedex/GoogleSearchWebViewController.swift create mode 100644 Pokedex/Info.plist create mode 100644 Pokedex/OpeningViewController.swift create mode 100644 Pokedex/Pokemon.swift create mode 100644 Pokedex/PokemonCollectionViewCell.swift create mode 100644 Pokedex/PokemonCollectionViewCell.swift.orig create mode 100644 Pokedex/PokemonGenerator.swift create mode 100644 Pokedex/PokemonProfileViewController.swift create mode 100644 Pokedex/PokemonTableViewCell.swift create mode 100644 Pokedex/PokemonTableViewController.swift create mode 100644 Pokedex/SearchBarViewController.swift create mode 100644 Pokedex/SearchResultsViewController.swift create mode 100644 Pokedex/TypeSelectorViewController.swift create mode 100644 Pokedex/TypeTableViewCell.swift create mode 100644 Pokedex/TypeTwoTableViewCell.swift create mode 100644 Pokedex/Utils.swift create mode 100644 Pokedex/imageFromURLRef.swift create mode 100644 Pokedex/pokeData.json create mode 100644 PokedexTests/Info.plist create mode 100644 PokedexTests/PokedexTests.swift create mode 100644 PokedexUITests/Info.plist create mode 100644 PokedexUITests/PokedexUITests.swift diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..0529e2d6aa6529190c2877c09dd46be7cd3bc815 GIT binary patch literal 6148 zcmeHK&2G~`5S~o}bwG%qBGKbsxCPV@3RD%63E{x4k`WvLwRUVZrjFOL9b5=Oehqj6 zZafC!#s%>J+;|FRc9+T~MRG3)p&e=WoBjEAGGDU0SpZ<8xjz8t0f2>tuyYQp6O6{G ztXNC;5Rb_Rl8XL6lgH=iO`2HNXwEEa=1TYY}*#_eUFFSfUbeSULzYq_+nD^~}1AMVdy zy3lATKR-+n`rAN=2c)mDSqV{=H_Ca zK`l4<_@Ozon%~xU3fVMfHOJF2Yk9&K8Prs#RX}eRi+;$)i~>dhqd-*wIv+R|LR(|0 zP#zsv$tM6}2fL-APj3n0aE-RcQX!6@F-1jGRHmO8OwqBQ>v^`uQlX*)(~l3PBQyO% zVKO?d&*gMrwn9@I1&ji91=_0Fqx=8CpWpv=l4%(Qi~|3a0<1H3#v@Eg->oaj(Ot{2 t>|-ILd8I;0!Af7p(xIz(1B)~q 2.2' + pod ‘HanekeSwift’, :git => ‘https://github.com/Haneke/HanekeSwift.git', :branch => ‘feature/swift-3’ +end diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 0000000..5ba009c --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,25 @@ +PODS: + - HanekeSwift (0.10.1) + - ObjectMapper (2.2.9) + +DEPENDENCIES: + - HanekeSwift (from `https://github.com/Haneke/HanekeSwift.git`, branch `feature/swift-3`) + - ObjectMapper (~> 2.2) + +EXTERNAL SOURCES: + HanekeSwift: + :branch: feature/swift-3 + :git: https://github.com/Haneke/HanekeSwift.git + +CHECKOUT OPTIONS: + HanekeSwift: + :commit: 2f6d87f1f725d204d85cb34492e8c399cd5a200f + :git: https://github.com/Haneke/HanekeSwift.git + +SPEC CHECKSUMS: + HanekeSwift: 4113367892828e7700d24a384027de6ebc79aad1 + ObjectMapper: 63cfe41bc6f8e7c8f44344c49901b8ae7de14c52 + +PODFILE CHECKSUM: 538d829ced17ecb6c715d132f791f34d2433468a + +COCOAPODS: 1.3.1 diff --git a/Pods/HanekeSwift/Haneke/CGSize+Swift.swift b/Pods/HanekeSwift/Haneke/CGSize+Swift.swift new file mode 100644 index 0000000..2e367ca --- /dev/null +++ b/Pods/HanekeSwift/Haneke/CGSize+Swift.swift @@ -0,0 +1,35 @@ +// +// CGSize+Swift.swift +// Haneke +// +// Created by Oriol Blanc Gimeno on 09/09/14. +// Copyright (c) 2014 Haneke. All rights reserved. +// + +import UIKit + +extension CGSize { + + func hnk_aspectFillSize(_ size: CGSize) -> CGSize { + let scaleWidth = size.width / self.width + let scaleHeight = size.height / self.height + let scale = max(scaleWidth, scaleHeight) + + let resultSize = CGSize(width: self.width * scale, height: self.height * scale) + return CGSize(width: ceil(resultSize.width), height: ceil(resultSize.height)) + } + + func hnk_aspectFitSize(_ size: CGSize) -> CGSize { + let targetAspect = size.width / size.height + let sourceAspect = self.width / self.height + var resultSize = size + + if (targetAspect > sourceAspect) { + resultSize.width = size.height * sourceAspect + } + else { + resultSize.height = size.width / sourceAspect + } + return CGSize(width: ceil(resultSize.width), height: ceil(resultSize.height)) + } +} diff --git a/Pods/HanekeSwift/Haneke/Cache.swift b/Pods/HanekeSwift/Haneke/Cache.swift new file mode 100644 index 0000000..99ce073 --- /dev/null +++ b/Pods/HanekeSwift/Haneke/Cache.swift @@ -0,0 +1,311 @@ +// +// Cache.swift +// Haneke +// +// Created by Luis Ascorbe on 23/07/14. +// Copyright (c) 2014 Haneke. All rights reserved. +// + +import UIKit + +// Used to add T to NSCache +class ObjectWrapper : NSObject { + let hnk_value: Any + + init(value: Any) { + self.hnk_value = value + } +} + +extension HanekeGlobals { + + // It'd be better to define this in the Cache class but Swift doesn't allow statics in a generic type + public struct Cache { + + public static let OriginalFormatName = "original" + + public enum ErrorCode : Int { + case objectNotFound = -100 + case formatNotFound = -101 + } + + } + +} + +open class Cache where T.Result == T, T : DataRepresentable { + + let name: String + + var memoryWarningObserver : NSObjectProtocol! + + public init(name: String) { + self.name = name + + let notifications = NotificationCenter.default + // Using block-based observer to avoid subclassing NSObject + memoryWarningObserver = notifications.addObserver(forName: Notification.Name.UIApplicationDidReceiveMemoryWarning, + object: nil, + queue: OperationQueue.main, + using: { [unowned self] (notification : Notification!) -> Void in + self.onMemoryWarning() + } + ) + + let originalFormat = Format(name: HanekeGlobals.Cache.OriginalFormatName) + self.addFormat(originalFormat) + } + + deinit { + let notifications = NotificationCenter.default + notifications.removeObserver(memoryWarningObserver, name: Notification.Name.UIApplicationDidReceiveMemoryWarning, object: nil) + } + + open func set(value: T, key: String, formatName: String = HanekeGlobals.Cache.OriginalFormatName, success succeed: ((T) -> ())? = nil) { + if let (format, memoryCache, diskCache) = self.formats[formatName] { + self.format(value: value, format: format) { formattedValue in + let wrapper = ObjectWrapper(value: formattedValue) + memoryCache.setObject(wrapper, forKey: key as AnyObject) + // Value data is sent as @autoclosure to be executed in the disk cache queue. + diskCache.setData(self.dataFromValue(formattedValue, format: format), key: key) + succeed?(formattedValue) + } + } else { + assertionFailure("Can't set value before adding format") + } + } + + @discardableResult open func fetch(key: String, formatName: String = HanekeGlobals.Cache.OriginalFormatName, failure fail : Fetch.Failer? = nil, success succeed : Fetch.Succeeder? = nil) -> Fetch { + let fetch = Cache.buildFetch(failure: fail, success: succeed) + if let (format, memoryCache, diskCache) = self.formats[formatName] { + if let wrapper = memoryCache.object(forKey: key as AnyObject) as? ObjectWrapper, let result = wrapper.hnk_value as? T { + fetch.succeed(result) + diskCache.updateAccessDate(self.dataFromValue(result, format: format), key: key) + return fetch + } + + self.fetchFromDiskCache(diskCache, key: key, memoryCache: memoryCache, failure: { error in + fetch.fail(error) + }) { value in + fetch.succeed(value) + } + + } else { + let localizedFormat = NSLocalizedString("Format %@ not found", comment: "Error description") + let description = String(format:localizedFormat, formatName) + let error = errorWithCode(HanekeGlobals.Cache.ErrorCode.formatNotFound.rawValue, description: description) + fetch.fail(error) + } + return fetch + } + + @discardableResult open func fetch(fetcher : Fetcher, formatName: String = HanekeGlobals.Cache.OriginalFormatName, failure fail : Fetch.Failer? = nil, success succeed : Fetch.Succeeder? = nil) -> Fetch { + let key = fetcher.key + let fetch = Cache.buildFetch(failure: fail, success: succeed) + self.fetch(key: key, formatName: formatName, failure: { error in + if (error as NSError?)?.code == HanekeGlobals.Cache.ErrorCode.formatNotFound.rawValue { + fetch.fail(error) + } + + if let (format, _, _) = self.formats[formatName] { + self.fetchAndSet(fetcher, format: format, failure: { error in + fetch.fail(error) + }) {value in + fetch.succeed(value) + } + } + + // Unreachable code. Formats can't be removed from Cache. + }) { value in + fetch.succeed(value) + } + return fetch + } + + open func remove(key: String, formatName: String = HanekeGlobals.Cache.OriginalFormatName) { + if let (_, memoryCache, diskCache) = self.formats[formatName] { + memoryCache.removeObject(forKey: key as AnyObject) + diskCache.removeData(with: key) + } + } + + open func removeAll(_ completion: (() -> ())? = nil) { + let group = DispatchGroup() + for (_, (_, memoryCache, diskCache)) in self.formats { + memoryCache.removeAllObjects() + group.enter() + diskCache.removeAllData { + group.leave() + } + } + DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async { + let timeout = DispatchTime.now() + Double(Int64(60 * NSEC_PER_SEC)) / Double(NSEC_PER_SEC) + if group.wait(timeout: timeout) != .success { + Log.error(message: "removeAll timed out waiting for disk caches") + } + let path = self.cachePath + do { + try FileManager.default.removeItem(atPath: path) + } catch { + Log.error(message: "Failed to remove path \(path)", error: error) + } + if let completion = completion { + DispatchQueue.main.async { + completion() + } + } + } + } + + // MARK: Size + + open var size: UInt64 { + var size: UInt64 = 0 + for (_, (_, _, diskCache)) in self.formats { + diskCache.cacheQueue.sync { size += diskCache.size } + } + return size + } + + // MARK: Notifications + + func onMemoryWarning() { + for (_, (_, memoryCache, _)) in self.formats { + memoryCache.removeAllObjects() + } + } + + // MARK: Formats + + public var formats : [String : (Format, NSCache, DiskCache)] = [:] + + open func addFormat(_ format : Format) { + let name = format.name + let formatPath = self.formatPath(withFormatName: name) + let memoryCache = NSCache() + let diskCache = DiskCache(path: formatPath, capacity : format.diskCapacity) + self.formats[name] = (format, memoryCache, diskCache) + } + + // MARK: Internal + + lazy var cachePath: String = { + let basePath = DiskCache.basePath() + let cachePath = (basePath as NSString).appendingPathComponent(self.name) + return cachePath + }() + + func formatPath(withFormatName formatName: String) -> String { + let formatPath = (self.cachePath as NSString).appendingPathComponent(formatName) + do { + try FileManager.default.createDirectory(atPath: formatPath, withIntermediateDirectories: true, attributes: nil) + } catch { + Log.error(message: "Failed to create directory \(formatPath)", error: error) + } + return formatPath + } + + // MARK: Private + + func dataFromValue(_ value : T, format : Format) -> Data? { + if let data = format.convertToData?(value) { + return data as Data + } + return value.asData() + } + + fileprivate func fetchFromDiskCache(_ diskCache : DiskCache, key: String, memoryCache : NSCache, failure fail : ((Error?) -> ())?, success succeed : @escaping (T) -> ()) { + diskCache.fetchData(key: key, failure: { error in + if let block = fail { + if (error as NSError?)?.code == NSFileReadNoSuchFileError { + let localizedFormat = NSLocalizedString("Object not found for key %@", comment: "Error description") + let description = String(format:localizedFormat, key) + let error = errorWithCode(HanekeGlobals.Cache.ErrorCode.objectNotFound.rawValue, description: description) + block(error) + } else { + block(error) + } + } + }) { data in + DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async(execute: { + let value = T.convertFromData(data) + if let value = value { + let descompressedValue = self.decompressedImageIfNeeded(value) + DispatchQueue.main.async(execute: { + succeed(descompressedValue) + let wrapper = ObjectWrapper(value: descompressedValue) + memoryCache.setObject(wrapper, forKey: key as AnyObject) + }) + } + }) + } + } + + fileprivate func fetchAndSet(_ fetcher : Fetcher, format : Format, failure fail : ((Error?) -> ())?, success succeed : @escaping (T) -> ()) { + fetcher.fetch(failure: { error in + let _ = fail?(error) + }) { value in + self.set(value: value, key: fetcher.key, formatName: format.name, success: succeed) + } + } + + fileprivate func format(value : T, format : Format, success succeed : @escaping (T) -> ()) { + // HACK: Ideally Cache shouldn't treat images differently but I can't think of any other way of doing this that doesn't complicate the API for other types. + if format.isIdentity && !(value is UIImage) { + succeed(value) + } else { + DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async { + var formatted = format.apply(value) + + if let formattedImage = formatted as? UIImage { + let originalImage = value as? UIImage + if formattedImage === originalImage { + formatted = self.decompressedImageIfNeeded(formatted) + } + } + + DispatchQueue.main.async { + succeed(formatted) + } + } + } + } + + fileprivate func decompressedImageIfNeeded(_ value : T) -> T { + if let image = value as? UIImage { + let decompressedImage = image.hnk_decompressedImage() as? T + return decompressedImage! + } + return value + } + + fileprivate class func buildFetch(failure fail : Fetch.Failer? = nil, success succeed : Fetch.Succeeder? = nil) -> Fetch { + let fetch = Fetch() + if let succeed = succeed { + fetch.onSuccess(succeed) + } + if let fail = fail { + fetch.onFailure(fail) + } + return fetch + } + + // MARK: Convenience fetch + // Ideally we would put each of these in the respective fetcher file as a Cache extension. Unfortunately, this fails to link when using the framework in a project as of Xcode 6.1. + + open func fetch(key: String, value getValue : @autoclosure @escaping () -> T.Result, formatName: String = HanekeGlobals.Cache.OriginalFormatName, success succeed : Fetch.Succeeder? = nil) -> Fetch { + let fetcher = SimpleFetcher(key: key, value: getValue) + return self.fetch(fetcher: fetcher, formatName: formatName, success: succeed) + } + + open func fetch(path: String, formatName: String = HanekeGlobals.Cache.OriginalFormatName, failure fail : Fetch.Failer? = nil, success succeed : Fetch.Succeeder? = nil) -> Fetch { + let fetcher = DiskFetcher(path: path) + return self.fetch(fetcher: fetcher, formatName: formatName, failure: fail, success: succeed) + } + + open func fetch(URL : Foundation.URL, formatName: String = HanekeGlobals.Cache.OriginalFormatName, failure fail : Fetch.Failer? = nil, success succeed : Fetch.Succeeder? = nil) -> Fetch { + let fetcher = NetworkFetcher(URL: URL) + return self.fetch(fetcher: fetcher, formatName: formatName, failure: fail, success: succeed) + } + +} diff --git a/Pods/HanekeSwift/Haneke/CryptoSwiftMD5.swift b/Pods/HanekeSwift/Haneke/CryptoSwiftMD5.swift new file mode 100755 index 0000000..85ccb06 --- /dev/null +++ b/Pods/HanekeSwift/Haneke/CryptoSwiftMD5.swift @@ -0,0 +1,229 @@ +// +// CryptoSwiftMD5.Swif +// +// To date, adding CommonCrypto to a Swift framework is problematic. See: +// http://stackoverflow.com/questions/25248598/importing-commoncrypto-in-a-swift-framework +// We're using a subset of CryptoSwift as a (temporary?) alternative. +// The following is an altered source version that only includes MD5. The original software can be found at: +// https://github.com/krzyzanowskim/CryptoSwift +// This is the original copyright notice: + +/* +Copyright (C) 2014 Marcin Krzyżanowski +This software is provided 'as-is', without any express or implied warranty. + +In no event will the authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + +- The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +- Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +- This notice may not be removed or altered from any source or binary distribution. +*/ + +import Foundation + +/** array of bytes, little-endian representation */ +func arrayOfBytes(value:T, length:Int? = nil) -> [UInt8] { + let totalBytes = length ?? MemoryLayout.size + + let valuePointer = UnsafeMutablePointer.allocate(capacity: 1) + valuePointer.pointee = value + + let bytesPointer = UnsafeMutablePointer(OpaquePointer(valuePointer)) + var bytes = Array(repeating: 0, count: totalBytes) + for j in 0...size,totalBytes) { + bytes[totalBytes - 1 - j] = (bytesPointer + j).pointee + } + + valuePointer.deinitialize() + valuePointer.deallocate(capacity: 1) + + return bytes +} + +extension Int { + /** Array of bytes with optional padding (little-endian) */ + public func bytes(totalBytes: Int = MemoryLayout.size) -> [UInt8] { + return arrayOfBytes(value: self, length: totalBytes) + } + +} + +extension NSMutableData { + + /** Convenient way to append bytes */ + internal func appendBytes(arrayOfBytes: [UInt8]) { + self.append(arrayOfBytes, length: arrayOfBytes.count) + } + +} + +struct BytesSequence: Sequence { + let chunkSize: Int + let data: [UInt8] + + func makeIterator() -> AnyIterator> { + var offset:Int = 0 + return AnyIterator { + let end = Swift.min(self.chunkSize, self.data.count - offset) + let result = self.data[offset.. [UInt8] { + var tmpMessage = message + + // Step 1. Append Padding Bits + tmpMessage.append(0x80) // append one bit (UInt8 with one bit) to message + + // append "0" bit until message length in bits ≡ 448 (mod 512) + var msgLength = tmpMessage.count + var counter = 0 + + while msgLength % len != (len - 8) { + counter += 1 + msgLength += 1 + } + + tmpMessage += Array(repeating: 0, count: counter) + return tmpMessage + } +} + +func rotateLeft(v: UInt32, n: UInt32) -> UInt32 { + return ((v << n) & 0xFFFFFFFF) | (v >> (32 - n)) +} + +func sliceToUInt32Array(_ slice: ArraySlice) -> [UInt32] { + var result = [UInt32]() + result.reserveCapacity(16) + for idx in stride(from: slice.startIndex, to: slice.endIndex, by: MemoryLayout.size) { + let val1:UInt32 = (UInt32(slice[idx.advanced(by: 3)]) << 24) + let val2:UInt32 = (UInt32(slice[idx.advanced(by: 2)]) << 16) + let val3:UInt32 = (UInt32(slice[idx.advanced(by: 1)]) << 8) + let val4:UInt32 = UInt32(slice[idx]) + let val:UInt32 = val1 | val2 | val3 | val4 + result.append(val) + } + return result +} + +class MD5 : HashBase { + + + /** specifies the per-round shift amounts */ + private let s: [UInt32] = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21] + + /** binary integer part of the sines of integers (Radians) */ + private let k: [UInt32] = [0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee, + 0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501, + 0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be, + 0x6b901122,0xfd987193,0xa679438e,0x49b40821, + 0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa, + 0xd62f105d,0x2441453,0xd8a1e681,0xe7d3fbc8, + 0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed, + 0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a, + 0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c, + 0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70, + 0x289b7ec6,0xeaa127fa,0xd4ef3085,0x4881d05, + 0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665, + 0xf4292244,0x432aff97,0xab9423a7,0xfc93a039, + 0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1, + 0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1, + 0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391] + + private let h: [UInt32] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476] + + func calculate() -> [UInt8] { + var tmpMessage = prepare(64) + tmpMessage.reserveCapacity(tmpMessage.count + 4) + + // initialize hh with hash values + var hh = h + + // Step 2. Append Length a 64-bit representation of lengthInBits + let lengthInBits = (message.count * 8) + let lengthBytes = lengthInBits.bytes(totalBytes: 64 / 8) + tmpMessage += lengthBytes.reversed() + + // Process the message in successive 512-bit chunks: + let chunkSizeBytes = 512 / 8 // 64 + for chunk in BytesSequence(chunkSize: chunkSizeBytes, data: tmpMessage) { + // break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15 + var M = sliceToUInt32Array(chunk) + assert(M.count == 16, "Invalid array") + + // Initialize hash value for this chunk: + var A:UInt32 = hh[0] + var B:UInt32 = hh[1] + var C:UInt32 = hh[2] + var D:UInt32 = hh[3] + + var dTemp:UInt32 = 0 + + // Main loop + for j in 0..> 8) & 0xff), UInt8((itemLE >> 16) & 0xff), UInt8((itemLE >> 24) & 0xff)] + } + + return result + } +} diff --git a/Pods/HanekeSwift/Haneke/Data.swift b/Pods/HanekeSwift/Haneke/Data.swift new file mode 100644 index 0000000..33cc542 --- /dev/null +++ b/Pods/HanekeSwift/Haneke/Data.swift @@ -0,0 +1,129 @@ +// +// Data.swift +// Haneke +// +// Created by Hermes Pique on 9/19/14. +// Copyright (c) 2014 Haneke. All rights reserved. +// + +import UIKit + +// See: http://stackoverflow.com/questions/25922152/not-identical-to-self +public protocol DataConvertible { + associatedtype Result + + static func convertFromData(_ data:Data) -> Result? +} + +public protocol DataRepresentable { + + func asData() -> Data! +} + +private let imageSync = NSLock() + +extension UIImage : DataConvertible, DataRepresentable { + + public typealias Result = UIImage + + // HACK: UIImage data initializer is no longer thread safe. See: https://github.com/AFNetworking/AFNetworking/issues/2572#issuecomment-115854482 + static func safeImageWithData(_ data:Data) -> Result? { + imageSync.lock() + let image = UIImage(data:data, scale: scale) + imageSync.unlock() + return image + } + + public class func convertFromData(_ data: Data) -> Result? { + let image = UIImage.safeImageWithData(data) + return image + } + + public func asData() -> Data! { + return self.hnk_data() as Data! + } + + fileprivate static let scale = UIScreen.main.scale + +} + +extension String : DataConvertible, DataRepresentable { + + public typealias Result = String + + public static func convertFromData(_ data: Data) -> Result? { + let string = NSString(data: data, encoding: String.Encoding.utf8.rawValue) + return string as Result? + } + + public func asData() -> Data! { + return self.data(using: String.Encoding.utf8) + } + +} + +extension Data : DataConvertible, DataRepresentable { + + public typealias Result = Data + + public static func convertFromData(_ data: Data) -> Result? { + return data + } + + public func asData() -> Data! { + return self + } + +} + +public enum JSON : DataConvertible, DataRepresentable { + public typealias Result = JSON + + case Dictionary([String:AnyObject]) + case Array([AnyObject]) + + public static func convertFromData(_ data: Data) -> Result? { + do { + let object : Any = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions()) + switch (object) { + case let dictionary as [String:AnyObject]: + return JSON.Dictionary(dictionary) + case let array as [AnyObject]: + return JSON.Array(array) + default: + return nil + } + } catch { + Log.error(message: "Invalid JSON data", error: error) + return nil + } + } + + public func asData() -> Data! { + switch (self) { + case .Dictionary(let dictionary): + return try? JSONSerialization.data(withJSONObject: dictionary, options: JSONSerialization.WritingOptions()) + case .Array(let array): + return try? JSONSerialization.data(withJSONObject: array, options: JSONSerialization.WritingOptions()) + } + } + + public var array : [AnyObject]! { + switch (self) { + case .Dictionary(_): + return nil + case .Array(let array): + return array + } + } + + public var dictionary : [String:AnyObject]! { + switch (self) { + case .Dictionary(let dictionary): + return dictionary + case .Array(_): + return nil + } + } + +} diff --git a/Pods/HanekeSwift/Haneke/DiskCache.swift b/Pods/HanekeSwift/Haneke/DiskCache.swift new file mode 100644 index 0000000..e7cf060 --- /dev/null +++ b/Pods/HanekeSwift/Haneke/DiskCache.swift @@ -0,0 +1,237 @@ +// +// DiskCache.swift +// Haneke +// +// Created by Hermes Pique on 8/10/14. +// Copyright (c) 2014 Haneke. All rights reserved. +// + +import Foundation + +open class DiskCache { + + open class func basePath() -> String { + let cachesPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0] + let hanekePathComponent = HanekeGlobals.Domain + let basePath = (cachesPath as NSString).appendingPathComponent(hanekePathComponent) + // TODO: Do not recaculate basePath value + return basePath + } + + open let path: String + + open var size : UInt64 = 0 + + open var capacity : UInt64 = 0 { + didSet { + self.cacheQueue.async(execute: { + self.controlCapacity() + }) + } + } + + open lazy var cacheQueue : DispatchQueue = { + let queueName = HanekeGlobals.Domain + "." + (self.path as NSString).lastPathComponent + let cacheQueue = DispatchQueue(label: queueName, attributes: []) + return cacheQueue + }() + + public init(path: String, capacity: UInt64 = UINT64_MAX) { + self.path = path + self.capacity = capacity + self.cacheQueue.async(execute: { + self.calculateSize() + self.controlCapacity() + }) + } + + open func setData( _ getData: @autoclosure @escaping () -> Data?, key: String) { + cacheQueue.async(execute: { + if let data = getData() { + self.setDataSync(data, key: key) + } else { + Log.error(message: "Failed to get data for key \(key)") + } + }) + } + + open func fetchData(key: String, failure fail: ((Error?) -> ())? = nil, success succeed: @escaping (Data) -> ()) { + cacheQueue.async { + let path = self.path(forKey: key) + do { + let data = try Data(contentsOf: URL(fileURLWithPath: path), options: Data.ReadingOptions()) + DispatchQueue.main.async { + succeed(data) + } + self.updateDiskAccessDate(atPath: path) + } catch { + if let block = fail { + DispatchQueue.main.async { + block(error) + } + } + } + } + } + + open func removeData(with key: String) { + cacheQueue.async(execute: { + let path = self.path(forKey: key) + self.removeFile(atPath: path) + }) + } + + open func removeAllData(_ completion: (() -> ())? = nil) { + let fileManager = FileManager.default + let cachePath = self.path + cacheQueue.async(execute: { + do { + let contents = try fileManager.contentsOfDirectory(atPath: cachePath) + for pathComponent in contents { + let path = (cachePath as NSString).appendingPathComponent(pathComponent) + do { + try fileManager.removeItem(atPath: path) + } catch { + Log.error(message: "Failed to remove path \(path)", error: error) + } + } + self.calculateSize() + } catch { + Log.error(message: "Failed to list directory", error: error) + } + if let completion = completion { + DispatchQueue.main.async { + completion() + } + } + }) + } + + open func updateAccessDate( _ getData: @autoclosure @escaping () -> Data?, key: String) { + cacheQueue.async(execute: { + let path = self.path(forKey: key) + let fileManager = FileManager.default + if (!(fileManager.fileExists(atPath: path) && self.updateDiskAccessDate(atPath: path))){ + if let data = getData() { + self.setDataSync(data, key: key) + } else { + Log.error(message: "Failed to get data for key \(key)") + } + } + }) + } + + open func path(forKey key: String) -> String { + let escapedFilename = key.escapedFilename() + let filename = escapedFilename.characters.count < Int(NAME_MAX) ? escapedFilename : key.MD5Filename() + let keyPath = (self.path as NSString).appendingPathComponent(filename) + return keyPath + } + + // MARK: Private + + fileprivate func calculateSize() { + let fileManager = FileManager.default + size = 0 + let cachePath = self.path + do { + let contents = try fileManager.contentsOfDirectory(atPath: cachePath) + for pathComponent in contents { + let path = (cachePath as NSString).appendingPathComponent(pathComponent) + do { + let attributes: [FileAttributeKey: Any] = try fileManager.attributesOfItem(atPath: path) + if let fileSize = attributes[FileAttributeKey.size] as? UInt64 { + size += fileSize + } + } catch { + Log.error(message: "Failed to list directory", error: error) + } + } + + } catch { + Log.error(message: "Failed to list directory", error: error) + } + } + + fileprivate func controlCapacity() { + if self.size <= self.capacity { return } + + let fileManager = FileManager.default + let cachePath = self.path + fileManager.enumerateContentsOfDirectory(atPath: cachePath, orderedByProperty: URLResourceKey.contentModificationDateKey.rawValue, ascending: true) { (URL : URL, _, stop : inout Bool) -> Void in + + self.removeFile(atPath: URL.path) + + stop = self.size <= self.capacity + } + } + + fileprivate func setDataSync(_ data: Data, key: String) { + let path = self.path(forKey: key) + let fileManager = FileManager.default + let previousAttributes : [FileAttributeKey: Any]? = try? fileManager.attributesOfItem(atPath: path) + + do { + try data.write(to: URL(fileURLWithPath: path), options: Data.WritingOptions.atomicWrite) + } catch { + Log.error(message: "Failed to write key \(key)", error: error) + } + + if let attributes = previousAttributes { + if let fileSize = attributes[FileAttributeKey.size] as? UInt64 { + substract(size: fileSize) + } + } + self.size += UInt64(data.count) + self.controlCapacity() + } + + @discardableResult fileprivate func updateDiskAccessDate(atPath path: String) -> Bool { + let fileManager = FileManager.default + let now = Date() + do { + try fileManager.setAttributes([FileAttributeKey.modificationDate : now], ofItemAtPath: path) + return true + } catch { + Log.error(message: "Failed to update access date", error: error) + return false + } + } + + fileprivate func removeFile(atPath path: String) { + let fileManager = FileManager.default + do { + let attributes: [FileAttributeKey: Any] = try fileManager.attributesOfItem(atPath: path) + do { + try fileManager.removeItem(atPath: path) + if let fileSize = attributes[FileAttributeKey.size] as? UInt64 { + substract(size: fileSize) + } + } catch { + Log.error(message: "Failed to remove file", error: error) + } + } catch { + if isNoSuchFileError(error) { + Log.debug(message: "File not found", error: error) + } else { + Log.error(message: "Failed to remove file", error: error) + } + } + } + + fileprivate func substract(size : UInt64) { + if (self.size >= size) { + self.size -= size + } else { + Log.error(message: "Disk cache size (\(self.size)) is smaller than size to substract (\(size))") + self.size = 0 + } + } +} + +private func isNoSuchFileError(_ error : Error?) -> Bool { + if let error = error { + return NSCocoaErrorDomain == (error as NSError).domain && (error as NSError).code == NSFileReadNoSuchFileError + } + return false +} diff --git a/Pods/HanekeSwift/Haneke/DiskFetcher.swift b/Pods/HanekeSwift/Haneke/DiskFetcher.swift new file mode 100644 index 0000000..a034f0e --- /dev/null +++ b/Pods/HanekeSwift/Haneke/DiskFetcher.swift @@ -0,0 +1,92 @@ +// +// DiskFetcher.swift +// Haneke +// +// Created by Joan Romano on 9/16/14. +// Copyright (c) 2014 Haneke. All rights reserved. +// + +import Foundation + +extension HanekeGlobals { + + // It'd be better to define this in the DiskFetcher class but Swift doesn't allow to declare an enum in a generic type + public struct DiskFetcher { + + public enum ErrorCode : Int { + case invalidData = -500 + } + + } + +} + +open class DiskFetcher : Fetcher { + + let path: String + var cancelled = false + + public init(path: String) { + self.path = path + let key = path + super.init(key: key) + } + + // MARK: Fetcher + + + open override func fetch(failure fail: @escaping ((Error?) -> ()), success succeed: @escaping (T.Result) -> ()) { + self.cancelled = false + DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async(execute: { [weak self] in + if let strongSelf = self { + strongSelf.privateFetch(failure: fail, success: succeed) + } + }) + } + + open override func cancelFetch() { + self.cancelled = true + } + + // MARK: Private + + fileprivate func privateFetch(failure fail: @escaping ((Error?) -> ()), success succeed: @escaping (T.Result) -> ()) { + if self.cancelled { + return + } + + let data : Data + do { + data = try Data(contentsOf: URL(fileURLWithPath: self.path), options: Data.ReadingOptions()) + } catch { + DispatchQueue.main.async { + if self.cancelled { + return + } + fail(error) + } + return + } + + if self.cancelled { + return + } + + guard let value : T.Result = T.convertFromData(data) else { + let localizedFormat = NSLocalizedString("Failed to convert value from data at path %@", comment: "Error description") + let description = String(format:localizedFormat, self.path) + let error = errorWithCode(HanekeGlobals.DiskFetcher.ErrorCode.invalidData.rawValue, description: description) + DispatchQueue.main.async { + fail(error) + } + return + } + + DispatchQueue.main.async(execute: { + if self.cancelled { + return + } + succeed(value) + }) + } +} diff --git a/Pods/HanekeSwift/Haneke/Fetch.swift b/Pods/HanekeSwift/Haneke/Fetch.swift new file mode 100644 index 0000000..75f3fa5 --- /dev/null +++ b/Pods/HanekeSwift/Haneke/Fetch.swift @@ -0,0 +1,89 @@ +// +// Fetch.swift +// Haneke +// +// Created by Hermes Pique on 9/28/14. +// Copyright (c) 2014 Haneke. All rights reserved. +// + +import Foundation + +enum FetchState { + case pending + // Using Wrapper as a workaround for error 'unimplemented IR generation feature non-fixed multi-payload enum layout' + // See: http://swiftradar.tumblr.com/post/88314603360/swift-fails-to-compile-enum-with-two-data-cases + // See: http://owensd.io/2014/08/06/fixed-enum-layout.html + case success(Wrapper) + case failure(Error?) +} + +open class Fetch { + + public typealias Succeeder = (T) -> () + + public typealias Failer = (Error?) -> () + + fileprivate var onSuccess : Succeeder? + + fileprivate var onFailure : Failer? + + fileprivate var state : FetchState = FetchState.pending + + public init() {} + + @discardableResult open func onSuccess(_ onSuccess: @escaping Succeeder) -> Self { + self.onSuccess = onSuccess + switch self.state { + case FetchState.success(let wrapper): + onSuccess(wrapper.value) + default: + break + } + return self + } + + @discardableResult open func onFailure(_ onFailure: @escaping Failer) -> Self { + self.onFailure = onFailure + switch self.state { + case FetchState.failure(let error): + onFailure(error) + default: + break + } + return self + } + + func succeed(_ value: T) { + self.state = FetchState.success(Wrapper(value)) + self.onSuccess?(value) + } + + func fail(_ error: Error? = nil) { + self.state = FetchState.failure(error) + self.onFailure?(error) + } + + var hasFailed : Bool { + switch self.state { + case FetchState.failure(_): + return true + default: + return false + } + } + + var hasSucceeded : Bool { + switch self.state { + case FetchState.success(_): + return true + default: + return false + } + } + +} + +open class Wrapper { + open let value: T + public init(_ value: T) { self.value = value } +} diff --git a/Pods/HanekeSwift/Haneke/Fetcher.swift b/Pods/HanekeSwift/Haneke/Fetcher.swift new file mode 100644 index 0000000..1c044c7 --- /dev/null +++ b/Pods/HanekeSwift/Haneke/Fetcher.swift @@ -0,0 +1,41 @@ +// +// Fetcher.swift +// Haneke +// +// Created by Hermes Pique on 9/9/14. +// Copyright (c) 2014 Haneke. All rights reserved. +// + +import UIKit + +// See: http://stackoverflow.com/questions/25915306/generic-closure-in-protocol +open class Fetcher { + + open let key: String + + public init(key: String) { + self.key = key + } + + open func fetch(failure fail: @escaping ((Error?) -> ()), success succeed: @escaping (T.Result) -> ()) {} + + open func cancelFetch() {} +} + +class SimpleFetcher : Fetcher { + + let getValue : () -> T.Result + + init(key: String, value getValue : @autoclosure @escaping () -> T.Result) { + self.getValue = getValue + super.init(key: key) + } + + override func fetch(failure fail: @escaping ((Error?) -> ()), success succeed: @escaping (T.Result) -> ()) { + let value = getValue() + succeed(value) + } + + override func cancelFetch() {} + +} diff --git a/Pods/HanekeSwift/Haneke/Format.swift b/Pods/HanekeSwift/Haneke/Format.swift new file mode 100644 index 0000000..7350b44 --- /dev/null +++ b/Pods/HanekeSwift/Haneke/Format.swift @@ -0,0 +1,93 @@ +// +// Format.swift +// Haneke +// +// Created by Hermes Pique on 8/27/14. +// Copyright (c) 2014 Haneke. All rights reserved. +// + +import UIKit + +public struct Format { + + public let name: String + + public let diskCapacity : UInt64 + + public var transform : ((T) -> (T))? + + public var convertToData : ((T) -> Data)? + + public init(name: String, diskCapacity : UInt64 = UINT64_MAX, transform: ((T) -> (T))? = nil) { + self.name = name + self.diskCapacity = diskCapacity + self.transform = transform + } + + public func apply(_ value : T) -> T { + var transformed = value + if let transform = self.transform { + transformed = transform(value) + } + return transformed + } + + var isIdentity : Bool { + return self.transform == nil + } + +} + +public struct ImageResizer { + + public enum ScaleMode: String { + case Fill = "fill", AspectFit = "aspectfit", AspectFill = "aspectfill", None = "none" + } + + public typealias T = UIImage + + public let allowUpscaling : Bool + + public let size : CGSize + + public let scaleMode: ScaleMode + + public let compressionQuality : Float + + public init(size: CGSize = CGSize.zero, scaleMode: ScaleMode = .None, allowUpscaling: Bool = true, compressionQuality: Float = 1.0) { + self.size = size + self.scaleMode = scaleMode + self.allowUpscaling = allowUpscaling + self.compressionQuality = compressionQuality + } + + public func resizeImage(_ image: UIImage) -> UIImage { + var resizeToSize: CGSize + switch self.scaleMode { + case .Fill: + resizeToSize = self.size + case .AspectFit: + resizeToSize = image.size.hnk_aspectFitSize(self.size) + case .AspectFill: + resizeToSize = image.size.hnk_aspectFillSize(self.size) + case .None: + return image + } + assert(self.size.width > 0 && self.size.height > 0, "Expected non-zero size. Use ScaleMode.None to avoid resizing.") + + // If does not allow to scale up the image + if (!self.allowUpscaling) { + if (resizeToSize.width > image.size.width || resizeToSize.height > image.size.height) { + return image + } + } + + // Avoid unnecessary computations + if (resizeToSize.width == image.size.width && resizeToSize.height == image.size.height) { + return image + } + + let resizedImage = image.hnk_imageByScaling(toSize: resizeToSize) + return resizedImage + } +} diff --git a/Pods/HanekeSwift/Haneke/Haneke.swift b/Pods/HanekeSwift/Haneke/Haneke.swift new file mode 100644 index 0000000..c5b63f7 --- /dev/null +++ b/Pods/HanekeSwift/Haneke/Haneke.swift @@ -0,0 +1,55 @@ +// +// Haneke.swift +// Haneke +// +// Created by Hermes Pique on 9/9/14. +// Copyright (c) 2014 Haneke. All rights reserved. +// + +import UIKit + +public struct HanekeGlobals { + + public static let Domain = "io.haneke" + +} + +public struct Shared { + + public static var imageCache : Cache { + struct Static { + static let name = "shared-images" + static let cache = Cache(name: name) + } + return Static.cache + } + + public static var dataCache : Cache { + struct Static { + static let name = "shared-data" + static let cache = Cache(name: name) + } + return Static.cache + } + + public static var stringCache : Cache { + struct Static { + static let name = "shared-strings" + static let cache = Cache(name: name) + } + return Static.cache + } + + public static var JSONCache : Cache { + struct Static { + static let name = "shared-json" + static let cache = Cache(name: name) + } + return Static.cache + } +} + +func errorWithCode(_ code: Int, description: String) -> Error { + let userInfo = [NSLocalizedDescriptionKey: description] + return NSError(domain: HanekeGlobals.Domain, code: code, userInfo: userInfo) as Error +} diff --git a/Pods/HanekeSwift/Haneke/Log.swift b/Pods/HanekeSwift/Haneke/Log.swift new file mode 100644 index 0000000..b05868a --- /dev/null +++ b/Pods/HanekeSwift/Haneke/Log.swift @@ -0,0 +1,38 @@ +// +// Log.swift +// Haneke +// +// Created by Hermes Pique on 11/10/14. +// Copyright (c) 2014 Haneke. All rights reserved. +// + +import Foundation + +struct Log { + + fileprivate static let Tag = "[HANEKE]" + + fileprivate enum Level : String { + case Debug = "[DEBUG]" + case Error = "[ERROR]" + } + + fileprivate static func log(_ level: Level, _ message: @autoclosure () -> String, _ error: Error? = nil) { + if let error = error { + print("\(Tag)\(level.rawValue) \(message()) with error \(error)") + } else { + print("\(Tag)\(level.rawValue) \(message())") + } + } + + static func debug(message: @autoclosure () -> String, error: Error? = nil) { + #if DEBUG + log(.Debug, message, error) + #endif + } + + static func error(message: @autoclosure () -> String, error: Error? = nil) { + log(.Error, message, error) + } + +} diff --git a/Pods/HanekeSwift/Haneke/NSFileManager+Haneke.swift b/Pods/HanekeSwift/Haneke/NSFileManager+Haneke.swift new file mode 100644 index 0000000..8958e2f --- /dev/null +++ b/Pods/HanekeSwift/Haneke/NSFileManager+Haneke.swift @@ -0,0 +1,65 @@ +// +// NSFileManager+Haneke.swift +// Haneke +// +// Created by Hermes Pique on 8/26/14. +// Copyright (c) 2014 Haneke. All rights reserved. +// + +import Foundation + +extension FileManager { + + func enumerateContentsOfDirectory(atPath path: String, orderedByProperty property: String, ascending: Bool, usingBlock block: (URL, Int, inout Bool) -> Void ) { + + let directoryURL = URL(fileURLWithPath: path) + do { + let contents = try self.contentsOfDirectory(at: directoryURL, includingPropertiesForKeys: [URLResourceKey(rawValue: property)], options: FileManager.DirectoryEnumerationOptions()) + let sortedContents = contents.sorted(by: {(URL1: URL, URL2: URL) -> Bool in + + // Maybe there's a better way to do this. See: http://stackoverflow.com/questions/25502914/comparing-anyobject-in-swift + + var value1 : AnyObject? + do { + try (URL1 as NSURL).getResourceValue(&value1, forKey: URLResourceKey(rawValue: property)) + } catch { + return true + } + var value2 : AnyObject? + do { + try (URL2 as NSURL).getResourceValue(&value2, forKey: URLResourceKey(rawValue: property)) + } catch { + return false + } + + if let string1 = value1 as? String, let string2 = value2 as? String { + return ascending ? string1 < string2 : string2 < string1 + } + + if let date1 = value1 as? Date, let date2 = value2 as? Date { + return ascending ? date1 < date2 : date2 < date1 + } + + if let number1 = value1 as? NSNumber, let number2 = value2 as? NSNumber { + return ascending ? number1 < number2 : number2 < number1 + } + + return false + }) + + for (i, v) in sortedContents.enumerated() { + var stop : Bool = false + block(v, i, &stop) + if stop { break } + } + + } catch { + Log.error(message: "Failed to list directory", error: error) + } + } + +} + +func < (lhs: NSNumber, rhs: NSNumber) -> Bool { + return lhs.compare(rhs) == ComparisonResult.orderedAscending +} diff --git a/Pods/HanekeSwift/Haneke/NSHTTPURLResponse+Haneke.swift b/Pods/HanekeSwift/Haneke/NSHTTPURLResponse+Haneke.swift new file mode 100644 index 0000000..d38ac9d --- /dev/null +++ b/Pods/HanekeSwift/Haneke/NSHTTPURLResponse+Haneke.swift @@ -0,0 +1,22 @@ +// +// NSHTTPURLResponse+Haneke.swift +// Haneke +// +// Created by Hermes Pique on 1/2/16. +// Copyright © 2016 Haneke. All rights reserved. +// + +import Foundation + +extension HTTPURLResponse { + + func hnk_isValidStatusCode() -> Bool { + switch self.statusCode { + case 200...201: + return true + default: + return false + } + } + +} diff --git a/Pods/HanekeSwift/Haneke/NSURLResponse+Haneke.swift b/Pods/HanekeSwift/Haneke/NSURLResponse+Haneke.swift new file mode 100644 index 0000000..9a470ad --- /dev/null +++ b/Pods/HanekeSwift/Haneke/NSURLResponse+Haneke.swift @@ -0,0 +1,22 @@ +// +// NSHTTPURLResponse+Haneke.swift +// Haneke +// +// Created by Hermes Pique on 9/12/14. +// Copyright (c) 2014 Haneke. All rights reserved. +// + +import Foundation + +extension URLResponse { + + func hnk_validateLength(ofData data: Data) -> Bool { + let expectedContentLength = self.expectedContentLength + if (expectedContentLength > -1) { + let dataLength = data.count + return Int64(dataLength) >= expectedContentLength + } + return true + } + +} diff --git a/Pods/HanekeSwift/Haneke/NetworkFetcher.swift b/Pods/HanekeSwift/Haneke/NetworkFetcher.swift new file mode 100644 index 0000000..2f50c84 --- /dev/null +++ b/Pods/HanekeSwift/Haneke/NetworkFetcher.swift @@ -0,0 +1,105 @@ +// +// NetworkFetcher.swift +// Haneke +// +// Created by Hermes Pique on 9/12/14. +// Copyright (c) 2014 Haneke. All rights reserved. +// + +import UIKit + +extension HanekeGlobals { + + // It'd be better to define this in the NetworkFetcher class but Swift doesn't allow to declare an enum in a generic type + public struct NetworkFetcher { + + public enum ErrorCode : Int { + case invalidData = -400 + case missingData = -401 + case invalidStatusCode = -402 + } + + } + +} + +open class NetworkFetcher : Fetcher { + + let URL : Foundation.URL + + public init(URL : Foundation.URL) { + self.URL = URL + + let key = URL.absoluteString + super.init(key: key) + } + + open var session : URLSession { return URLSession.shared } + + var task : URLSessionDataTask? = nil + + var cancelled = false + + // MARK: Fetcher + + open override func fetch(failure fail: @escaping ((Error?) -> ()), success succeed: @escaping (T.Result) -> ()) { + self.cancelled = false + self.task = self.session.dataTask(with: self.URL) {[weak self] (data, response, error) -> Void in + if let strongSelf = self { + strongSelf.onReceive(data: data, response: response, error: error, failure: fail, success: succeed) + } + } + self.task?.resume() + } + + open override func cancelFetch() { + self.task?.cancel() + self.cancelled = true + } + + // MARK: Private + + fileprivate func onReceive(data: Data!, response: URLResponse!, error: Error!, failure fail: @escaping ((Error?) -> ()), success succeed: @escaping (T.Result) -> ()) { + + if cancelled { return } + + let URL = self.URL + + if let error = error { + if ((error as NSError).domain == NSURLErrorDomain && (error as NSError).code == NSURLErrorCancelled) { return } + + Log.debug(message: "Request \(URL.absoluteString) failed", error: error) + DispatchQueue.main.async(execute: { fail(error) }) + return + } + + if let httpResponse = response as? HTTPURLResponse , !httpResponse.hnk_isValidStatusCode() { + let description = HTTPURLResponse.localizedString(forStatusCode: httpResponse.statusCode) + self.failWithCode(.invalidStatusCode, localizedDescription: description, failure: fail) + return + } + + if !response.hnk_validateLength(ofData: data) { + let localizedFormat = NSLocalizedString("Request expected %ld bytes and received %ld bytes", comment: "Error description") + let description = String(format:localizedFormat, response.expectedContentLength, data.count) + self.failWithCode(.missingData, localizedDescription: description, failure: fail) + return + } + + guard let value = T.convertFromData(data) else { + let localizedFormat = NSLocalizedString("Failed to convert value from data at URL %@", comment: "Error description") + let description = String(format:localizedFormat, URL.absoluteString) + self.failWithCode(.invalidData, localizedDescription: description, failure: fail) + return + } + + DispatchQueue.main.async { succeed(value) } + + } + + fileprivate func failWithCode(_ code: HanekeGlobals.NetworkFetcher.ErrorCode, localizedDescription: String, failure fail: @escaping ((Error?) -> ())) { + let error = errorWithCode(code.rawValue, description: localizedDescription) + Log.debug(message: localizedDescription, error: error) + DispatchQueue.main.async { fail(error) } + } +} diff --git a/Pods/HanekeSwift/Haneke/String+Haneke.swift b/Pods/HanekeSwift/Haneke/String+Haneke.swift new file mode 100644 index 0000000..8b7ee21 --- /dev/null +++ b/Pods/HanekeSwift/Haneke/String+Haneke.swift @@ -0,0 +1,49 @@ +// +// String+Haneke.swift +// Haneke +// +// Created by Hermes Pique on 8/30/14. +// Copyright (c) 2014 Haneke. All rights reserved. +// + +import Foundation + +extension String { + + func escapedFilename() -> String { + return [ "\0":"%00", ":":"%3A", "/":"%2F" ] + .reduce(self.components(separatedBy: "%").joined(separator: "%25")) { + str, m in str.components(separatedBy: m.0).joined(separator: m.1) + } + } + + func MD5String() -> String { + guard let data = self.data(using: String.Encoding.utf8) else { + return self + } + + let MD5Calculator = MD5(Array(data)) + let MD5Data = MD5Calculator.calculate() + let resultBytes = UnsafeMutablePointer(mutating: MD5Data) + let resultEnumerator = UnsafeBufferPointer(start: resultBytes, count: MD5Data.count) + let MD5String = NSMutableString() + for c in resultEnumerator { + MD5String.appendFormat("%02x", c) + } + return MD5String as String + } + + func MD5Filename() -> String { + let MD5String = self.MD5String() + + // NSString.pathExtension alone could return a query string, which can lead to very long filenames. + let pathExtension = URL(string: self)?.pathExtension ?? (self as NSString).pathExtension + + if pathExtension.characters.count > 0 { + return (MD5String as NSString).appendingPathExtension(pathExtension) ?? MD5String + } else { + return MD5String + } + } + +} diff --git a/Pods/HanekeSwift/Haneke/UIButton+Haneke.swift b/Pods/HanekeSwift/Haneke/UIButton+Haneke.swift new file mode 100644 index 0000000..faa3167 --- /dev/null +++ b/Pods/HanekeSwift/Haneke/UIButton+Haneke.swift @@ -0,0 +1,234 @@ +// +// UIButton+Haneke.swift +// Haneke +// +// Created by Joan Romano on 10/1/14. +// Copyright (c) 2014 Haneke. All rights reserved. +// + +import UIKit + +public extension UIButton { + + public var hnk_imageFormat : Format { + let bounds = self.bounds + assert(bounds.size.width > 0 && bounds.size.height > 0, "[\(Mirror(reflecting: self).description) \(#function)]: UIButton size is zero. Set its frame, call sizeToFit or force layout first. You can also set a custom format with a defined size if you don't want to force layout.") + let contentRect = self.contentRect(forBounds: bounds) + let imageInsets = self.imageEdgeInsets + let scaleMode = self.contentHorizontalAlignment != UIControlContentHorizontalAlignment.fill || self.contentVerticalAlignment != UIControlContentVerticalAlignment.fill ? ImageResizer.ScaleMode.AspectFit : ImageResizer.ScaleMode.Fill + let imageSize = CGSize(width: contentRect.width - imageInsets.left - imageInsets.right, height: contentRect.height - imageInsets.top - imageInsets.bottom) + + return HanekeGlobals.UIKit.formatWithSize(imageSize, scaleMode: scaleMode, allowUpscaling: scaleMode == ImageResizer.ScaleMode.AspectFit ? false : true) + } + + public func hnk_setImageFromURL(_ URL: Foundation.URL, state: UIControlState = .normal, placeholder: UIImage? = nil, format: Format? = nil, failure fail: ((Error?) -> ())? = nil, success succeed: ((UIImage) -> ())? = nil) { + let fetcher = NetworkFetcher(URL: URL) + self.hnk_setImageFromFetcher(fetcher, state: state, placeholder: placeholder, format: format, failure: fail, success: succeed) + } + + public func hnk_setImage(_ image: UIImage, key: String, state: UIControlState = .normal, placeholder: UIImage? = nil, format: Format? = nil, success succeed: ((UIImage) -> ())? = nil) { + let fetcher = SimpleFetcher(key: key, value: image) + self.hnk_setImageFromFetcher(fetcher, state: state, placeholder: placeholder, format: format, success: succeed) + } + + public func hnk_setImageFromFile(_ path: String, state: UIControlState = .normal, placeholder: UIImage? = nil, format: Format? = nil, failure fail: ((Error?) -> ())? = nil, success succeed: ((UIImage) -> ())? = nil) { + let fetcher = DiskFetcher(path: path) + self.hnk_setImageFromFetcher(fetcher, state: state, placeholder: placeholder, format: format, failure: fail, success: succeed) + } + + public func hnk_setImageFromFetcher(_ fetcher: Fetcher, state: UIControlState = .normal, placeholder: UIImage? = nil, format: Format? = nil, failure fail: ((Error?) -> ())? = nil, success succeed: ((UIImage) -> ())? = nil){ + self.hnk_cancelSetImage() + self.hnk_imageFetcher = fetcher + + let didSetImage = self.hnk_fetchImageForFetcher(fetcher, state: state, format : format, failure: fail, success: succeed) + + if didSetImage { return } + + if let placeholder = placeholder { + self.setImage(placeholder, for: state) + } + } + + public func hnk_cancelSetImage() { + if let fetcher = self.hnk_imageFetcher { + fetcher.cancelFetch() + self.hnk_imageFetcher = nil + } + } + + // MARK: Internal Image + + // See: http://stackoverflow.com/questions/25907421/associating-swift-things-with-nsobject-instances + var hnk_imageFetcher : Fetcher! { + get { + let wrapper = objc_getAssociatedObject(self, &HanekeGlobals.UIKit.SetImageFetcherKey) as? ObjectWrapper + let fetcher = wrapper?.hnk_value as? Fetcher + return fetcher + } + set (fetcher) { + var wrapper : ObjectWrapper? + if let fetcher = fetcher { + wrapper = ObjectWrapper(value: fetcher) + } + objc_setAssociatedObject(self, &HanekeGlobals.UIKit.SetImageFetcherKey, wrapper, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + + func hnk_fetchImageForFetcher(_ fetcher : Fetcher, state : UIControlState = .normal, format : Format? = nil, failure fail : ((Error?) -> ())?, success succeed : ((UIImage) -> ())?) -> Bool { + let format = format ?? self.hnk_imageFormat + let cache = Shared.imageCache + if cache.formats[format.name] == nil { + cache.addFormat(format) + } + var animated = false + let fetch = cache.fetch(fetcher: fetcher, formatName: format.name, failure: {[weak self] error in + if let strongSelf = self { + if strongSelf.hnk_shouldCancelImageForKey(fetcher.key) { return } + + strongSelf.hnk_imageFetcher = nil + + fail?(error) + } + }) { [weak self] image in + if let strongSelf = self { + if strongSelf.hnk_shouldCancelImageForKey(fetcher.key) { return } + + strongSelf.hnk_setImage(image, state: state, animated: animated, success: succeed) + } + } + animated = true + return fetch.hasSucceeded + } + + + func hnk_setImage(_ image : UIImage, state : UIControlState, animated : Bool, success succeed : ((UIImage) -> ())?) { + self.hnk_imageFetcher = nil + + if let succeed = succeed { + succeed(image) + } else if animated { + UIView.transition(with: self, duration: HanekeGlobals.UIKit.SetImageAnimationDuration, options: .transitionCrossDissolve, animations: { + self.setImage(image, for: state) + }, completion: nil) + } else { + self.setImage(image, for: state) + } + } + + func hnk_shouldCancelImageForKey(_ key:String) -> Bool { + if self.hnk_imageFetcher?.key == key { return false } + + Log.debug(message: "Cancelled set image for \((key as NSString).lastPathComponent)") + return true + } + + // MARK: Background image + + public var hnk_backgroundImageFormat : Format { + let bounds = self.bounds + assert(bounds.size.width > 0 && bounds.size.height > 0, "[\(Mirror(reflecting: self).description) \(#function)]: UIButton size is zero. Set its frame, call sizeToFit or force layout first. You can also set a custom format with a defined size if you don't want to force layout.") + let imageSize = self.backgroundRect(forBounds: bounds).size + + return HanekeGlobals.UIKit.formatWithSize(imageSize, scaleMode: .Fill) + } + + public func hnk_setBackgroundImageFromURL(_ URL : Foundation.URL, state : UIControlState = .normal, placeholder : UIImage? = nil, format : Format? = nil, failure fail : ((Error?) -> ())? = nil, success succeed : ((UIImage) -> ())? = nil) { + let fetcher = NetworkFetcher(URL: URL) + self.hnk_setBackgroundImageFromFetcher(fetcher, state: state, placeholder: placeholder, format: format, failure: fail, success: succeed) + } + + public func hnk_setBackgroundImage(_ image : UIImage, key: String, state : UIControlState = .normal, placeholder : UIImage? = nil, format : Format? = nil, success succeed : ((UIImage) -> ())? = nil) { + let fetcher = SimpleFetcher(key: key, value: image) + self.hnk_setBackgroundImageFromFetcher(fetcher, state: state, placeholder: placeholder, format: format, success: succeed) + } + + public func hnk_setBackgroundImageFromFile(_ path: String, state : UIControlState = .normal, placeholder : UIImage? = nil, format : Format? = nil, failure fail : ((Error?) -> ())? = nil, success succeed : ((UIImage) -> ())? = nil) { + let fetcher = DiskFetcher(path: path) + self.hnk_setBackgroundImageFromFetcher(fetcher, state: state, placeholder: placeholder, format: format, failure: fail, success: succeed) + } + + public func hnk_setBackgroundImageFromFetcher(_ fetcher : Fetcher, state : UIControlState = .normal, placeholder : UIImage? = nil, format : Format? = nil, failure fail : ((Error?) -> ())? = nil, success succeed : ((UIImage) -> ())? = nil) { + self.hnk_cancelSetBackgroundImage() + self.hnk_backgroundImageFetcher = fetcher + + let didSetImage = self.hnk_fetchBackgroundImageForFetcher(fetcher, state: state, format : format, failure: fail, success: succeed) + + if didSetImage { return } + + if let placeholder = placeholder { + self.setBackgroundImage(placeholder, for: state) + } + } + + public func hnk_cancelSetBackgroundImage() { + if let fetcher = self.hnk_backgroundImageFetcher { + fetcher.cancelFetch() + self.hnk_backgroundImageFetcher = nil + } + } + + // MARK: Internal Background image + + // See: http://stackoverflow.com/questions/25907421/associating-swift-things-with-nsobject-instances + var hnk_backgroundImageFetcher : Fetcher! { + get { + let wrapper = objc_getAssociatedObject(self, &HanekeGlobals.UIKit.SetBackgroundImageFetcherKey) as? ObjectWrapper + let fetcher = wrapper?.hnk_value as? Fetcher + return fetcher + } + set (fetcher) { + var wrapper : ObjectWrapper? + if let fetcher = fetcher { + wrapper = ObjectWrapper(value: fetcher) + } + objc_setAssociatedObject(self, &HanekeGlobals.UIKit.SetBackgroundImageFetcherKey, wrapper, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + + func hnk_fetchBackgroundImageForFetcher(_ fetcher: Fetcher, state: UIControlState = .normal, format: Format? = nil, failure fail: ((Error?) -> ())?, success succeed : ((UIImage) -> ())?) -> Bool { + let format = format ?? self.hnk_backgroundImageFormat + let cache = Shared.imageCache + if cache.formats[format.name] == nil { + cache.addFormat(format) + } + var animated = false + let fetch = cache.fetch(fetcher: fetcher, formatName: format.name, failure: {[weak self] error in + if let strongSelf = self { + if strongSelf.hnk_shouldCancelBackgroundImageForKey(fetcher.key) { return } + + strongSelf.hnk_backgroundImageFetcher = nil + + fail?(error) + } + }) { [weak self] image in + if let strongSelf = self { + if strongSelf.hnk_shouldCancelBackgroundImageForKey(fetcher.key) { return } + + strongSelf.hnk_setBackgroundImage(image, state: state, animated: animated, success: succeed) + } + } + animated = true + return fetch.hasSucceeded + } + + func hnk_setBackgroundImage(_ image: UIImage, state: UIControlState, animated: Bool, success succeed: ((UIImage) -> ())?) { + self.hnk_backgroundImageFetcher = nil + + if let succeed = succeed { + succeed(image) + } else if animated { + UIView.transition(with: self, duration: HanekeGlobals.UIKit.SetImageAnimationDuration, options: .transitionCrossDissolve, animations: { + self.setBackgroundImage(image, for: state) + }, completion: nil) + } else { + self.setBackgroundImage(image, for: state) + } + } + + func hnk_shouldCancelBackgroundImageForKey(_ key: String) -> Bool { + if self.hnk_backgroundImageFetcher?.key == key { return false } + + Log.debug(message: "Cancelled set background image for \((key as NSString).lastPathComponent)") + return true + } +} diff --git a/Pods/HanekeSwift/Haneke/UIImage+Haneke.swift b/Pods/HanekeSwift/Haneke/UIImage+Haneke.swift new file mode 100644 index 0000000..93cdf7e --- /dev/null +++ b/Pods/HanekeSwift/Haneke/UIImage+Haneke.swift @@ -0,0 +1,81 @@ +// +// UIImage+Haneke.swift +// Haneke +// +// Created by Hermes Pique on 8/10/14. +// Copyright (c) 2014 Haneke. All rights reserved. +// + +import UIKit + +extension UIImage { + + func hnk_imageByScaling(toSize size: CGSize) -> UIImage { + UIGraphicsBeginImageContextWithOptions(size, !hnk_hasAlpha(), 0.0) + draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height)) + let resizedImage = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + return resizedImage! + } + + func hnk_hasAlpha() -> Bool { + guard let alphaInfo = self.cgImage?.alphaInfo else { return false } + switch alphaInfo { + case .first, .last, .premultipliedFirst, .premultipliedLast, .alphaOnly: + return true + case .none, .noneSkipFirst, .noneSkipLast: + return false + } + } + + func hnk_data(compressionQuality: Float = 1.0) -> Data! { + let hasAlpha = self.hnk_hasAlpha() + let data = hasAlpha ? UIImagePNGRepresentation(self) : UIImageJPEGRepresentation(self, CGFloat(compressionQuality)) + return data + } + + func hnk_decompressedImage() -> UIImage! { + let originalImageRef = self.cgImage + let originalBitmapInfo = originalImageRef?.bitmapInfo + guard let alphaInfo = originalImageRef?.alphaInfo else { return UIImage() } + + // See: http://stackoverflow.com/questions/23723564/which-cgimagealphainfo-should-we-use + var bitmapInfo = originalBitmapInfo + switch alphaInfo { + case .none: + let rawBitmapInfoWithoutAlpha = (bitmapInfo?.rawValue)! & ~CGBitmapInfo.alphaInfoMask.rawValue + let rawBitmapInfo = rawBitmapInfoWithoutAlpha | CGImageAlphaInfo.noneSkipFirst.rawValue + bitmapInfo = CGBitmapInfo(rawValue: rawBitmapInfo) + case .premultipliedFirst, .premultipliedLast, .noneSkipFirst, .noneSkipLast: + break + case .alphaOnly, .last, .first: // Unsupported + return self + } + + let colorSpace = CGColorSpaceCreateDeviceRGB() + let pixelSize = CGSize(width: self.size.width * self.scale, height: self.size.height * self.scale) + guard let context = CGContext(data: nil, width: Int(ceil(pixelSize.width)), height: Int(ceil(pixelSize.height)), bitsPerComponent: (originalImageRef?.bitsPerComponent)!, bytesPerRow: 0, space: colorSpace, bitmapInfo: (bitmapInfo?.rawValue)!) else { + return self + } + + let imageRect = CGRect(x: 0, y: 0, width: pixelSize.width, height: pixelSize.height) + UIGraphicsPushContext(context) + + // Flip coordinate system. See: http://stackoverflow.com/questions/506622/cgcontextdrawimage-draws-image-upside-down-when-passed-uiimage-cgimage + context.translateBy(x: 0, y: pixelSize.height) + context.scaleBy(x: 1.0, y: -1.0) + + // UIImage and drawInRect takes into account image orientation, unlike CGContextDrawImage. + self.draw(in: imageRect) + UIGraphicsPopContext() + + guard let decompressedImageRef = context.makeImage() else { + return self + } + + let scale = UIScreen.main.scale + let image = UIImage(cgImage: decompressedImageRef, scale:scale, orientation:UIImageOrientation.up) + return image + } + +} diff --git a/Pods/HanekeSwift/Haneke/UIImageView+Haneke.swift b/Pods/HanekeSwift/Haneke/UIImageView+Haneke.swift new file mode 100644 index 0000000..99a2162 --- /dev/null +++ b/Pods/HanekeSwift/Haneke/UIImageView+Haneke.swift @@ -0,0 +1,139 @@ +// +// UIImageView+Haneke.swift +// Haneke +// +// Created by Hermes Pique on 9/17/14. +// Copyright (c) 2014 Haneke. All rights reserved. +// + +import UIKit + +public extension UIImageView { + + public var hnk_format : Format { + let viewSize = self.bounds.size + assert(viewSize.width > 0 && viewSize.height > 0, "[\(Mirror(reflecting: self).description) \(#function)]: UImageView size is zero. Set its frame, call sizeToFit or force layout first.") + let scaleMode = self.hnk_scaleMode + return HanekeGlobals.UIKit.formatWithSize(viewSize, scaleMode: scaleMode) + } + + public func hnk_setImageFromURL(_ URL: Foundation.URL, placeholder : UIImage? = nil, format : Format? = nil, failure fail : ((Error?) -> ())? = nil, success succeed : ((UIImage) -> ())? = nil) { + let fetcher = NetworkFetcher(URL: URL) + self.hnk_setImage(fromFetcher: fetcher, placeholder: placeholder, format: format, failure: fail, success: succeed) + } + + public func hnk_setImage( _ image: @autoclosure @escaping () -> UIImage, key: String, placeholder : UIImage? = nil, format : Format? = nil, success succeed : ((UIImage) -> ())? = nil) { + let fetcher = SimpleFetcher(key: key, value: image) + self.hnk_setImage(fromFetcher: fetcher, placeholder: placeholder, format: format, success: succeed) + } + + public func hnk_setImageFromFile(_ path: String, placeholder : UIImage? = nil, format : Format? = nil, failure fail : ((Error?) -> ())? = nil, success succeed : ((UIImage) -> ())? = nil) { + let fetcher = DiskFetcher(path: path) + self.hnk_setImage(fromFetcher: fetcher, placeholder: placeholder, format: format, failure: fail, success: succeed) + } + + public func hnk_setImage(fromFetcher fetcher : Fetcher, + placeholder : UIImage? = nil, + format : Format? = nil, + failure fail : ((Error?) -> ())? = nil, + success succeed : ((UIImage) -> ())? = nil) { + + self.hnk_cancelSetImage() + + self.hnk_fetcher = fetcher + + let didSetImage = self.hnk_fetchImageForFetcher(fetcher, format: format, failure: fail, success: succeed) + + if didSetImage { return } + + if let placeholder = placeholder { + self.image = placeholder + } + } + + public func hnk_cancelSetImage() { + if let fetcher = self.hnk_fetcher { + fetcher.cancelFetch() + self.hnk_fetcher = nil + } + } + + // MARK: Internal + + // See: http://stackoverflow.com/questions/25907421/associating-swift-things-with-nsobject-instances + var hnk_fetcher : Fetcher! { + get { + let wrapper = objc_getAssociatedObject(self, &HanekeGlobals.UIKit.SetImageFetcherKey) as? ObjectWrapper + let fetcher = wrapper?.hnk_value as? Fetcher + return fetcher + } + set (fetcher) { + var wrapper : ObjectWrapper? + if let fetcher = fetcher { + wrapper = ObjectWrapper(value: fetcher) + } + objc_setAssociatedObject(self, &HanekeGlobals.UIKit.SetImageFetcherKey, wrapper, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + + public var hnk_scaleMode : ImageResizer.ScaleMode { + switch (self.contentMode) { + case .scaleToFill: + return .Fill + case .scaleAspectFit: + return .AspectFit + case .scaleAspectFill: + return .AspectFill + case .redraw, .center, .top, .bottom, .left, .right, .topLeft, .topRight, .bottomLeft, .bottomRight: + return .None + } + } + + func hnk_fetchImageForFetcher(_ fetcher : Fetcher, format : Format? = nil, failure fail : ((Error?) -> ())?, success succeed : ((UIImage) -> ())?) -> Bool { + let cache = Shared.imageCache + let format = format ?? self.hnk_format + if cache.formats[format.name] == nil { + cache.addFormat(format) + } + var animated = false + let fetch = cache.fetch(fetcher: fetcher, formatName: format.name, failure: {[weak self] error in + if let strongSelf = self { + if strongSelf.hnk_shouldCancel(forKey: fetcher.key) { return } + + strongSelf.hnk_fetcher = nil + + fail?(error) + } + }) { [weak self] image in + if let strongSelf = self { + if strongSelf.hnk_shouldCancel(forKey: fetcher.key) { return } + + strongSelf.hnk_setImage(image, animated: animated, success: succeed) + } + } + animated = true + return fetch.hasSucceeded + } + + func hnk_setImage(_ image : UIImage, animated : Bool, success succeed : ((UIImage) -> ())?) { + self.hnk_fetcher = nil + + if let succeed = succeed { + succeed(image) + } else if animated { + UIView.transition(with: self, duration: HanekeGlobals.UIKit.SetImageAnimationDuration, options: .transitionCrossDissolve, animations: { + self.image = image + }, completion: nil) + } else { + self.image = image + } + } + + func hnk_shouldCancel(forKey key:String) -> Bool { + if self.hnk_fetcher?.key == key { return false } + + Log.debug(message: "Cancelled set image for \((key as NSString).lastPathComponent)") + return true + } + +} diff --git a/Pods/HanekeSwift/Haneke/UIView+Haneke.swift b/Pods/HanekeSwift/Haneke/UIView+Haneke.swift new file mode 100644 index 0000000..b44923e --- /dev/null +++ b/Pods/HanekeSwift/Haneke/UIView+Haneke.swift @@ -0,0 +1,48 @@ +// +// UIView+Haneke.swift +// Haneke +// +// Created by Joan Romano on 15/10/14. +// Copyright (c) 2014 Haneke. All rights reserved. +// + +import UIKit + +public extension HanekeGlobals { + + public struct UIKit { + + static func formatWithSize(_ size : CGSize, scaleMode : ImageResizer.ScaleMode, allowUpscaling: Bool = true) -> Format { + let name = "auto-\(size.width)x\(size.height)-\(scaleMode.rawValue)" + let cache = Shared.imageCache + if let (format,_,_) = cache.formats[name] { + return format + } + + var format = Format(name: name, + diskCapacity: HanekeGlobals.UIKit.DefaultFormat.DiskCapacity) { + let resizer = ImageResizer(size:size, + scaleMode: scaleMode, + allowUpscaling: allowUpscaling, + compressionQuality: HanekeGlobals.UIKit.DefaultFormat.CompressionQuality) + return resizer.resizeImage($0) + } + format.convertToData = {(image : UIImage) -> Data in + image.hnk_data(compressionQuality: HanekeGlobals.UIKit.DefaultFormat.CompressionQuality) as Data + } + return format + } + + public struct DefaultFormat { + + public static let DiskCapacity : UInt64 = 50 * 1024 * 1024 + public static let CompressionQuality : Float = 0.75 + + } + + static var SetImageAnimationDuration = 0.1 + static var SetImageFetcherKey = 0 + static var SetBackgroundImageFetcherKey = 1 + } + +} diff --git a/Pods/HanekeSwift/LICENSE b/Pods/HanekeSwift/LICENSE new file mode 100644 index 0000000..ad410e1 --- /dev/null +++ b/Pods/HanekeSwift/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/Pods/HanekeSwift/README.md b/Pods/HanekeSwift/README.md new file mode 100644 index 0000000..e83f6a2 --- /dev/null +++ b/Pods/HanekeSwift/README.md @@ -0,0 +1,249 @@ +![Haneke](https://raw.githubusercontent.com/Haneke/HanekeSwift/master/Assets/github-header.png) + +[![CocoaPods Version](https://cocoapod-badges.herokuapp.com/v/HanekeSwift/badge.png)](http://cocoadocs.org/docsets/HanekeSwift) +[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) +[![Platform](https://cocoapod-badges.herokuapp.com/p/HanekeSwift/badge.png)](http://cocoadocs.org/docsets/HanekeSwift) +[![Build Status](https://travis-ci.org/Haneke/HanekeSwift.svg?branch=master)](https://travis-ci.org/Haneke/HanekeSwift) +[![Join the chat at https://gitter.im/Haneke/HanekeSwift](https://badges.gitter.im/Haneke/HanekeSwift.svg)](https://gitter.im/Haneke/HanekeSwift?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +Haneke is a lightweight *generic* cache for iOS and tvOS written in Swift 2.3 (Swift 3 coming soon). It's designed to be super-simple to use. Here's how you would initalize a JSON cache and fetch objects from a url: + +```swift +let cache = Cache(name: "github") +let URL = NSURL(string: "https://api.github.com/users/haneke")! + +cache.fetch(URL: URL).onSuccess { JSON in + print(JSON.dictionary?["bio"]) +} +``` + +Haneke provides a memory and LRU disk cache for `UIImage`, `NSData`, `JSON`, `String` or any other type that can be read or written as data. + +Particularly, Haneke excels at working with images. It includes a zero-config image cache with automatic resizing. Everything is done in background, allowing for fast, responsive scrolling. Asking Haneke to load, resize, cache and display an *appropriately sized image* is as simple as: + +```swift +imageView.hnk_setImageFromURL(url) +``` + +_Really._ + +## Features + +* Generic cache with out-of-the-box support for `UIImage`, `NSData`, `JSON` and `String` +* First-level memory cache using `NSCache` +* Second-level LRU disk cache using the file system +* Asynchronous [fetching](#fetchers) of original values from network or disk +* All disk access is performed in background +* Thread-safe +* Automatic cache eviction on memory warnings or disk capacity reached +* Comprehensive unit tests +* Extensible by defining [custom formats](#formats), supporting [additional types](#supporting-additional-types) or implementing [custom fetchers](#custom-fetchers) + +For images: + +* Zero-config `UIImageView` and `UIButton` extensions to use the cache, optimized for `UITableView` and `UICollectionView` cell reuse +* Background image resizing and decompression + +## Installation + +Using [CocoaPods](http://cocoapods.org/): + +```ruby +use_frameworks! +pod 'HanekeSwift' +``` + +Using [Carthage](https://github.com/Carthage/Carthage): + +``` +github "Haneke/HanekeSwift" +``` + +Manually: + +1. Drag `Haneke.xcodeproj` to your project in the _Project Navigator_. +2. Select your project and then your app target. Open the _Build Phases_ panel. +3. Expand the _Target Dependencies_ group, and add `Haneke.framework`. +4. Click on the `+` button at the top left of the panel and select _New Copy Files Phase_. Set _Destination_ to _Frameworks_, and add `Haneke.framework`. +5. `import Haneke` whenever you want to use Haneke. + +## Requirements + +- iOS 8.0+ or tvOS 9.1+ +- Swift 2.3 + +## Using the cache + +Haneke provides shared caches for `UIImage`, `NSData`, `JSON` and `String`. You can also create your own caches. + +The cache is a key-value store. For example, here's how you would cache and then fetch some data. + +```Swift +let cache = Shared.dataCache + +cache.set(value: data, key: "funny-games.mp4") + +// Eventually... + +cache.fetch(key: "funny-games.mp4").onSuccess { data in + // Do something with data +} +``` + +In most cases the value will not be readily available and will have to be fetched from network or disk. Haneke offers convenience `fetch` functions for these cases. Let's go back to the first example, now using a shared cache: + +```Swift +let cache = Shared.JSONCache +let URL = NSURL(string: "https://api.github.com/users/haneke")! + +cache.fetch(URL: URL).onSuccess { JSON in + print(JSON.dictionary?["bio"]) +} +``` + +The above call will first attempt to fetch the required JSON from (in order) memory, disk or `NSURLCache`. If not available, Haneke will fetch the JSON from the source, return it and then cache it. In this case, the URL itself is used as the key. + +Further customization can be achieved by using [formats](#formats), [supporting additional types](#supporting-additional-types) or implementing [custom fetchers](#custom-fetchers). + +## Extra ♡ for images + +Need to cache and display images? Haneke provides convenience methods for `UIImageView` and `UIButton` with optimizations for `UITableView` and `UICollectionView` cell reuse. Images will be resized appropriately and cached in a shared cache. + +```swift +// Setting a remote image +imageView.hnk_setImageFromURL(url) + +// Setting an image manually. Requires you to provide a key. +imageView.hnk_setImage(image, key: key) +``` + +The above lines take care of: + +1. If cached, retrieving an appropriately sized image (based on the `bounds` and `contentMode` of the `UIImageView`) from the memory or disk cache. Disk access is performed in background. +2. If not cached, loading the original image from web/memory and producing an appropriately sized image, both in background. Remote images will be retrieved from the shared `NSURLCache` if available. +3. Setting the image and animating the change if appropriate. +4. Or doing nothing if the `UIImageView` was reused during any of the above steps. +5. Caching the resulting image. +6. If needed, evicting the least recently used images in the cache. + +## Formats + +Formats allow to specify the disk cache size and any transformations to the values before being cached. For example, the `UIImageView` extension uses a format that resizes images to fit or fill the image view as needed. + +You can also use custom formats. Say you want to limit the disk capacity for icons to 10MB and apply rounded corners to the images. This is how it could look like: + +```swift +let cache = Shared.imageCache + +let iconFormat = Format(name: "icons", diskCapacity: 10 * 1024 * 1024) { image in + return imageByRoundingCornersOfImage(image) +} +cache.addFormat(iconFormat) + +let URL = NSURL(string: "http://haneke.io/icon.png")! +cache.fetch(URL: URL, formatName: "icons").onSuccess { image in + // image will be a nice rounded icon +} +``` + +Because we told the cache to use the `"icons"` format Haneke will execute the format transformation in background and return the resulting value. + +Formats can also be used from the `UIKit` extensions: + +```swift +imageView.hnk_setImageFromURL(url, format: iconFormat) +``` + +## Fetchers + +The `fetch` functions for urls and paths are actually convenience methods. Under the hood Haneke uses fetcher objects. To illustrate, here's another way of fetching from a url by explictly using a network fetcher: + +```swift +let URL = NSURL(string: "http://haneke.io/icon.png")! +let fetcher = NetworkFetcher(URL: URL) +cache.fetch(fetcher: fetcher).onSuccess { image in + // Do something with image +} +``` + +Fetching an original value from network or disk is an expensive operation. Fetchers act as a proxy for the value, and allow Haneke to perform the fetch operation only if absolutely necessary. + +In the above example the fetcher will be executed only if there is no value associated with `"http://haneke.io/icon.png"` in the memory or disk cache. If that happens, the fetcher will be responsible from fetching the original value, which will then be cached to avoid further network activity. + +Haneke provides two specialized fetchers: `NetworkFetcher` and `DiskFetcher`. You can also implement your own fetchers by subclassing `Fetcher`. + +### Custom fetchers + +Through custom fetchers you can fetch original values from other sources than network or disk (e.g., Core Data), or even change how Haneke acceses network or disk (e.g., use [Alamofire](https://github.com/Alamofire/Alamofire) for networking instead of `NSURLSession`). A custom fetcher must subclass `Fetcher` and is responsible for: + +* Providing the key (e.g., `NSURL.absoluteString` in the case of `NetworkFetcher`) associated with the value to be fetched +* Fetching the value in background and calling the success or failure closure accordingly, both in the main queue +* Cancelling the fetch on demand, if possible + +Fetchers are generic, and the only restriction on their type is that it must implement `DataConvertible`. + +## Supporting additional types + +Haneke can cache any type that can be read and saved as data. This is indicated to Haneke by implementing the protocols `DataConvertible` and `DataRepresentable`. + +```Swift +public protocol DataConvertible { + typealias Result + + class func convertFromData(data:NSData) -> Result? + +} + +public protocol DataRepresentable { + + func asData() -> NSData! + +} +``` + +This is how one could add support for `NSDictionary`: + +```Swift +extension NSDictionary : DataConvertible, DataRepresentable { + + public typealias Result = NSDictionary + + public class func convertFromData(data:NSData) -> Result? { + return NSKeyedUnarchiver.unarchiveObjectWithData(data) as? NSDictionary + } + + public func asData() -> NSData! { + return NSKeyedArchiver.archivedDataWithRootObject(self) + } + +} +``` + +Then creating a `NSDictionary` cache would be as simple as: + +```swift +let cache = Cache(name: "dictionaries") +``` + +## Roadmap + +Haneke Swift is in initial development and its public API should not be considered stable. + +## License + + Copyright 2014 Hermes Pique ([@hpique](https://twitter.com/hpique)) +                 2014 Joan Romano ([@joanromano](https://twitter.com/joanromano)) +                 2014 Luis Ascorbe ([@lascorbe](https://twitter.com/Lascorbe)) +                 2014 Oriol Blanc ([@oriolblanc](https://twitter.com/oriolblanc)) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/Local Podspecs/HanekeSwift.podspec.json b/Pods/Local Podspecs/HanekeSwift.podspec.json new file mode 100644 index 0000000..ce839be --- /dev/null +++ b/Pods/Local Podspecs/HanekeSwift.podspec.json @@ -0,0 +1,20 @@ +{ + "name": "HanekeSwift", + "module_name": "Haneke", + "version": "0.10.1", + "license": "Apache", + "summary": "A lightweight generic cache for iOS written in Swift with extra love for images.", + "homepage": "https://github.com/Haneke/HanekeSwift", + "authors": { + "Hermes Pique": "https://twitter.com/hpique" + }, + "source": { + "git": "https://github.com/Haneke/HanekeSwift.git", + "tag": "v0.10.1" + }, + "platforms": { + "tvos": "9.1", + "ios": "8.0" + }, + "source_files": "Haneke/*.swift" +} diff --git a/Pods/Manifest.lock b/Pods/Manifest.lock new file mode 100644 index 0000000..5ba009c --- /dev/null +++ b/Pods/Manifest.lock @@ -0,0 +1,25 @@ +PODS: + - HanekeSwift (0.10.1) + - ObjectMapper (2.2.9) + +DEPENDENCIES: + - HanekeSwift (from `https://github.com/Haneke/HanekeSwift.git`, branch `feature/swift-3`) + - ObjectMapper (~> 2.2) + +EXTERNAL SOURCES: + HanekeSwift: + :branch: feature/swift-3 + :git: https://github.com/Haneke/HanekeSwift.git + +CHECKOUT OPTIONS: + HanekeSwift: + :commit: 2f6d87f1f725d204d85cb34492e8c399cd5a200f + :git: https://github.com/Haneke/HanekeSwift.git + +SPEC CHECKSUMS: + HanekeSwift: 4113367892828e7700d24a384027de6ebc79aad1 + ObjectMapper: 63cfe41bc6f8e7c8f44344c49901b8ae7de14c52 + +PODFILE CHECKSUM: 538d829ced17ecb6c715d132f791f34d2433468a + +COCOAPODS: 1.3.1 diff --git a/Pods/ObjectMapper/LICENSE b/Pods/ObjectMapper/LICENSE new file mode 100644 index 0000000..be48bc6 --- /dev/null +++ b/Pods/ObjectMapper/LICENSE @@ -0,0 +1,8 @@ +The MIT License (MIT) +Copyright (c) 2014 Hearst + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Pods/ObjectMapper/README-CN.md b/Pods/ObjectMapper/README-CN.md new file mode 100644 index 0000000..b1a0209 --- /dev/null +++ b/Pods/ObjectMapper/README-CN.md @@ -0,0 +1,502 @@ +# ObjectMapper-CN-Guide +> 文档由Swift老司机活动中心负责翻译,欢迎关注[@SwiftOldDriver](http://weibo.com/6062089411)。翻译有问题可以到 [ObjectMapper-CN-Guide](https://github.com/SwiftOldDriver/ObjectMapper-CN-Guide) 提 PR。 + +[ObjectMapper](https://github.com/Hearst-DD/ObjectMapper) 是一个使用 Swift 编写的用于 model 对象(类和结构体)和 JSON 之间转换的框架。 + +- [特性](#特性) +- [基础使用方法](#基础使用方法) +- [映射嵌套对象](#映射嵌套对象) +- [自定义转换规则](#自定义转换规则) +- [继承](#继承) +- [泛型对象](#泛型对象) +- [映射时的上下文对象](#映射时的上下文对象) +- [ObjectMapper + Alamofire](#objectmapper--alamofire) +- [ObjectMapper + Realm](#objectmapper--realm) +- [待完成](#待完成) +- [安装](#安装) + +# 特性: +- 把 JSON 映射成对象 +- 把对象映射 JSON +- 支持嵌套对象 (单独的成员变量、在数组或字典中都可以) +- 在转换过程支持自定义规则 +- 支持结构体( Struct ) +- [Immutable support](#immutablemappable-protocol-beta) (目前还在 beta ) + +# 基础使用方法 +为了支持映射,类或者结构体只需要实现```Mappable```协议。这个协议包含以下方法: +```swift +init?(map: Map) +mutating func mapping(map: Map) +``` +ObjectMapper使用自定义的```<-``` 运算符来声明成员变量和 JSON 的映射关系。 +```swift +class User: Mappable { + var username: String? + var age: Int? + var weight: Double! + var array: [AnyObject]? + var dictionary: [String : AnyObject] = [:] + var bestFriend: User? // 嵌套的 User 对象 + var friends: [User]? // Users 的数组 + var birthday: NSDate? + + required init?(map: Map) { + + } + + // Mappable + func mapping(map: Map) { + username <- map["username"] + age <- map["age"] + weight <- map["weight"] + array <- map["arr"] + dictionary <- map["dict"] + bestFriend <- map["best_friend"] + friends <- map["friends"] + birthday <- (map["birthday"], DateTransform()) + } +} + +struct Temperature: Mappable { + var celsius: Double? + var fahrenheit: Double? + + init?(map: Map) { + + } + + mutating func mapping(map: Map) { + celsius <- map["celsius"] + fahrenheit <- map["fahrenheit"] + } +} +``` + +一旦你的对象实现了 `Mappable`, ObjectMapper就可以让你轻松的实现和 JSON 之间的转换。 + +把 JSON 字符串转成 model 对象: + +```swift +let user = User(JSONString: JSONString) +``` + +把一个 model 转成 JSON 字符串: + +```swift +let JSONString = user.toJSONString(prettyPrint: true) +``` + +也可以使用`Mapper.swift`类来完成转换(这个类还额外提供了一些函数来处理一些特殊的情况: + +```swift +// 把 JSON 字符串转成 Model +let user = Mapper().map(JSONString: JSONString) +// 根据 Model 生成 JSON 字符串 +let JSONString = Mapper().toJSONString(user, prettyPrint: true) +``` + +ObjectMapper支持以下的类型映射到对象中: + +- `Int` +- `Bool` +- `Double` +- `Float` +- `String` +- `RawRepresentable` (枚举) +- `Array` +- `Dictionary` +- `Object` +- `Array` +- `Array>` +- `Set` +- `Dictionary` +- `Dictionary>` +- 以上所有的 Optional 类型 +- 以上所有的隐式强制解包类型(Implicitly Unwrapped Optional) + +## `Mappable` 协议 + +#### `mutating func mapping(map: Map)` +所有的映射最后都会调用到这个函数。当解析 JSON 时,这个函数会在对象创建成功后被执行。当生成 JSON 时就只有这个函数会被对象调用。 + +#### `init?(map: Map)` +这个可失败的初始化函数是 ObjectMapper 创建对象的时候使用的。开发者可以通过这个函数在映射前校验 JSON 。如果在这个方法里返回 nil 就不会执行 `mapping` 函数。可以通过传入的保存着 JSON 的 `Map` 对象进行校验: + +```swift +required init?(map: Map){ + // 检查 JSON 里是否有一定要有的 "name" 属性 + if map.JSONDictionary["name"] == nil { + return nil + } +} +``` + +## `StaticMappable` 协议 +`StaticMappable` 是 `Mappable` 之外的另一种选择。 这个协议可以让开发者通过一个静态函数初始化对象而不是通过 `init?(map: Map)`。 + +注意: `StaticMappable` 和 `Mappable` 都继承了 `BaseMappable` 协议。 `BaseMappable` 协议声明了 `mapping(map: Map)` 函数。 + +#### `static func objectForMapping(map: Map) -> BaseMappable?` +ObjectMapper 使用这个函数获取对象后进行映射。开发者需要在这个函数里返回一个实现 `BaseMappable` 对象的实例。这个函数也可以用于: + +- 在对象进行映射前校验 JSON +- 提供一个缓存过的对象用于映射 +- 返回另外一种类型的对象(当然是必须实现了 BaseMappable)用于映射。比如你可能通过检查 JSON 推断出用于映射的对象 ([看这个例子](https://github.com/Hearst-DD/ObjectMapper/blob/master/ObjectMapperTests/ClassClusterTests.swift#L62))。 + +如果你需要在 extension 里实现 ObjectMapper,你需要选择这个协议而不是 `Mappable` 。 + +## `ImmutableMappable` Protocol (Beta) + +> ⚠️ 这个特性还处于 Beta 阶段。正式发布时 API 可能会完全不同。 + +使用 `ImmutableMappable` 可以映射不可变的属性。下面的表格展示了 `ImmutableMappable` 和 `Mappable` 的不同: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ImmutableMappableMappable
Properties
+
+let id: Int
+let name: String?
+
+
+
+var id: Int!
+var name: String?
+
+
JSON -> Model
+
+init(map: Map) throws {
+  id   = try map.value("id")
+  name = try? map.value("name")
+}
+
+
+
+mutating func mapping(map: Map) {
+  id   <- map["id"]
+  name <- map["name"]
+}
+
+
Model -> JSON
+
+mutating func mapping(map: Map) {
+  id   >>> map["id"]
+  name >>> map["name"]
+}
+
+
+
+mutating func mapping(map: Map) {
+  id   <- map["id"]
+  name <- map["name"]
+}
+
+
Initializing
+
+try User(JSONString: JSONString)
+
+
+
+User(JSONString: JSONString)
+
+
+ +#### `init(map: Map) throws` + +这个可能抛出异常的初始化函数用于在提供的 `Map` 里映射不可变属性。每个不可变的初始化属性都要在这个初始化函数里初始化。 + +当发生下列情况时初始化函数会抛出一个错误: + +- `Map` 根据提供的键名获取不到对应值 +- `Map` 使用 `Transform` 后没有得到值 + +`ImmutableMappable` 使用 `Map.value(_:using:)` 方法从 `Map` 中获取值。因为可能抛出异常,这个方法在使用时需要使用 `try` 关键字。 `Optional` 的属性可以简单的用 `try?` 处理。 + +```swift +init(map: Map) throws { + name = try map.value("name") // throws an error when it fails + createdAt = try map.value("createdAt", using: DateTransform()) // throws an error when it fails + updatedAt = try? map.value("updatedAt", using: DateTransform()) // optional + posts = (try? map.value("posts")) ?? [] // optional + default value +} +``` + +#### `mutating func mapping(map: Map)` + +这个方法是在 Model 转回 JSON 时调用的。因为不可变的属性不能被 `<-` 映射,所以映射回来时需要使用 `>>>` 。 + +```swift +mutating func mapping(map: Map) { + name >>> map["name"] + createdAt >>> (map["createdAt"], DateTransform()) + updatedAt >>> (map["updatedAt"], DateTransform()) + posts >>> map["posts"] +} +``` +# 轻松映射嵌套对象 + +ObjectMapper 支持使用点语法来轻松实现嵌套对象的映射。比如有如下的 JSON 字符串: + +```json +"distance" : { + "text" : "102 ft", + "value" : 31 +} +``` +你可以通过这种写法直接访问到嵌套对象: + +```swift +func mapping(map: Map) { + distance <- map["distance.value"] +} +``` +嵌套的键名也支持访问数组中的值。如果有一个返回的 JSON 是一个包含 distance 的数组,可以通过这种写法访问: + +``` +distance <- map["distances.0.value"] +``` +如果你的键名刚好含有 `.` 符号,你需要特别声明关闭上面提到的获取嵌套对象功能: + +```swift +func mapping(map: Map) { + identifier <- map["app.identifier", nested: false] +} +``` +如果刚好有嵌套的对象的键名还有 `.` ,可以在中间加入一个自定义的分割符([#629](https://github.com/Hearst-DD/ObjectMapper/pull/629)): +```swift +func mapping(map: Map) { + appName <- map["com.myapp.info->com.myapp.name", delimiter: "->"] +} +``` +这种情况的 JSON 是这样的: + +```json +"com.myapp.info" : { + "com.myapp.name" : "SwiftOldDriver" +} +``` + +# 自定义转换规则 +ObjectMapper 也支持在映射时自定义转换规则。如果要使用自定义转换,创建一个 tuple(元祖)包含 ```map["field_name"]``` 和你要使用的变换放在 ```<-``` 的右边: + +```swift +birthday <- (map["birthday"], DateTransform()) +``` +当解析 JSON 时上面的转换会把 JSON 里面的 Int 值转成一个 NSDate ,如果是对象转为 JSON 时,则会把 NSDate 对象转成 Int 值。 + +只要实现```TransformType``` 协议就可以轻松的创建自定义的转换规则: + +```swift +public protocol TransformType { + associatedtype Object + associatedtype JSON + + func transformFromJSON(_ value: Any?) -> Object? + func transformToJSON(_ value: Object?) -> JSON? +} +``` + +### TransformOf +大多数情况下你都可以使用框架提供的转换类 ```TransformOf``` 来快速的实现一个期望的转换。 ```TransformOf``` 的初始化需要两个类型和两个闭包。两个类型声明了转换的目标类型和源类型,闭包则实现具体转换逻辑。 + +举个例子,如果你想要把一个 JSON 字符串转成 Int ,你可以像这样使用 ```TransformOf``` : + +```swift +let transform = TransformOf(fromJSON: { (value: String?) -> Int? in + // 把值从 String? 转成 Int? + return Int(value!) +}, toJSON: { (value: Int?) -> String? in + // 把值从 Int? 转成 String? + if let value = value { + return String(value) + } + return nil +}) + +id <- (map["id"], transform) +``` +这是一种更省略的写法: + +```swift +id <- (map["id"], TransformOf(fromJSON: { Int($0!) }, toJSON: { $0.map { String($0) } })) +``` +# 继承 + +实现了 ```Mappable``` 协议的类可以容易的被继承。当继承一个 mappable 的类时,使用这样的结构: + +```swift +class Base: Mappable { + var base: String? + + required init?(map: Map) { + + } + + func mapping(map: Map) { + base <- map["base"] + } +} + +class Subclass: Base { + var sub: String? + + required init?(map: Map) { + super.init(map) + } + + override func mapping(map: Map) { + super.mapping(map) + + sub <- map["sub"] + } +} +``` + +注意确认子类中的实现调用了父类中正确的初始化器和映射函数。 + +# 泛型对象 + +ObjectMapper 可以处理泛型只要这个泛型也实现了`Mappable`协议。看这个例子: + +```swift +class Result: Mappable { + var result: T? + + required init?(map: Map){ + + } + + func mapping(map: Map) { + result <- map["result"] + } +} + +let result = Mapper>().map(JSON) +``` +# 映射时的上下文对象 + +`Map` 是在映射时传入的对象,带有一个 optional `MapContext` 对象,开发者可以通过使用这个对象在映射时传入一些信息。 + +为了使用这个特性,需要先创建一个对象实现了 `MapContext` 协议(这个协议是空的),然后在初始化时传入 `Mapper` 中。 + +```swift +struct Context: MapContext { + var importantMappingInfo = "映射时需要知道的额外信息" +} + +class User: Mappable { + var name: String? + + required init?(map: Map){ + + } + + func mapping(map: Map){ + if let context = map.context as? Context { + // 获取到额外的信息 + } + } +} + +let context = Context() +let user = Mapper(context: context).map(JSONString) +``` + +# ObjectMapper + Alamofire + +如果网络层你使用的是 [Alamofire](https://github.com/Alamofire/Alamofire) ,并且你希望把返回的结果转换成 Swift 对象,你可以使用 [AlamofireObjectMapper](https://github.com/tristanhimmelman/AlamofireObjectMapper) 。这是一个使用 ObjectMapper 实现的把返回的 JSON 自动转成 Swift 对象的 Alamofire 的扩展。 + + +# ObjectMapper + Realm + +ObjectMapper 可以和 Realm 一起配合使用。使用下面的声明结构就可以使用 ObjectMapper 生成 Realm 对象: + +```swift +class Model: Object, Mappable { + dynamic var name = "" + + required convenience init?(map: Map) { + self.init() + } + + func mapping(map: Map) { + name <- map["name"] + } +} +``` + +如果你想要序列化相关联的 RealmObject,你可以使用 [ObjectMapper+Realm](https://github.com/jakenberg/ObjectMapper-Realm)。这是一个简单的 Realm 扩展,用于把任意的 JSON 序列化成 Realm 的类(ealm's List class。) + +注意:使用 ObjectMappers 的 `toJSON` 函数来生成 JSON 字符串只在 Realm 的写事务中有效(write transaction)。这是因为 ObjectMapper 在解析和生成时在映射函数( `<-` )中使用 `inout` 作为标记( flag )。Realm 会检测到标记并且强制要求 `toJSON` 函数只能在一个写的事务中调用,即使这个对象并没有被修改。 + +# 待完成 +- 改善错误的处理。可能使用 `throws` 来处理。 +- 相关类的文档完善 + +# 安装 +### Cocoapods +如果你的项目使用 [CocoaPods 0.36 及以上](http://blog.cocoapods.org/Pod-Authors-Guide-to-CocoaPods-Frameworks/) 的版本,你可以把下面内容添加到在 `Podfile` 中,将 ObjectMapper 添加到你的项目中: + +```ruby +pod 'ObjectMapper', '~> 2.2' +``` + +### Carthage +如果你的项目使用 [Carthage](https://github.com/Carthage/Carthage) ,你可以把下面的内容添加到 `Cartfile` 中,将 ObjectMapper 的依赖到你的项目中: + +``` +github "Hearst-DD/ObjectMapper" ~> 2.2 +``` + +### Swift Package Manager +如果你的项目使用 [Swift Package Manager](https://swift.org/package-manager/) ,那么你可以把下面内容添加到 `Package.swift` 中的 `dependencies` 数组中,将 ObjectMapper 的依赖到你的项目中: + +```swift +.Package(url: "https://github.com/Hearst-DD/ObjectMapper.git", majorVersion: 2, minor: 2), +``` + + +### Submodule +此外,ObjectMapper 也可以作为一个 submodule 添加到项目中: + +1. 打开终端,使用 `cd` 命令进入项目文件的根目录下,然后在终端中输入 `git submodule add https://github.com/Hearst-DD/ObjectMapper.git` ,把 ObjectMapper 作为项目的一个 [submodule](http://git-scm.com/docs/git-submodule) 添加进来。 +2. 打开 `ObjectMapper` 文件,并将 `ObjectMapper.xcodeproj` 拖进你 app 项目的文件导航中。 +3. 在 Xcode 中,文件导航中点击蓝色项目图标进入到 target 配置界面,在侧边栏的 "TARGETS" 下选择主工程对应的target。 +4. 确保 `ObjectMapper.framework` 的部署版本( deployment target )和主工程的部署版本保持一致。 +5. 在配置界面的顶部选项栏中,打开 "Build Phases" 面板。 +6. 展开 "Target Dependencies" 组,并添加 `ObjectMapper.framework` 。 +7. 点击面板左上角的 `+` 按钮,选择 "New Copy Files Phase"。将这个阶段重命名为 "Copy Frameworks",设置 "Destination" 为 "Frameworks",最后添加 `ObjectMapper.framework` 。 + + diff --git a/Pods/ObjectMapper/Sources/CustomDateFormatTransform.swift b/Pods/ObjectMapper/Sources/CustomDateFormatTransform.swift new file mode 100644 index 0000000..3cd5c59 --- /dev/null +++ b/Pods/ObjectMapper/Sources/CustomDateFormatTransform.swift @@ -0,0 +1,40 @@ +// +// CustomDateFormatTransform.swift +// ObjectMapper +// +// Created by Dan McCracken on 3/8/15. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Hearst +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +open class CustomDateFormatTransform: DateFormatterTransform { + + public init(formatString: String) { + let formatter = DateFormatter() + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.dateFormat = formatString + + super.init(dateFormatter: formatter) + } +} diff --git a/Pods/ObjectMapper/Sources/DataTransform.swift b/Pods/ObjectMapper/Sources/DataTransform.swift new file mode 100644 index 0000000..d96f3d6 --- /dev/null +++ b/Pods/ObjectMapper/Sources/DataTransform.swift @@ -0,0 +1,50 @@ +// +// DataTransform.swift +// ObjectMapper +// +// Created by Yagrushkin, Evgeny on 8/30/16. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Hearst +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +open class DataTransform: TransformType { + public typealias Object = Data + public typealias JSON = String + + public init() {} + + open func transformFromJSON(_ value: Any?) -> Data? { + guard let string = value as? String else{ + return nil + } + return Data(base64Encoded: string) + } + + open func transformToJSON(_ value: Data?) -> String? { + guard let data = value else{ + return nil + } + return data.base64EncodedString() + } +} diff --git a/Pods/ObjectMapper/Sources/DateFormatterTransform.swift b/Pods/ObjectMapper/Sources/DateFormatterTransform.swift new file mode 100644 index 0000000..fa75f3b --- /dev/null +++ b/Pods/ObjectMapper/Sources/DateFormatterTransform.swift @@ -0,0 +1,54 @@ +// +// DateFormatterTransform.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2015-03-09. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Hearst +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +open class DateFormatterTransform: TransformType { + public typealias Object = Date + public typealias JSON = String + + public let dateFormatter: DateFormatter + + public init(dateFormatter: DateFormatter) { + self.dateFormatter = dateFormatter + } + + open func transformFromJSON(_ value: Any?) -> Date? { + if let dateString = value as? String { + return dateFormatter.date(from: dateString) + } + return nil + } + + open func transformToJSON(_ value: Date?) -> String? { + if let date = value { + return dateFormatter.string(from: date) + } + return nil + } +} diff --git a/Pods/ObjectMapper/Sources/DateTransform.swift b/Pods/ObjectMapper/Sources/DateTransform.swift new file mode 100644 index 0000000..2c175cb --- /dev/null +++ b/Pods/ObjectMapper/Sources/DateTransform.swift @@ -0,0 +1,55 @@ +// +// DateTransform.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2014-10-13. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Hearst +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +open class DateTransform: TransformType { + public typealias Object = Date + public typealias JSON = Double + + public init() {} + + open func transformFromJSON(_ value: Any?) -> Date? { + if let timeInt = value as? Double { + return Date(timeIntervalSince1970: TimeInterval(timeInt)) + } + + if let timeStr = value as? String { + return Date(timeIntervalSince1970: TimeInterval(atof(timeStr))) + } + + return nil + } + + open func transformToJSON(_ value: Date?) -> Double? { + if let date = value { + return Double(date.timeIntervalSince1970) + } + return nil + } +} diff --git a/Pods/ObjectMapper/Sources/DictionaryTransform.swift b/Pods/ObjectMapper/Sources/DictionaryTransform.swift new file mode 100644 index 0000000..e7b6ef3 --- /dev/null +++ b/Pods/ObjectMapper/Sources/DictionaryTransform.swift @@ -0,0 +1,58 @@ +// +// DictionaryTransform.swift +// ObjectMapper +// +// Created by Milen Halachev on 7/20/16. +// Copyright © 2016 hearst. All rights reserved. +// + +import Foundation + +///Transforms [String: AnyObject] <-> [Key: Value] where Key is RawRepresentable as String, Value is Mappable +public struct DictionaryTransform: TransformType where Key: Hashable, Key: RawRepresentable, Key.RawValue == String, Value: Mappable { + + public init() { + + } + + public func transformFromJSON(_ value: Any?) -> [Key: Value]? { + + guard let json = value as? [String: Any] else { + + return nil + } + + let result = json.reduce([:]) { (result, element) -> [Key: Value] in + + guard + let key = Key(rawValue: element.0), + let valueJSON = element.1 as? [String: Any], + let value = Value(JSON: valueJSON) + else { + + return result + } + + var result = result + result[key] = value + return result + } + + return result + } + + public func transformToJSON(_ value: [Key: Value]?) -> Any? { + + let result = value?.reduce([:]) { (result, element) -> [String: Any] in + + let key = element.0.rawValue + let value = element.1.toJSON() + + var result = result + result[key] = value + return result + } + + return result + } +} diff --git a/Pods/ObjectMapper/Sources/EnumOperators.swift b/Pods/ObjectMapper/Sources/EnumOperators.swift new file mode 100644 index 0000000..5a1a667 --- /dev/null +++ b/Pods/ObjectMapper/Sources/EnumOperators.swift @@ -0,0 +1,91 @@ +// +// EnumOperators.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2016-09-26. +// Copyright © 2016 hearst. All rights reserved. +// + +import Foundation + + +// MARK:- Raw Representable types + +/// Object of Raw Representable type +public func <- (left: inout T, right: Map) { + left <- (right, EnumTransform()) +} + +public func >>> (left: T, right: Map) { + left >>> (right, EnumTransform()) +} + + +/// Optional Object of Raw Representable type +public func <- (left: inout T?, right: Map) { + left <- (right, EnumTransform()) +} + +public func >>> (left: T?, right: Map) { + left >>> (right, EnumTransform()) +} + + +/// Implicitly Unwrapped Optional Object of Raw Representable type +public func <- (left: inout T!, right: Map) { + left <- (right, EnumTransform()) +} + +// MARK:- Arrays of Raw Representable type + +/// Array of Raw Representable object +public func <- (left: inout [T], right: Map) { + left <- (right, EnumTransform()) +} + +public func >>> (left: [T], right: Map) { + left >>> (right, EnumTransform()) +} + + +/// Array of Raw Representable object +public func <- (left: inout [T]?, right: Map) { + left <- (right, EnumTransform()) +} + +public func >>> (left: [T]?, right: Map) { + left >>> (right, EnumTransform()) +} + + +/// Array of Raw Representable object +public func <- (left: inout [T]!, right: Map) { + left <- (right, EnumTransform()) +} + +// MARK:- Dictionaries of Raw Representable type + +/// Dictionary of Raw Representable object +public func <- (left: inout [String: T], right: Map) { + left <- (right, EnumTransform()) +} + +public func >>> (left: [String: T], right: Map) { + left >>> (right, EnumTransform()) +} + + +/// Dictionary of Raw Representable object +public func <- (left: inout [String: T]?, right: Map) { + left <- (right, EnumTransform()) +} + +public func >>> (left: [String: T]?, right: Map) { + left >>> (right, EnumTransform()) +} + + +/// Dictionary of Raw Representable object +public func <- (left: inout [String: T]!, right: Map) { + left <- (right, EnumTransform()) +} diff --git a/Pods/ObjectMapper/Sources/EnumTransform.swift b/Pods/ObjectMapper/Sources/EnumTransform.swift new file mode 100644 index 0000000..43e4ce7 --- /dev/null +++ b/Pods/ObjectMapper/Sources/EnumTransform.swift @@ -0,0 +1,50 @@ +// +// EnumTransform.swift +// ObjectMapper +// +// Created by Kaan Dedeoglu on 3/20/15. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Hearst +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +open class EnumTransform: TransformType { + public typealias Object = T + public typealias JSON = T.RawValue + + public init() {} + + open func transformFromJSON(_ value: Any?) -> T? { + if let raw = value as? T.RawValue { + return T(rawValue: raw) + } + return nil + } + + open func transformToJSON(_ value: T?) -> T.RawValue? { + if let obj = value { + return obj.rawValue + } + return nil + } +} diff --git a/Pods/ObjectMapper/Sources/FromJSON.swift b/Pods/ObjectMapper/Sources/FromJSON.swift new file mode 100755 index 0000000..952b42b --- /dev/null +++ b/Pods/ObjectMapper/Sources/FromJSON.swift @@ -0,0 +1,181 @@ +// +// FromJSON.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2014-10-09. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Hearst +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +internal final class FromJSON { + + /// Basic type + class func basicType(_ field: inout FieldType, object: FieldType?) { + if let value = object { + field = value + } + } + + /// optional basic type + class func optionalBasicType(_ field: inout FieldType?, object: FieldType?) { + field = object + } + + /// Implicitly unwrapped optional basic type + class func optionalBasicType(_ field: inout FieldType!, object: FieldType?) { + field = object + } + + /// Mappable object + class func object(_ field: inout N, map: Map) { + if map.toObject { + field = Mapper(context: map.context).map(JSONObject: map.currentValue, toObject: field) + } else if let value: N = Mapper(context: map.context).map(JSONObject: map.currentValue) { + field = value + } + } + + /// Optional Mappable Object + + class func optionalObject(_ field: inout N?, map: Map) { + if let f = field , map.toObject && map.currentValue != nil { + field = Mapper(context: map.context).map(JSONObject: map.currentValue, toObject: f) + } else { + field = Mapper(context: map.context).map(JSONObject: map.currentValue) + } + } + + /// Implicitly unwrapped Optional Mappable Object + class func optionalObject(_ field: inout N!, map: Map) { + if let f = field , map.toObject && map.currentValue != nil { + field = Mapper(context: map.context).map(JSONObject: map.currentValue, toObject: f) + } else { + field = Mapper(context: map.context).map(JSONObject: map.currentValue) + } + } + + /// mappable object array + class func objectArray(_ field: inout Array, map: Map) { + if let objects = Mapper(context: map.context).mapArray(JSONObject: map.currentValue) { + field = objects + } + } + + /// optional mappable object array + + class func optionalObjectArray(_ field: inout Array?, map: Map) { + if let objects: Array = Mapper(context: map.context).mapArray(JSONObject: map.currentValue) { + field = objects + } else { + field = nil + } + } + + /// Implicitly unwrapped optional mappable object array + class func optionalObjectArray(_ field: inout Array!, map: Map) { + if let objects: Array = Mapper(context: map.context).mapArray(JSONObject: map.currentValue) { + field = objects + } else { + field = nil + } + } + + /// mappable object array + class func twoDimensionalObjectArray(_ field: inout Array>, map: Map) { + if let objects = Mapper(context: map.context).mapArrayOfArrays(JSONObject: map.currentValue) { + field = objects + } + } + + /// optional mappable 2 dimentional object array + class func optionalTwoDimensionalObjectArray(_ field: inout Array>?, map: Map) { + field = Mapper(context: map.context).mapArrayOfArrays(JSONObject: map.currentValue) + } + + /// Implicitly unwrapped optional 2 dimentional mappable object array + class func optionalTwoDimensionalObjectArray(_ field: inout Array>!, map: Map) { + field = Mapper(context: map.context).mapArrayOfArrays(JSONObject: map.currentValue) + } + + /// Dctionary containing Mappable objects + class func objectDictionary(_ field: inout Dictionary, map: Map) { + if map.toObject { + field = Mapper(context: map.context).mapDictionary(JSONObject: map.currentValue, toDictionary: field) + } else { + if let objects = Mapper(context: map.context).mapDictionary(JSONObject: map.currentValue) { + field = objects + } + } + } + + /// Optional dictionary containing Mappable objects + class func optionalObjectDictionary(_ field: inout Dictionary?, map: Map) { + if let f = field , map.toObject && map.currentValue != nil { + field = Mapper(context: map.context).mapDictionary(JSONObject: map.currentValue, toDictionary: f) + } else { + field = Mapper(context: map.context).mapDictionary(JSONObject: map.currentValue) + } + } + + /// Implicitly unwrapped Dictionary containing Mappable objects + class func optionalObjectDictionary(_ field: inout Dictionary!, map: Map) { + if let f = field , map.toObject && map.currentValue != nil { + field = Mapper(context: map.context).mapDictionary(JSONObject: map.currentValue, toDictionary: f) + } else { + field = Mapper(context: map.context).mapDictionary(JSONObject: map.currentValue) + } + } + + /// Dictionary containing Array of Mappable objects + class func objectDictionaryOfArrays(_ field: inout Dictionary, map: Map) { + if let objects = Mapper(context: map.context).mapDictionaryOfArrays(JSONObject: map.currentValue) { + field = objects + } + } + + /// Optional Dictionary containing Array of Mappable objects + class func optionalObjectDictionaryOfArrays(_ field: inout Dictionary?, map: Map) { + field = Mapper(context: map.context).mapDictionaryOfArrays(JSONObject: map.currentValue) + } + + /// Implicitly unwrapped Dictionary containing Array of Mappable objects + class func optionalObjectDictionaryOfArrays(_ field: inout Dictionary!, map: Map) { + field = Mapper(context: map.context).mapDictionaryOfArrays(JSONObject: map.currentValue) + } + + /// mappable object Set + class func objectSet(_ field: inout Set, map: Map) { + if let objects = Mapper(context: map.context).mapSet(JSONObject: map.currentValue) { + field = objects + } + } + + /// optional mappable object array + class func optionalObjectSet(_ field: inout Set?, map: Map) { + field = Mapper(context: map.context).mapSet(JSONObject: map.currentValue) + } + + /// Implicitly unwrapped optional mappable object array + class func optionalObjectSet(_ field: inout Set!, map: Map) { + field = Mapper(context: map.context).mapSet(JSONObject: map.currentValue) + } +} diff --git a/Pods/ObjectMapper/Sources/HexColorTransform.swift b/Pods/ObjectMapper/Sources/HexColorTransform.swift new file mode 100644 index 0000000..dd9299f --- /dev/null +++ b/Pods/ObjectMapper/Sources/HexColorTransform.swift @@ -0,0 +1,126 @@ +// +// HexColorTransform.swift +// ObjectMapper +// +// Created by Vitaliy Kuzmenko on 10/10/16. +// Copyright © 2016 hearst. All rights reserved. +// + +#if os(iOS) || os(tvOS) || os(watchOS) +import UIKit +#elseif os(macOS) +import Cocoa +#endif + +#if os(iOS) || os(tvOS) || os(watchOS) || os(macOS) +open class HexColorTransform: TransformType { + + #if os(iOS) || os(tvOS) || os(watchOS) + public typealias Object = UIColor + #else + public typealias Object = NSColor + #endif + + public typealias JSON = String + + var prefix: Bool = false + + var alpha: Bool = false + + public init(prefixToJSON: Bool = false, alphaToJSON: Bool = false) { + alpha = alphaToJSON + prefix = prefixToJSON + } + + open func transformFromJSON(_ value: Any?) -> Object? { + if let rgba = value as? String { + if rgba.hasPrefix("#") { + let index = rgba.characters.index(rgba.startIndex, offsetBy: 1) + let hex = rgba.substring(from: index) + return getColor(hex: hex) + } else { + return getColor(hex: rgba) + } + } + return nil + } + + open func transformToJSON(_ value: Object?) -> JSON? { + if let value = value { + return hexString(color: value) + } + return nil + } + + fileprivate func hexString(color: Object) -> String { + let comps = color.cgColor.components! + let compsCount = color.cgColor.numberOfComponents + let r: Int + let g: Int + var b: Int + let a = Int(comps[compsCount - 1] * 255) + if compsCount == 4 { // RGBA + r = Int(comps[0] * 255) + g = Int(comps[1] * 255) + b = Int(comps[2] * 255) + } else { // Grayscale + r = Int(comps[0] * 255) + g = Int(comps[0] * 255) + b = Int(comps[0] * 255) + } + var hexString: String = "" + if prefix { + hexString = "#" + } + hexString += String(format: "%02X%02X%02X", r, g, b) + + if alpha { + hexString += String(format: "%02X", a) + } + return hexString + } + + fileprivate func getColor(hex: String) -> Object? { + var red: CGFloat = 0.0 + var green: CGFloat = 0.0 + var blue: CGFloat = 0.0 + var alpha: CGFloat = 1.0 + + let scanner = Scanner(string: hex) + var hexValue: CUnsignedLongLong = 0 + if scanner.scanHexInt64(&hexValue) { + switch (hex.characters.count) { + case 3: + red = CGFloat((hexValue & 0xF00) >> 8) / 15.0 + green = CGFloat((hexValue & 0x0F0) >> 4) / 15.0 + blue = CGFloat(hexValue & 0x00F) / 15.0 + case 4: + red = CGFloat((hexValue & 0xF000) >> 12) / 15.0 + green = CGFloat((hexValue & 0x0F00) >> 8) / 15.0 + blue = CGFloat((hexValue & 0x00F0) >> 4) / 15.0 + alpha = CGFloat(hexValue & 0x000F) / 15.0 + case 6: + red = CGFloat((hexValue & 0xFF0000) >> 16) / 255.0 + green = CGFloat((hexValue & 0x00FF00) >> 8) / 255.0 + blue = CGFloat(hexValue & 0x0000FF) / 255.0 + case 8: + red = CGFloat((hexValue & 0xFF000000) >> 24) / 255.0 + green = CGFloat((hexValue & 0x00FF0000) >> 16) / 255.0 + blue = CGFloat((hexValue & 0x0000FF00) >> 8) / 255.0 + alpha = CGFloat(hexValue & 0x000000FF) / 255.0 + default: + // Invalid RGB string, number of characters after '#' should be either 3, 4, 6 or 8 + return nil + } + } else { + // "Scan hex error + return nil + } + #if os(iOS) || os(tvOS) || os(watchOS) + return UIColor(red: red, green: green, blue: blue, alpha: alpha) + #else + return NSColor(calibratedRed: red, green: green, blue: blue, alpha: alpha) + #endif + } +} +#endif diff --git a/Pods/ObjectMapper/Sources/ISO8601DateTransform.swift b/Pods/ObjectMapper/Sources/ISO8601DateTransform.swift new file mode 100644 index 0000000..2200423 --- /dev/null +++ b/Pods/ObjectMapper/Sources/ISO8601DateTransform.swift @@ -0,0 +1,47 @@ +// +// ISO8601DateTransform.swift +// ObjectMapper +// +// Created by Jean-Pierre Mouilleseaux on 21 Nov 2014. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Hearst +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +public extension DateFormatter { + public convenience init(withFormat format : String, locale : String) { + self.init() + self.locale = Locale(identifier: locale) + dateFormat = format + } +} + +open class ISO8601DateTransform: DateFormatterTransform { + + static let reusableISODateFormatter = DateFormatter(withFormat: "yyyy-MM-dd'T'HH:mm:ssZZZZZ", locale: "en_US_POSIX") + + public init() { + super.init(dateFormatter: ISO8601DateTransform.reusableISODateFormatter) + } +} + diff --git a/Pods/ObjectMapper/Sources/ImmutableMappable.swift b/Pods/ObjectMapper/Sources/ImmutableMappable.swift new file mode 100644 index 0000000..46ce555 --- /dev/null +++ b/Pods/ObjectMapper/Sources/ImmutableMappable.swift @@ -0,0 +1,315 @@ +// +// ImmutableMappble.swift +// ObjectMapper +// +// Created by Suyeol Jeon on 23/09/2016. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Hearst +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +public protocol ImmutableMappable: BaseMappable { + init(map: Map) throws +} + +public extension ImmutableMappable { + + /// Implement this method to support object -> JSON transform. + public func mapping(map: Map) {} + + /// Initializes object from a JSON String + public init(JSONString: String, context: MapContext? = nil) throws { + self = try Mapper(context: context).map(JSONString: JSONString) + } + + /// Initializes object from a JSON Dictionary + public init(JSON: [String: Any], context: MapContext? = nil) throws { + self = try Mapper(context: context).map(JSON: JSON) + } + + /// Initializes object from a JSONObject + public init(JSONObject: Any, context: MapContext? = nil) throws { + self = try Mapper(context: context).map(JSONObject: JSONObject) + } + +} + +public extension Map { + + fileprivate func currentValue(for key: String, nested: Bool? = nil, delimiter: String = ".") -> Any? { + let isNested = nested ?? key.contains(delimiter) + return self[key, nested: isNested, delimiter: delimiter].currentValue + } + + // MARK: Basic + + /// Returns a value or throws an error. + public func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> T { + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let value = currentValue as? T else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '\(T.self)'", file: file, function: function, line: line) + } + return value + } + + /// Returns a transformed value or throws an error. + public func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", using transform: Transform, file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> Transform.Object { + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let value = transform.transformFromJSON(currentValue) else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot transform to '\(Transform.Object.self)' using \(transform)", file: file, function: function, line: line) + } + return value + } + + /// Returns a RawRepresentable type or throws an error. + public func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> T { + return try self.value(key, nested: nested, delimiter: delimiter, using: EnumTransform(), file: file, function: function, line: line) + } + + /// Returns a `[RawRepresentable]` type or throws an error. + public func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> [T] { + return try self.value(key, nested: nested, delimiter: delimiter, using: EnumTransform(), file: file, function: function, line: line) + } + + // MARK: BaseMappable + + /// Returns a `BaseMappable` object or throws an error. + public func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> T { + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let JSONObject = currentValue else { + throw MapError(key: key, currentValue: currentValue, reason: "Found unexpected nil value", file: file, function: function, line: line) + } + return try Mapper(context: context).mapOrFail(JSONObject: JSONObject) + } + + // MARK: [BaseMappable] + + /// Returns a `[BaseMappable]` or throws an error. + public func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> [T] { + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let jsonArray = currentValue as? [Any] else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '[Any]'", file: file, function: function, line: line) + } + return try jsonArray.enumerated().map { i, JSONObject -> T in + return try Mapper(context: context).mapOrFail(JSONObject: JSONObject) + } + } + + /// Returns a `[BaseMappable]` using transform or throws an error. + public func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", using transform: Transform, file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> [Transform.Object] { + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let jsonArray = currentValue as? [Any] else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '[Any]'", file: file, function: function, line: line) + } + return try jsonArray.enumerated().map { i, json -> Transform.Object in + guard let object = transform.transformFromJSON(json) else { + throw MapError(key: "\(key)[\(i)]", currentValue: json, reason: "Cannot transform to '\(Transform.Object.self)' using \(transform)", file: file, function: function, line: line) + } + return object + } + } + + // MARK: [String: BaseMappable] + + /// Returns a `[String: BaseMappable]` or throws an error. + public func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> [String: T] { + + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let jsonDictionary = currentValue as? [String: Any] else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '[String: Any]'", file: file, function: function, line: line) + } + var value: [String: T] = [:] + for (key, json) in jsonDictionary { + value[key] = try Mapper(context: context).mapOrFail(JSONObject: json) + } + return value + } + + /// Returns a `[String: BaseMappable]` using transform or throws an error. + public func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", using transform: Transform, file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> [String: Transform.Object] { + + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let jsonDictionary = currentValue as? [String: Any] else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '[String: Any]'", file: file, function: function, line: line) + } + var value: [String: Transform.Object] = [:] + for (key, json) in jsonDictionary { + guard let object = transform.transformFromJSON(json) else { + throw MapError(key: key, currentValue: json, reason: "Cannot transform to '\(Transform.Object.self)' using \(transform)", file: file, function: function, line: line) + } + value[key] = object + } + return value + } + + // MARK: [[BaseMappable]] + /// Returns a `[[BaseMappable]]` or throws an error. + public func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> [[T]] { + + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let json2DArray = currentValue as? [[Any]] else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '[[Any]]'", file: file, function: function, line: line) + } + return try json2DArray.map { jsonArray in + try jsonArray.map { jsonObject -> T in + return try Mapper(context: context).mapOrFail(JSONObject: jsonObject) + } + } + } + + /// Returns a `[[BaseMappable]]` using transform or throws an error. + public func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", using transform: Transform, file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> [[Transform.Object]] { + + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let json2DArray = currentValue as? [[Any]] else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '[[Any]]'", + file: file, function: function, line: line) + } + return try json2DArray.enumerated().map { i, jsonArray in + try jsonArray.enumerated().map { j, json -> Transform.Object in + guard let object = transform.transformFromJSON(json) else { + throw MapError(key: "\(key)[\(i)][\(j)]", currentValue: json, reason: "Cannot transform to '\(Transform.Object.self)' using \(transform)", file: file, function: function, line: line) + } + return object + } + } + } + +} + +public extension Mapper where N: ImmutableMappable { + + public func map(JSON: [String: Any]) throws -> N { + return try self.mapOrFail(JSON: JSON) + } + + public func map(JSONString: String) throws -> N { + return try mapOrFail(JSONString: JSONString) + } + + public func map(JSONObject: Any) throws -> N { + return try mapOrFail(JSONObject: JSONObject) + } + + // MARK: Array mapping functions + + public func mapArray(JSONArray: [[String: Any]]) throws -> [N] { + return try JSONArray.flatMap(mapOrFail) + } + + public func mapArray(JSONString: String) throws -> [N] { + guard let JSONObject = Mapper.parseJSONString(JSONString: JSONString) else { + throw MapError(key: nil, currentValue: JSONString, reason: "Cannot convert string into Any'") + } + + return try mapArray(JSONObject: JSONObject) + } + + public func mapArray(JSONObject: Any) throws -> [N] { + guard let JSONArray = JSONObject as? [[String: Any]] else { + throw MapError(key: nil, currentValue: JSONObject, reason: "Cannot cast to '[[String: Any]]'") + } + + return try mapArray(JSONArray: JSONArray) + } + + // MARK: Dictionary mapping functions + + public func mapDictionary(JSONString: String) throws -> [String: N] { + guard let JSONObject = Mapper.parseJSONString(JSONString: JSONString) else { + throw MapError(key: nil, currentValue: JSONString, reason: "Cannot convert string into Any'") + } + + return try mapDictionary(JSONObject: JSONObject) + } + + public func mapDictionary(JSONObject: Any?) throws -> [String: N] { + guard let JSON = JSONObject as? [String: [String: Any]] else { + throw MapError(key: nil, currentValue: JSONObject, reason: "Cannot cast to '[String: [String: Any]]''") + } + + return try mapDictionary(JSON: JSON) + } + + public func mapDictionary(JSON: [String: [String: Any]]) throws -> [String: N] { + return try JSON.filterMap(mapOrFail) + } + + // MARK: Dictinoary of arrays mapping functions + + public func mapDictionaryOfArrays(JSONObject: Any?) throws -> [String: [N]] { + guard let JSON = JSONObject as? [String: [[String: Any]]] else { + throw MapError(key: nil, currentValue: JSONObject, reason: "Cannot cast to '[String: [String: Any]]''") + } + return try mapDictionaryOfArrays(JSON: JSON) + } + + public func mapDictionaryOfArrays(JSON: [String: [[String: Any]]]) throws -> [String: [N]] { + return try JSON.filterMap { array -> [N] in + try mapArray(JSONArray: array) + } + } + + // MARK: 2 dimentional array mapping functions + + public func mapArrayOfArrays(JSONObject: Any?) throws -> [[N]] { + guard let JSONArray = JSONObject as? [[[String: Any]]] else { + throw MapError(key: nil, currentValue: JSONObject, reason: "Cannot cast to '[[[String: Any]]]''") + } + return try JSONArray.map(mapArray) + } + +} + +internal extension Mapper { + + internal func mapOrFail(JSON: [String: Any]) throws -> N { + let map = Map(mappingType: .fromJSON, JSON: JSON, context: context, shouldIncludeNilValues: shouldIncludeNilValues) + + // Check if object is ImmutableMappable, if so use ImmutableMappable protocol for mapping + if let klass = N.self as? ImmutableMappable.Type, + var object = try klass.init(map: map) as? N { + object.mapping(map: map) + return object + } + + // If not, map the object the standard way + guard let value = self.map(JSON: JSON) else { + throw MapError(key: nil, currentValue: JSON, reason: "Cannot map to '\(N.self)'") + } + return value + } + + internal func mapOrFail(JSONString: String) throws -> N { + guard let JSON = Mapper.parseJSONStringIntoDictionary(JSONString: JSONString) else { + throw MapError(key: nil, currentValue: JSONString, reason: "Cannot parse into '[String: Any]'") + } + return try mapOrFail(JSON: JSON) + } + + internal func mapOrFail(JSONObject: Any) throws -> N { + guard let JSON = JSONObject as? [String: Any] else { + throw MapError(key: nil, currentValue: JSONObject, reason: "Cannot cast to '[String: Any]'") + } + return try mapOrFail(JSON: JSON) + } + +} diff --git a/Pods/ObjectMapper/Sources/IntegerOperators.swift b/Pods/ObjectMapper/Sources/IntegerOperators.swift new file mode 100644 index 0000000..269c3bc --- /dev/null +++ b/Pods/ObjectMapper/Sources/IntegerOperators.swift @@ -0,0 +1,145 @@ +// +// IntegerOperators.swift +// ObjectMapper +// +// Created by Suyeol Jeon on 17/02/2017. +// Copyright © 2017 hearst. All rights reserved. +// + +import Foundation + +// MARK: - Signed Integer + +/// SignedInteger mapping +public func <- (left: inout T, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + let value: T = toSignedInteger(right.currentValue) ?? 0 + FromJSON.basicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + +/// Optional SignedInteger mapping +public func <- (left: inout T?, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + let value: T? = toSignedInteger(right.currentValue) + FromJSON.basicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + +/// ImplicitlyUnwrappedOptional SignedInteger mapping +public func <- (left: inout T!, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + let value: T! = toSignedInteger(right.currentValue) + FromJSON.basicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + + +// MARK: - Unsigned Integer + +/// UnsignedInteger mapping +public func <- (left: inout T, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + let value: T = toUnsignedInteger(right.currentValue) ?? 0 + FromJSON.basicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + + +/// Optional UnsignedInteger mapping +public func <- (left: inout T?, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + let value: T? = toUnsignedInteger(right.currentValue) + FromJSON.basicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + +/// ImplicitlyUnwrappedOptional UnsignedInteger mapping +public func <- (left: inout T!, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + let value: T! = toUnsignedInteger(right.currentValue) + FromJSON.basicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + +// MARK: - Casting Utils + +/// Convert any value to `SignedInteger`. +private func toSignedInteger(_ value: Any?) -> T? { + guard + let value = value, + case let number as NSNumber = value + else { + return nil + } + + if T.self == Int.self, let x = Int(exactly: number.int64Value)?.toIntMax() { + return T.init(x) + } + if T.self == Int8.self, let x = Int8(exactly: number.int64Value)?.toIntMax() { + return T.init(x) + } + if T.self == Int16.self, let x = Int16(exactly: number.int64Value)?.toIntMax() { + return T.init(x) + } + if T.self == Int32.self, let x = Int32(exactly: number.int64Value)?.toIntMax() { + return T.init(x) + } + if T.self == Int64.self, let x = Int64(exactly: number.int64Value)?.toIntMax() { + return T.init(x) + } + + return nil +} + +/// Convert any value to `UnsignedInteger`. +private func toUnsignedInteger(_ value: Any?) -> T? { + guard + let value = value, + case let number as NSNumber = value + else { + return nil + } + + if T.self == UInt.self, let x = UInt(exactly: number.uint64Value)?.toUIntMax() { + return T.init(x) + } + if T.self == UInt8.self, let x = UInt8(exactly: number.uint64Value)?.toUIntMax() { + return T.init(x) + } + if T.self == UInt16.self, let x = UInt16(exactly: number.uint64Value)?.toUIntMax() { + return T.init(x) + } + if T.self == UInt32.self, let x = UInt32(exactly: number.uint64Value)?.toUIntMax() { + return T.init(x) + } + if T.self == UInt64.self, let x = UInt64(exactly: number.uint64Value)?.toUIntMax() { + return T.init(x) + } + + return nil +} diff --git a/Pods/ObjectMapper/Sources/Map.swift b/Pods/ObjectMapper/Sources/Map.swift new file mode 100644 index 0000000..c7e7a5e --- /dev/null +++ b/Pods/ObjectMapper/Sources/Map.swift @@ -0,0 +1,181 @@ +// +// Map.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2015-10-09. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Hearst +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +import Foundation + +/// MapContext is available for developers who wish to pass information around during the mapping process. +public protocol MapContext { + +} + +/// A class used for holding mapping data +public final class Map { + public let mappingType: MappingType + + public internal(set) var JSON: [String: Any] = [:] + public internal(set) var isKeyPresent = false + public internal(set) var currentValue: Any? + public internal(set) var currentKey: String? + var keyIsNested = false + public internal(set) var nestedKeyDelimiter: String = "." + public var context: MapContext? + public var shouldIncludeNilValues = false /// If this is set to true, toJSON output will include null values for any variables that are not set. + + public let toObject: Bool // indicates whether the mapping is being applied to an existing object + + public init(mappingType: MappingType, JSON: [String: Any], toObject: Bool = false, context: MapContext? = nil, shouldIncludeNilValues: Bool = false) { + + self.mappingType = mappingType + self.JSON = JSON + self.toObject = toObject + self.context = context + self.shouldIncludeNilValues = shouldIncludeNilValues + } + + /// Sets the current mapper value and key. + /// The Key paramater can be a period separated string (ex. "distance.value") to access sub objects. + public subscript(key: String) -> Map { + // save key and value associated to it + return self[key, delimiter: ".", ignoreNil: false] + } + + public subscript(key: String, delimiter delimiter: String) -> Map { + let nested = key.contains(delimiter) + return self[key, nested: nested, delimiter: delimiter, ignoreNil: false] + } + + public subscript(key: String, nested nested: Bool) -> Map { + return self[key, nested: nested, delimiter: ".", ignoreNil: false] + } + + public subscript(key: String, nested nested: Bool, delimiter delimiter: String) -> Map { + return self[key, nested: nested, delimiter: delimiter, ignoreNil: false] + } + + public subscript(key: String, ignoreNil ignoreNil: Bool) -> Map { + return self[key, delimiter: ".", ignoreNil: ignoreNil] + } + + public subscript(key: String, delimiter delimiter: String, ignoreNil ignoreNil: Bool) -> Map { + let nested = key.contains(delimiter) + return self[key, nested: nested, delimiter: delimiter, ignoreNil: ignoreNil] + } + + public subscript(key: String, nested nested: Bool, ignoreNil ignoreNil: Bool) -> Map { + return self[key, nested: nested, delimiter: ".", ignoreNil: ignoreNil] + } + + public subscript(key: String, nested nested: Bool, delimiter delimiter: String, ignoreNil ignoreNil: Bool) -> Map { + // save key and value associated to it + currentKey = key + keyIsNested = nested + nestedKeyDelimiter = delimiter + + if mappingType == .fromJSON { + // check if a value exists for the current key + // do this pre-check for performance reasons + if nested == false { + let object = JSON[key] + let isNSNull = object is NSNull + isKeyPresent = isNSNull ? true : object != nil + currentValue = isNSNull ? nil : object + } else { + // break down the components of the key that are separated by . + (isKeyPresent, currentValue) = valueFor(ArraySlice(key.components(separatedBy: delimiter)), dictionary: JSON) + } + + // update isKeyPresent if ignoreNil is true + if ignoreNil && currentValue == nil { + isKeyPresent = false + } + } + + return self + } + + public func value() -> T? { + return currentValue as? T + } + +} + +/// Fetch value from JSON dictionary, loop through keyPathComponents until we reach the desired object +private func valueFor(_ keyPathComponents: ArraySlice, dictionary: [String: Any]) -> (Bool, Any?) { + // Implement it as a tail recursive function. + if keyPathComponents.isEmpty { + return (false, nil) + } + + if let keyPath = keyPathComponents.first { + let object = dictionary[keyPath] + if object is NSNull { + return (true, nil) + } else if keyPathComponents.count > 1, let dict = object as? [String: Any] { + let tail = keyPathComponents.dropFirst() + return valueFor(tail, dictionary: dict) + } else if keyPathComponents.count > 1, let array = object as? [Any] { + let tail = keyPathComponents.dropFirst() + return valueFor(tail, array: array) + } else { + return (object != nil, object) + } + } + + return (false, nil) +} + +/// Fetch value from JSON Array, loop through keyPathComponents them until we reach the desired object +private func valueFor(_ keyPathComponents: ArraySlice, array: [Any]) -> (Bool, Any?) { + // Implement it as a tail recursive function. + + if keyPathComponents.isEmpty { + return (false, nil) + } + + //Try to convert keypath to Int as index + if let keyPath = keyPathComponents.first, + let index = Int(keyPath) , index >= 0 && index < array.count { + + let object = array[index] + + if object is NSNull { + return (true, nil) + } else if keyPathComponents.count > 1, let array = object as? [Any] { + let tail = keyPathComponents.dropFirst() + return valueFor(tail, array: array) + } else if keyPathComponents.count > 1, let dict = object as? [String: Any] { + let tail = keyPathComponents.dropFirst() + return valueFor(tail, dictionary: dict) + } else { + return (true, object) + } + } + + return (false, nil) +} diff --git a/Pods/ObjectMapper/Sources/MapError.swift b/Pods/ObjectMapper/Sources/MapError.swift new file mode 100644 index 0000000..21e20cb --- /dev/null +++ b/Pods/ObjectMapper/Sources/MapError.swift @@ -0,0 +1,68 @@ +// +// MapError.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2016-09-26. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Hearst +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +public struct MapError: Error { + public var key: String? + public var currentValue: Any? + public var reason: String? + public var file: StaticString? + public var function: StaticString? + public var line: UInt? + + public init(key: String?, currentValue: Any?, reason: String?, file: StaticString? = nil, function: StaticString? = nil, line: UInt? = nil) { + self.key = key + self.currentValue = currentValue + self.reason = reason + self.file = file + self.function = function + self.line = line + } +} + +extension MapError: CustomStringConvertible { + + private var location: String? { + guard let file = file, let function = function, let line = line else { return nil } + let fileName = ((String(describing: file).components(separatedBy: "/").last ?? "").components(separatedBy: ".").first ?? "") + return "\(fileName).\(function):\(line)" + } + + public var description: String { + let info: [(String, Any?)] = [ + ("- reason", reason), + ("- location", location), + ("- key", key), + ("- currentValue", currentValue), + ] + let infoString = info.map { "\($0): \($1 ?? "nil")" }.joined(separator: "\n") + return "Got an error while mapping.\n\(infoString)" + } + +} diff --git a/Pods/ObjectMapper/Sources/Mappable.swift b/Pods/ObjectMapper/Sources/Mappable.swift new file mode 100644 index 0000000..ac5d71d --- /dev/null +++ b/Pods/ObjectMapper/Sources/Mappable.swift @@ -0,0 +1,136 @@ +// +// Mappable.swift +// ObjectMapper +// +// Created by Scott Hoyt on 10/25/15. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Hearst +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// BaseMappable should not be implemented directly. Mappable or StaticMappable should be used instead +public protocol BaseMappable { + /// This function is where all variable mappings should occur. It is executed by Mapper during the mapping (serialization and deserialization) process. + mutating func mapping(map: Map) +} + +public protocol Mappable: BaseMappable { + /// This function can be used to validate JSON prior to mapping. Return nil to cancel mapping at this point + init?(map: Map) +} + +public protocol StaticMappable: BaseMappable { + /// This is function that can be used to: + /// 1) provide an existing cached object to be used for mapping + /// 2) return an object of another class (which conforms to BaseMappable) to be used for mapping. For instance, you may inspect the JSON to infer the type of object that should be used for any given mapping + static func objectForMapping(map: Map) -> BaseMappable? +} + +public extension BaseMappable { + + /// Initializes object from a JSON String + public init?(JSONString: String, context: MapContext? = nil) { + if let obj: Self = Mapper(context: context).map(JSONString: JSONString) { + self = obj + } else { + return nil + } + } + + /// Initializes object from a JSON Dictionary + public init?(JSON: [String: Any], context: MapContext? = nil) { + if let obj: Self = Mapper(context: context).map(JSON: JSON) { + self = obj + } else { + return nil + } + } + + /// Returns the JSON Dictionary for the object + public func toJSON() -> [String: Any] { + return Mapper().toJSON(self) + } + + /// Returns the JSON String for the object + public func toJSONString(prettyPrint: Bool = false) -> String? { + return Mapper().toJSONString(self, prettyPrint: prettyPrint) + } +} + +public extension Array where Element: BaseMappable { + + /// Initialize Array from a JSON String + public init?(JSONString: String, context: MapContext? = nil) { + if let obj: [Element] = Mapper(context: context).mapArray(JSONString: JSONString) { + self = obj + } else { + return nil + } + } + + /// Initialize Array from a JSON Array + public init(JSONArray: [[String: Any]], context: MapContext? = nil) { + let obj: [Element] = Mapper(context: context).mapArray(JSONArray: JSONArray) + self = obj + } + + /// Returns the JSON Array + public func toJSON() -> [[String: Any]] { + return Mapper().toJSONArray(self) + } + + /// Returns the JSON String for the object + public func toJSONString(prettyPrint: Bool = false) -> String? { + return Mapper().toJSONString(self, prettyPrint: prettyPrint) + } +} + +public extension Set where Element: BaseMappable { + + /// Initializes a set from a JSON String + public init?(JSONString: String, context: MapContext? = nil) { + if let obj: Set = Mapper(context: context).mapSet(JSONString: JSONString) { + self = obj + } else { + return nil + } + } + + /// Initializes a set from JSON + public init?(JSONArray: [[String: Any]], context: MapContext? = nil) { + guard let obj = Mapper(context: context).mapSet(JSONArray: JSONArray) as Set? else { + return nil + } + self = obj + } + + /// Returns the JSON Set + public func toJSON() -> [[String: Any]] { + return Mapper().toJSONSet(self) + } + + /// Returns the JSON String for the object + public func toJSONString(prettyPrint: Bool = false) -> String? { + return Mapper().toJSONString(self, prettyPrint: prettyPrint) + } +} diff --git a/Pods/ObjectMapper/Sources/Mapper.swift b/Pods/ObjectMapper/Sources/Mapper.swift new file mode 100755 index 0000000..b3cd984 --- /dev/null +++ b/Pods/ObjectMapper/Sources/Mapper.swift @@ -0,0 +1,446 @@ +// +// Mapper.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2014-10-09. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Hearst +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +public enum MappingType { + case fromJSON + case toJSON +} + +/// The Mapper class provides methods for converting Model objects to JSON and methods for converting JSON to Model objects +public final class Mapper { + + public var context: MapContext? + public var shouldIncludeNilValues = false /// If this is set to true, toJSON output will include null values for any variables that are not set. + + public init(context: MapContext? = nil, shouldIncludeNilValues: Bool = false){ + self.context = context + self.shouldIncludeNilValues = shouldIncludeNilValues + } + + // MARK: Mapping functions that map to an existing object toObject + + /// Maps a JSON object to an existing Mappable object if it is a JSON dictionary, or returns the passed object as is + public func map(JSONObject: Any?, toObject object: N) -> N { + if let JSON = JSONObject as? [String: Any] { + return map(JSON: JSON, toObject: object) + } + + return object + } + + /// Map a JSON string onto an existing object + public func map(JSONString: String, toObject object: N) -> N { + if let JSON = Mapper.parseJSONStringIntoDictionary(JSONString: JSONString) { + return map(JSON: JSON, toObject: object) + } + return object + } + + /// Maps a JSON dictionary to an existing object that conforms to Mappable. + /// Usefull for those pesky objects that have crappy designated initializers like NSManagedObject + public func map(JSON: [String: Any], toObject object: N) -> N { + var mutableObject = object + let map = Map(mappingType: .fromJSON, JSON: JSON, toObject: true, context: context, shouldIncludeNilValues: shouldIncludeNilValues) + mutableObject.mapping(map: map) + return mutableObject + } + + //MARK: Mapping functions that create an object + + /// Map a JSON string to an object that conforms to Mappable + public func map(JSONString: String) -> N? { + if let JSON = Mapper.parseJSONStringIntoDictionary(JSONString: JSONString) { + return map(JSON: JSON) + } + + return nil + } + + /// Maps a JSON object to a Mappable object if it is a JSON dictionary or NSString, or returns nil. + public func map(JSONObject: Any?) -> N? { + if let JSON = JSONObject as? [String: Any] { + return map(JSON: JSON) + } + + return nil + } + + /// Maps a JSON dictionary to an object that conforms to Mappable + public func map(JSON: [String: Any]) -> N? { + let map = Map(mappingType: .fromJSON, JSON: JSON, context: context, shouldIncludeNilValues: shouldIncludeNilValues) + + if let klass = N.self as? StaticMappable.Type { // Check if object is StaticMappable + if var object = klass.objectForMapping(map: map) as? N { + object.mapping(map: map) + return object + } + } else if let klass = N.self as? Mappable.Type { // Check if object is Mappable + if var object = klass.init(map: map) as? N { + object.mapping(map: map) + return object + } + } else if let klass = N.self as? ImmutableMappable.Type { // Check if object is ImmutableMappable + do { + return try klass.init(map: map) as? N + } catch let error { + #if DEBUG + let exception: NSException + if let mapError = error as? MapError { + exception = NSException(name: .init(rawValue: "MapError"), reason: mapError.description, userInfo: nil) + } else { + exception = NSException(name: .init(rawValue: "ImmutableMappableError"), reason: error.localizedDescription, userInfo: nil) + } + exception.raise() + #else + NSLog("\(error)") + #endif + } + } else { + // Ensure BaseMappable is not implemented directly + assert(false, "BaseMappable should not be implemented directly. Please implement Mappable, StaticMappable or ImmutableMappable") + } + + return nil + } + + // MARK: Mapping functions for Arrays and Dictionaries + + /// Maps a JSON array to an object that conforms to Mappable + public func mapArray(JSONString: String) -> [N]? { + let parsedJSON: Any? = Mapper.parseJSONString(JSONString: JSONString) + + if let objectArray = mapArray(JSONObject: parsedJSON) { + return objectArray + } + + // failed to parse JSON into array form + // try to parse it into a dictionary and then wrap it in an array + if let object = map(JSONObject: parsedJSON) { + return [object] + } + + return nil + } + + /// Maps a JSON object to an array of Mappable objects if it is an array of JSON dictionary, or returns nil. + public func mapArray(JSONObject: Any?) -> [N]? { + if let JSONArray = JSONObject as? [[String: Any]] { + return mapArray(JSONArray: JSONArray) + } + + return nil + } + + /// Maps an array of JSON dictionary to an array of Mappable objects + public func mapArray(JSONArray: [[String: Any]]) -> [N] { + // map every element in JSON array to type N + let result = JSONArray.flatMap(map) + return result + } + + /// Maps a JSON object to a dictionary of Mappable objects if it is a JSON dictionary of dictionaries, or returns nil. + public func mapDictionary(JSONString: String) -> [String: N]? { + let parsedJSON: Any? = Mapper.parseJSONString(JSONString: JSONString) + return mapDictionary(JSONObject: parsedJSON) + } + + /// Maps a JSON object to a dictionary of Mappable objects if it is a JSON dictionary of dictionaries, or returns nil. + public func mapDictionary(JSONObject: Any?) -> [String: N]? { + if let JSON = JSONObject as? [String: [String: Any]] { + return mapDictionary(JSON: JSON) + } + + return nil + } + + /// Maps a JSON dictionary of dictionaries to a dictionary of Mappable objects + public func mapDictionary(JSON: [String: [String: Any]]) -> [String: N]? { + // map every value in dictionary to type N + let result = JSON.filterMap(map) + if result.isEmpty == false { + return result + } + + return nil + } + + /// Maps a JSON object to a dictionary of Mappable objects if it is a JSON dictionary of dictionaries, or returns nil. + public func mapDictionary(JSONObject: Any?, toDictionary dictionary: [String: N]) -> [String: N] { + if let JSON = JSONObject as? [String : [String : Any]] { + return mapDictionary(JSON: JSON, toDictionary: dictionary) + } + + return dictionary + } + + /// Maps a JSON dictionary of dictionaries to an existing dictionary of Mappable objects + public func mapDictionary(JSON: [String: [String: Any]], toDictionary dictionary: [String: N]) -> [String: N] { + var mutableDictionary = dictionary + for (key, value) in JSON { + if let object = dictionary[key] { + _ = map(JSON: value, toObject: object) + } else { + mutableDictionary[key] = map(JSON: value) + } + } + + return mutableDictionary + } + + /// Maps a JSON object to a dictionary of arrays of Mappable objects + public func mapDictionaryOfArrays(JSONObject: Any?) -> [String: [N]]? { + if let JSON = JSONObject as? [String: [[String: Any]]] { + return mapDictionaryOfArrays(JSON: JSON) + } + + return nil + } + + ///Maps a JSON dictionary of arrays to a dictionary of arrays of Mappable objects + public func mapDictionaryOfArrays(JSON: [String: [[String: Any]]]) -> [String: [N]]? { + // map every value in dictionary to type N + let result = JSON.filterMap { + mapArray(JSONArray: $0) + } + + if result.isEmpty == false { + return result + } + + return nil + } + + /// Maps an 2 dimentional array of JSON dictionaries to a 2 dimentional array of Mappable objects + public func mapArrayOfArrays(JSONObject: Any?) -> [[N]]? { + if let JSONArray = JSONObject as? [[[String: Any]]] { + var objectArray = [[N]]() + for innerJSONArray in JSONArray { + let array = mapArray(JSONArray: innerJSONArray) + objectArray.append(array) + } + + if objectArray.isEmpty == false { + return objectArray + } + } + + return nil + } + + // MARK: Utility functions for converting strings to JSON objects + + /// Convert a JSON String into a Dictionary using NSJSONSerialization + public static func parseJSONStringIntoDictionary(JSONString: String) -> [String: Any]? { + let parsedJSON: Any? = Mapper.parseJSONString(JSONString: JSONString) + return parsedJSON as? [String: Any] + } + + /// Convert a JSON String into an Object using NSJSONSerialization + public static func parseJSONString(JSONString: String) -> Any? { + let data = JSONString.data(using: String.Encoding.utf8, allowLossyConversion: true) + if let data = data { + let parsedJSON: Any? + do { + parsedJSON = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) + } catch let error { + print(error) + parsedJSON = nil + } + return parsedJSON + } + + return nil + } +} + +extension Mapper { + + // MARK: Functions that create JSON from objects + + ///Maps an object that conforms to Mappable to a JSON dictionary + public func toJSON(_ object: N) -> [String: Any] { + var mutableObject = object + let map = Map(mappingType: .toJSON, JSON: [:], context: context, shouldIncludeNilValues: shouldIncludeNilValues) + mutableObject.mapping(map: map) + return map.JSON + } + + ///Maps an array of Objects to an array of JSON dictionaries [[String: Any]] + public func toJSONArray(_ array: [N]) -> [[String: Any]] { + return array.map { + // convert every element in array to JSON dictionary equivalent + self.toJSON($0) + } + } + + ///Maps a dictionary of Objects that conform to Mappable to a JSON dictionary of dictionaries. + public func toJSONDictionary(_ dictionary: [String: N]) -> [String: [String: Any]] { + return dictionary.map { k, v in + // convert every value in dictionary to its JSON dictionary equivalent + return (k, self.toJSON(v)) + } + } + + ///Maps a dictionary of Objects that conform to Mappable to a JSON dictionary of dictionaries. + public func toJSONDictionaryOfArrays(_ dictionary: [String: [N]]) -> [String: [[String: Any]]] { + return dictionary.map { k, v in + // convert every value (array) in dictionary to its JSON dictionary equivalent + return (k, self.toJSONArray(v)) + } + } + + /// Maps an Object to a JSON string with option of pretty formatting + public func toJSONString(_ object: N, prettyPrint: Bool = false) -> String? { + let JSONDict = toJSON(object) + + return Mapper.toJSONString(JSONDict as Any, prettyPrint: prettyPrint) + } + + /// Maps an array of Objects to a JSON string with option of pretty formatting + public func toJSONString(_ array: [N], prettyPrint: Bool = false) -> String? { + let JSONDict = toJSONArray(array) + + return Mapper.toJSONString(JSONDict as Any, prettyPrint: prettyPrint) + } + + /// Converts an Object to a JSON string with option of pretty formatting + public static func toJSONString(_ JSONObject: Any, prettyPrint: Bool) -> String? { + let options: JSONSerialization.WritingOptions = prettyPrint ? .prettyPrinted : [] + if let JSON = Mapper.toJSONData(JSONObject, options: options) { + return String(data: JSON, encoding: String.Encoding.utf8) + } + + return nil + } + + /// Converts an Object to JSON data with options + public static func toJSONData(_ JSONObject: Any, options: JSONSerialization.WritingOptions) -> Data? { + if JSONSerialization.isValidJSONObject(JSONObject) { + let JSONData: Data? + do { + JSONData = try JSONSerialization.data(withJSONObject: JSONObject, options: options) + } catch let error { + print(error) + JSONData = nil + } + + return JSONData + } + + return nil + } +} + +extension Mapper where N: Hashable { + + /// Maps a JSON array to an object that conforms to Mappable + public func mapSet(JSONString: String) -> Set? { + let parsedJSON: Any? = Mapper.parseJSONString(JSONString: JSONString) + + if let objectArray = mapArray(JSONObject: parsedJSON) { + return Set(objectArray) + } + + // failed to parse JSON into array form + // try to parse it into a dictionary and then wrap it in an array + if let object = map(JSONObject: parsedJSON) { + return Set([object]) + } + + return nil + } + + /// Maps a JSON object to an Set of Mappable objects if it is an array of JSON dictionary, or returns nil. + public func mapSet(JSONObject: Any?) -> Set? { + if let JSONArray = JSONObject as? [[String: Any]] { + return mapSet(JSONArray: JSONArray) + } + + return nil + } + + /// Maps an Set of JSON dictionary to an array of Mappable objects + public func mapSet(JSONArray: [[String: Any]]) -> Set { + // map every element in JSON array to type N + return Set(JSONArray.flatMap(map)) + } + + ///Maps a Set of Objects to a Set of JSON dictionaries [[String : Any]] + public func toJSONSet(_ set: Set) -> [[String: Any]] { + return set.map { + // convert every element in set to JSON dictionary equivalent + self.toJSON($0) + } + } + + /// Maps a set of Objects to a JSON string with option of pretty formatting + public func toJSONString(_ set: Set, prettyPrint: Bool = false) -> String? { + let JSONDict = toJSONSet(set) + + return Mapper.toJSONString(JSONDict as Any, prettyPrint: prettyPrint) + } +} + +extension Dictionary { + internal func map(_ f: (Element) throws -> (K, V)) rethrows -> [K: V] { + var mapped = [K: V]() + + for element in self { + let newElement = try f(element) + mapped[newElement.0] = newElement.1 + } + + return mapped + } + + internal func map(_ f: (Element) throws -> (K, [V])) rethrows -> [K: [V]] { + var mapped = [K: [V]]() + + for element in self { + let newElement = try f(element) + mapped[newElement.0] = newElement.1 + } + + return mapped + } + + + internal func filterMap(_ f: (Value) throws -> U?) rethrows -> [Key: U] { + var mapped = [Key: U]() + + for (key, value) in self { + if let newValue = try f(value) { + mapped[key] = newValue + } + } + + return mapped + } +} diff --git a/Pods/ObjectMapper/Sources/NSDecimalNumberTransform.swift b/Pods/ObjectMapper/Sources/NSDecimalNumberTransform.swift new file mode 100644 index 0000000..5852135 --- /dev/null +++ b/Pods/ObjectMapper/Sources/NSDecimalNumberTransform.swift @@ -0,0 +1,52 @@ +// +// TransformOf.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 8/22/16. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Hearst +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +open class NSDecimalNumberTransform: TransformType { + public typealias Object = NSDecimalNumber + public typealias JSON = String + + public init() {} + + open func transformFromJSON(_ value: Any?) -> NSDecimalNumber? { + if let string = value as? String { + return NSDecimalNumber(string: string) + } else if let number = value as? NSNumber { + return NSDecimalNumber(decimal: number.decimalValue) + } else if let double = value as? Double { + return NSDecimalNumber(floatLiteral: double) + } + return nil + } + + open func transformToJSON(_ value: NSDecimalNumber?) -> String? { + guard let value = value else { return nil } + return value.description + } +} diff --git a/Pods/ObjectMapper/Sources/Operators.swift b/Pods/ObjectMapper/Sources/Operators.swift new file mode 100755 index 0000000..eb49735 --- /dev/null +++ b/Pods/ObjectMapper/Sources/Operators.swift @@ -0,0 +1,377 @@ +// +// Operators.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2014-10-09. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Hearst +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/** +* This file defines a new operator which is used to create a mapping between an object and a JSON key value. +* There is an overloaded operator definition for each type of object that is supported in ObjectMapper. +* This provides a way to add custom logic to handle specific types of objects +*/ + +/// Operator used for defining mappings to and from JSON +infix operator <- + +/// Operator used to define mappings to JSON +infix operator >>> + +// MARK:- Objects with Basic types + +/// Object of Basic type +public func <- (left: inout T, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.basicType(&left, object: right.value()) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: T, right: Map) { + if right.mappingType == .toJSON { + ToJSON.basicType(left, map: right) + } +} + + +/// Optional object of basic type +public func <- (left: inout T?, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalBasicType(&left, object: right.value()) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: T?, right: Map) { + if right.mappingType == .toJSON { + ToJSON.optionalBasicType(left, map: right) + } +} + + +/// Implicitly unwrapped optional object of basic type +public func <- (left: inout T!, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalBasicType(&left, object: right.value()) + case .toJSON: + left >>> right + default: () + } +} + +// MARK:- Mappable Objects - + +/// Object conforming to Mappable +public func <- (left: inout T, right: Map) { + switch right.mappingType { + case .fromJSON: + FromJSON.object(&left, map: right) + case .toJSON: + left >>> right + } +} + +public func >>> (left: T, right: Map) { + if right.mappingType == .toJSON { + ToJSON.object(left, map: right) + } +} + + +/// Optional Mappable objects +public func <- (left: inout T?, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObject(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: T?, right: Map) { + if right.mappingType == .toJSON { + ToJSON.optionalObject(left, map: right) + } +} + + +/// Implicitly unwrapped optional Mappable objects +public func <- (left: inout T!, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObject(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +// MARK:- Dictionary of Mappable objects - Dictionary + +/// Dictionary of Mappable objects +public func <- (left: inout Dictionary, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.objectDictionary(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Dictionary, right: Map) { + if right.mappingType == .toJSON { + ToJSON.objectDictionary(left, map: right) + } +} + + +/// Optional Dictionary of Mappable object +public func <- (left: inout Dictionary?, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObjectDictionary(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Dictionary?, right: Map) { + if right.mappingType == .toJSON { + ToJSON.optionalObjectDictionary(left, map: right) + } +} + + +/// Implicitly unwrapped Optional Dictionary of Mappable object +public func <- (left: inout Dictionary!, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObjectDictionary(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +/// Dictionary of Mappable objects +public func <- (left: inout Dictionary, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.objectDictionaryOfArrays(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Dictionary, right: Map) { + if right.mappingType == .toJSON { + ToJSON.objectDictionaryOfArrays(left, map: right) + } +} + +/// Optional Dictionary of Mappable object +public func <- (left: inout Dictionary?, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObjectDictionaryOfArrays(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Dictionary?, right: Map) { + if right.mappingType == .toJSON { + ToJSON.optionalObjectDictionaryOfArrays(left, map: right) + } +} + + +/// Implicitly unwrapped Optional Dictionary of Mappable object +public func <- (left: inout Dictionary!, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObjectDictionaryOfArrays(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +// MARK:- Array of Mappable objects - Array + +/// Array of Mappable objects +public func <- (left: inout Array, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.objectArray(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Array, right: Map) { + if right.mappingType == .toJSON { + ToJSON.objectArray(left, map: right) + } +} + +/// Optional array of Mappable objects +public func <- (left: inout Array?, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObjectArray(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Array?, right: Map) { + if right.mappingType == .toJSON { + ToJSON.optionalObjectArray(left, map: right) + } +} + + +/// Implicitly unwrapped Optional array of Mappable objects +public func <- (left: inout Array!, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObjectArray(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +// MARK:- Array of Array of Mappable objects - Array> + +/// Array of Array Mappable objects +public func <- (left: inout Array>, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.twoDimensionalObjectArray(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Array>, right: Map) { + if right.mappingType == .toJSON { + ToJSON.twoDimensionalObjectArray(left, map: right) + } +} + + +/// Optional array of Mappable objects +public func <- (left:inout Array>?, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalTwoDimensionalObjectArray(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Array>?, right: Map) { + if right.mappingType == .toJSON { + ToJSON.optionalTwoDimensionalObjectArray(left, map: right) + } +} + + +/// Implicitly unwrapped Optional array of Mappable objects +public func <- (left: inout Array>!, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalTwoDimensionalObjectArray(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +// MARK:- Set of Mappable objects - Set + +/// Set of Mappable objects +public func <- (left: inout Set, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.objectSet(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Set, right: Map) { + if right.mappingType == .toJSON { + ToJSON.objectSet(left, map: right) + } +} + + +/// Optional Set of Mappable objects +public func <- (left: inout Set?, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObjectSet(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Set?, right: Map) { + if right.mappingType == .toJSON { + ToJSON.optionalObjectSet(left, map: right) + } +} + + +/// Implicitly unwrapped Optional Set of Mappable objects +public func <- (left: inout Set!, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObjectSet(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} diff --git a/Pods/ObjectMapper/Sources/ToJSON.swift b/Pods/ObjectMapper/Sources/ToJSON.swift new file mode 100644 index 0000000..32c3432 --- /dev/null +++ b/Pods/ObjectMapper/Sources/ToJSON.swift @@ -0,0 +1,179 @@ +// +// ToJSON.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2014-10-13. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Hearst +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +private func setValue(_ value: Any, map: Map) { + setValue(value, key: map.currentKey!, checkForNestedKeys: map.keyIsNested, delimiter: map.nestedKeyDelimiter, dictionary: &map.JSON) +} + +private func setValue(_ value: Any, key: String, checkForNestedKeys: Bool, delimiter: String, dictionary: inout [String : Any]) { + if checkForNestedKeys { + let keyComponents = ArraySlice(key.components(separatedBy: delimiter).filter { !$0.isEmpty }.map { $0.characters }) + setValue(value, forKeyPathComponents: keyComponents, dictionary: &dictionary) + } else { + dictionary[key] = value + } +} + +private func setValue(_ value: Any, forKeyPathComponents components: ArraySlice, dictionary: inout [String : Any]) { + if components.isEmpty { + return + } + + let head = components.first! + + if components.count == 1 { + dictionary[String(head)] = value + } else { + var child = dictionary[String(head)] as? [String : Any] + if child == nil { + child = [:] + } + + let tail = components.dropFirst() + setValue(value, forKeyPathComponents: tail, dictionary: &child!) + + dictionary[String(head)] = child + } +} + +internal final class ToJSON { + + class func basicType(_ field: N, map: Map) { + if let x = field as Any? , false + || x is NSNumber // Basic types + || x is Bool + || x is Int + || x is Double + || x is Float + || x is String + || x is NSNull + || x is Array // Arrays + || x is Array + || x is Array + || x is Array + || x is Array + || x is Array + || x is Array + || x is Array> + || x is Dictionary // Dictionaries + || x is Dictionary + || x is Dictionary + || x is Dictionary + || x is Dictionary + || x is Dictionary + || x is Dictionary + { + setValue(x, map: map) + } + } + + class func optionalBasicType(_ field: N?, map: Map) { + if let field = field { + basicType(field, map: map) + } else if map.shouldIncludeNilValues { + basicType(NSNull(), map: map) //If BasicType is nil, emil NSNull into the JSON output + } + } + + class func object(_ field: N, map: Map) { + if let result = Mapper(context: map.context, shouldIncludeNilValues: map.shouldIncludeNilValues).toJSON(field) as Any? { + setValue(result, map: map) + } + } + + class func optionalObject(_ field: N?, map: Map) { + if let field = field { + object(field, map: map) + } + } + + class func objectArray(_ field: Array, map: Map) { + let JSONObjects = Mapper(context: map.context, shouldIncludeNilValues: map.shouldIncludeNilValues).toJSONArray(field) + + setValue(JSONObjects, map: map) + } + + class func optionalObjectArray(_ field: Array?, map: Map) { + if let field = field { + objectArray(field, map: map) + } + } + + class func twoDimensionalObjectArray(_ field: Array>, map: Map) { + var array = [[[String: Any]]]() + for innerArray in field { + let JSONObjects = Mapper(context: map.context, shouldIncludeNilValues: map.shouldIncludeNilValues).toJSONArray(innerArray) + array.append(JSONObjects) + } + setValue(array, map: map) + } + + class func optionalTwoDimensionalObjectArray(_ field: Array>?, map: Map) { + if let field = field { + twoDimensionalObjectArray(field, map: map) + } + } + + class func objectSet(_ field: Set, map: Map) { + let JSONObjects = Mapper(context: map.context, shouldIncludeNilValues: map.shouldIncludeNilValues).toJSONSet(field) + + setValue(JSONObjects, map: map) + } + + class func optionalObjectSet(_ field: Set?, map: Map) { + if let field = field { + objectSet(field, map: map) + } + } + + class func objectDictionary(_ field: Dictionary, map: Map) { + let JSONObjects = Mapper(context: map.context, shouldIncludeNilValues: map.shouldIncludeNilValues).toJSONDictionary(field) + + setValue(JSONObjects, map: map) + } + + class func optionalObjectDictionary(_ field: Dictionary?, map: Map) { + if let field = field { + objectDictionary(field, map: map) + } + } + + class func objectDictionaryOfArrays(_ field: Dictionary, map: Map) { + let JSONObjects = Mapper(context: map.context, shouldIncludeNilValues: map.shouldIncludeNilValues).toJSONDictionaryOfArrays(field) + + setValue(JSONObjects, map: map) + } + + class func optionalObjectDictionaryOfArrays(_ field: Dictionary?, map: Map) { + if let field = field { + objectDictionaryOfArrays(field, map: map) + } + } +} diff --git a/Pods/ObjectMapper/Sources/TransformOf.swift b/Pods/ObjectMapper/Sources/TransformOf.swift new file mode 100644 index 0000000..97056c6 --- /dev/null +++ b/Pods/ObjectMapper/Sources/TransformOf.swift @@ -0,0 +1,48 @@ +// +// TransformOf.swift +// ObjectMapper +// +// Created by Syo Ikeda on 1/23/15. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Hearst +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +open class TransformOf: TransformType { + public typealias Object = ObjectType + public typealias JSON = JSONType + + private let fromJSON: (JSONType?) -> ObjectType? + private let toJSON: (ObjectType?) -> JSONType? + + public init(fromJSON: @escaping(JSONType?) -> ObjectType?, toJSON: @escaping(ObjectType?) -> JSONType?) { + self.fromJSON = fromJSON + self.toJSON = toJSON + } + + open func transformFromJSON(_ value: Any?) -> ObjectType? { + return fromJSON(value as? JSONType) + } + + open func transformToJSON(_ value: ObjectType?) -> JSONType? { + return toJSON(value) + } +} diff --git a/Pods/ObjectMapper/Sources/TransformOperators.swift b/Pods/ObjectMapper/Sources/TransformOperators.swift new file mode 100644 index 0000000..a68f895 --- /dev/null +++ b/Pods/ObjectMapper/Sources/TransformOperators.swift @@ -0,0 +1,617 @@ +// +// TransformOperators.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2016-09-26. +// Copyright © 2016 hearst. All rights reserved. +// + +import Foundation + +// MARK:- Transforms + +/// Object of Basic type with Transform +public func <- (left: inout Transform.Object, right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let value = transform.transformFromJSON(map.currentValue) + FromJSON.basicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Transform.Object, right: (Map, Transform)) { + let (map, transform) = right + if map.mappingType == .toJSON { + let value: Transform.JSON? = transform.transformToJSON(left) + ToJSON.optionalBasicType(value, map: map) + } +} + + +/// Optional object of basic type with Transform +public func <- (left: inout Transform.Object?, right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let value = transform.transformFromJSON(map.currentValue) + FromJSON.optionalBasicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Transform.Object?, right: (Map, Transform)) { + let (map, transform) = right + if map.mappingType == .toJSON { + let value: Transform.JSON? = transform.transformToJSON(left) + ToJSON.optionalBasicType(value, map: map) + } +} + + +/// Implicitly unwrapped optional object of basic type with Transform +public func <- (left: inout Transform.Object!, right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let value = transform.transformFromJSON(map.currentValue) + FromJSON.optionalBasicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + +/// Array of Basic type with Transform +public func <- (left: inout [Transform.Object], right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let values = fromJSONArrayWithTransform(map.currentValue, transform: transform) + FromJSON.basicType(&left, object: values) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: [Transform.Object], right: (Map, Transform)) { + let (map, transform) = right + if map.mappingType == .toJSON{ + let values = toJSONArrayWithTransform(left, transform: transform) + ToJSON.optionalBasicType(values, map: map) + } +} + + +/// Optional array of Basic type with Transform +public func <- (left: inout [Transform.Object]?, right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let values = fromJSONArrayWithTransform(map.currentValue, transform: transform) + FromJSON.optionalBasicType(&left, object: values) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: [Transform.Object]?, right: (Map, Transform)) { + let (map, transform) = right + if map.mappingType == .toJSON { + let values = toJSONArrayWithTransform(left, transform: transform) + ToJSON.optionalBasicType(values, map: map) + } +} + + +/// Implicitly unwrapped optional array of Basic type with Transform +public func <- (left: inout [Transform.Object]!, right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let values = fromJSONArrayWithTransform(map.currentValue, transform: transform) + FromJSON.optionalBasicType(&left, object: values) + case .toJSON: + left >>> right + default: () + } +} + +/// Dictionary of Basic type with Transform +public func <- (left: inout [String: Transform.Object], right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let values = fromJSONDictionaryWithTransform(map.currentValue, transform: transform) + FromJSON.basicType(&left, object: values) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: [String: Transform.Object], right: (Map, Transform)) { + let (map, transform) = right + if map.mappingType == . toJSON { + let values = toJSONDictionaryWithTransform(left, transform: transform) + ToJSON.optionalBasicType(values, map: map) + } +} + + +/// Optional dictionary of Basic type with Transform +public func <- (left: inout [String: Transform.Object]?, right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let values = fromJSONDictionaryWithTransform(map.currentValue, transform: transform) + FromJSON.optionalBasicType(&left, object: values) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: [String: Transform.Object]?, right: (Map, Transform)) { + let (map, transform) = right + if map.mappingType == .toJSON { + let values = toJSONDictionaryWithTransform(left, transform: transform) + ToJSON.optionalBasicType(values, map: map) + } +} + + +/// Implicitly unwrapped optional dictionary of Basic type with Transform +public func <- (left: inout [String: Transform.Object]!, right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let values = fromJSONDictionaryWithTransform(map.currentValue, transform: transform) + FromJSON.optionalBasicType(&left, object: values) + case .toJSON: + left >>> right + default: () + } +} + +// MARK:- Transforms of Mappable Objects - + +/// Object conforming to Mappable that have transforms +public func <- (left: inout Transform.Object, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let value: Transform.Object? = transform.transformFromJSON(map.currentValue) + FromJSON.basicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Transform.Object, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .toJSON { + let value: Transform.JSON? = transform.transformToJSON(left) + ToJSON.optionalBasicType(value, map: map) + } +} + + +/// Optional Mappable objects that have transforms +public func <- (left: inout Transform.Object?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let value: Transform.Object? = transform.transformFromJSON(map.currentValue) + FromJSON.optionalBasicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Transform.Object?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .toJSON{ + let value: Transform.JSON? = transform.transformToJSON(left) + ToJSON.optionalBasicType(value, map: map) + } +} + + +/// Implicitly unwrapped optional Mappable objects that have transforms +public func <- (left: inout Transform.Object!, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let value: Transform.Object? = transform.transformFromJSON(map.currentValue) + FromJSON.optionalBasicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + + +// MARK:- Dictionary of Mappable objects with a transform - Dictionary + +/// Dictionary of Mappable objects with a transform +public func <- (left: inout Dictionary, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .fromJSON && map.isKeyPresent, + let object = map.currentValue as? [String: Any] { + let value = fromJSONDictionaryWithTransform(object as Any?, transform: transform) ?? left + FromJSON.basicType(&left, object: value) + } else if map.mappingType == .toJSON { + left >>> right + } +} + +public func >>> (left: Dictionary, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .toJSON { + let value = toJSONDictionaryWithTransform(left, transform: transform) + ToJSON.basicType(value, map: map) + } +} + + +/// Optional Dictionary of Mappable object with a transform +public func <- (left: inout Dictionary?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .fromJSON && map.isKeyPresent, let object = map.currentValue as? [String : Any]{ + let value = fromJSONDictionaryWithTransform(object as Any?, transform: transform) ?? left + FromJSON.optionalBasicType(&left, object: value) + } else if map.mappingType == .toJSON { + left >>> right + } +} + +public func >>> (left: Dictionary?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .toJSON { + let value = toJSONDictionaryWithTransform(left, transform: transform) + ToJSON.optionalBasicType(value, map: map) + } +} + + +/// Implicitly unwrapped Optional Dictionary of Mappable object with a transform +public func <- (left: inout Dictionary!, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .fromJSON && map.isKeyPresent, let dictionary = map.currentValue as? [String : Any]{ + let transformedDictionary = fromJSONDictionaryWithTransform(dictionary as Any?, transform: transform) ?? left + FromJSON.optionalBasicType(&left, object: transformedDictionary) + } else if map.mappingType == .toJSON { + left >>> right + } +} + +/// Dictionary of Mappable objects with a transform +public func <- (left: inout Dictionary, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + + if let dictionary = map.currentValue as? [String : [Any]], map.mappingType == .fromJSON && map.isKeyPresent { + let transformedDictionary = dictionary.map { (key: String, values: [Any]) -> (String, [Transform.Object]) in + if let jsonArray = fromJSONArrayWithTransform(values, transform: transform) { + return (key, jsonArray) + } + if let leftValue = left[key] { + return (key, leftValue) + } + return (key, []) + } + + FromJSON.basicType(&left, object: transformedDictionary) + } else if map.mappingType == .toJSON { + left >>> right + } +} + +public func >>> (left: Dictionary, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + + if map.mappingType == .toJSON { + let transformedDictionary = left.map { (key, values) in + return (key, toJSONArrayWithTransform(values, transform: transform) ?? []) + } + + ToJSON.basicType(transformedDictionary, map: map) + } +} + + +/// Optional Dictionary of Mappable object with a transform +public func <- (left: inout Dictionary?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + + if let dictionary = map.currentValue as? [String : [Any]], map.mappingType == .fromJSON && map.isKeyPresent { + + let transformedDictionary = dictionary.map { (key: String, values: [Any]) -> (String, [Transform.Object]) in + if let jsonArray = fromJSONArrayWithTransform(values, transform: transform) { + return (key, jsonArray) + } + if let leftValue = left?[key] { + return (key, leftValue) + } + return (key, []) + + } + + FromJSON.optionalBasicType(&left, object: transformedDictionary) + } else if map.mappingType == .toJSON { + left >>> right + } +} + +public func >>> (left: Dictionary?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + + if map.mappingType == .toJSON { + let transformedDictionary = left?.map { (key, values) in + return (key, toJSONArrayWithTransform(values, transform: transform) ?? []) + } + + ToJSON.optionalBasicType(transformedDictionary, map: map) + } +} + + +/// Implicitly unwrapped Optional Dictionary of Mappable object with a transform +public func <- (left: inout Dictionary!, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + + if let dictionary = map.currentValue as? [String : [Any]], map.mappingType == .fromJSON && map.isKeyPresent { + let transformedDictionary = dictionary.map { (key: String, values: [Any]) -> (String, [Transform.Object]) in + if let jsonArray = fromJSONArrayWithTransform(values, transform: transform) { + return (key, jsonArray) + } + if let leftValue = left?[key] { + return (key, leftValue) + } + return (key, []) + } + FromJSON.optionalBasicType(&left, object: transformedDictionary) + } else if map.mappingType == .toJSON { + left >>> right + } +} + +// MARK:- Array of Mappable objects with transforms - Array + +/// Array of Mappable objects +public func <- (left: inout Array, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + if let transformedValues = fromJSONArrayWithTransform(map.currentValue, transform: transform) { + FromJSON.basicType(&left, object: transformedValues) + } + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Array, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .toJSON { + let transformedValues = toJSONArrayWithTransform(left, transform: transform) + ToJSON.optionalBasicType(transformedValues, map: map) + } +} + + +/// Optional array of Mappable objects +public func <- (left: inout Array?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let transformedValues = fromJSONArrayWithTransform(map.currentValue, transform: transform) + FromJSON.optionalBasicType(&left, object: transformedValues) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Array?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .toJSON { + let transformedValues = toJSONArrayWithTransform(left, transform: transform) + ToJSON.optionalBasicType(transformedValues, map: map) + } +} + + +/// Implicitly unwrapped Optional array of Mappable objects +public func <- (left: inout Array!, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let transformedValues = fromJSONArrayWithTransform(map.currentValue, transform: transform) + FromJSON.optionalBasicType(&left, object: transformedValues) + case .toJSON: + left >>> right + default: () + } +} + +// MARK:- Array of Array of objects - Array>> with transforms + +/// Array of Array of objects with transform +public func <- (left: inout [[Transform.Object]], right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .toJSON: + left >>> right + case .fromJSON where map.isKeyPresent: + guard let original2DArray = map.currentValue as? [[Any]] else { break } + let transformed2DArray = original2DArray.flatMap { values in + fromJSONArrayWithTransform(values as Any?, transform: transform) + } + FromJSON.basicType(&left, object: transformed2DArray) + default: + break + } +} + +public func >>> (left: [[Transform.Object]], right: (Map, Transform)) { + let (map, transform) = right + if map.mappingType == .toJSON{ + let transformed2DArray = left.flatMap { values in + toJSONArrayWithTransform(values, transform: transform) + } + ToJSON.basicType(transformed2DArray, map: map) + } +} + +/// Optional array of array of objects with transform +public func <- (left: inout [[Transform.Object]]?, right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .toJSON: + left >>> right + case .fromJSON where map.isKeyPresent: + guard let original2DArray = map.currentValue as? [[Any]] else { break } + let transformed2DArray = original2DArray.flatMap { values in + fromJSONArrayWithTransform(values as Any?, transform: transform) + } + FromJSON.optionalBasicType(&left, object: transformed2DArray) + default: + break + } +} + +public func >>> (left: [[Transform.Object]]?, right: (Map, Transform)) { + let (map, transform) = right + if map.mappingType == .toJSON { + let transformed2DArray = left?.flatMap { values in + toJSONArrayWithTransform(values, transform: transform) + } + ToJSON.optionalBasicType(transformed2DArray, map: map) + } +} + + +/// Implicitly unwrapped Optional array of array of objects with transform +public func <- (left: inout [[Transform.Object]]!, right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .toJSON: + left >>> right + case .fromJSON where map.isKeyPresent: + guard let original2DArray = map.currentValue as? [[Any]] else { break } + let transformed2DArray = original2DArray.flatMap { values in + fromJSONArrayWithTransform(values as Any?, transform: transform) + } + FromJSON.optionalBasicType(&left, object: transformed2DArray) + default: + break + } +} + +// MARK:- Set of Mappable objects with a transform - Set + +/// Set of Mappable objects with transform +public func <- (left: inout Set, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + if let transformedValues = fromJSONArrayWithTransform(map.currentValue, transform: transform) { + FromJSON.basicType(&left, object: Set(transformedValues)) + } + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Set, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .toJSON { + let transformedValues = toJSONArrayWithTransform(Array(left), transform: transform) + ToJSON.optionalBasicType(transformedValues, map: map) + } +} + + +/// Optional Set of Mappable objects with transform +public func <- (left: inout Set?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + if let transformedValues = fromJSONArrayWithTransform(map.currentValue, transform: transform) { + FromJSON.basicType(&left, object: Set(transformedValues)) + } + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Set?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .toJSON { + if let values = left { + let transformedValues = toJSONArrayWithTransform(Array(values), transform: transform) + ToJSON.optionalBasicType(transformedValues, map: map) + } + } +} + + +/// Implicitly unwrapped Optional set of Mappable objects with transform +public func <- (left: inout Set!, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + if let transformedValues = fromJSONArrayWithTransform(map.currentValue, transform: transform) { + FromJSON.basicType(&left, object: Set(transformedValues)) + } + case .toJSON: + left >>> right + default: () + } +} + + +private func fromJSONArrayWithTransform(_ input: Any?, transform: Transform) -> [Transform.Object]? { + if let values = input as? [Any] { + return values.flatMap { value in + return transform.transformFromJSON(value) + } + } else { + return nil + } +} + +private func fromJSONDictionaryWithTransform(_ input: Any?, transform: Transform) -> [String: Transform.Object]? { + if let values = input as? [String: Any] { + return values.filterMap { value in + return transform.transformFromJSON(value) + } + } else { + return nil + } +} + +private func toJSONArrayWithTransform(_ input: [Transform.Object]?, transform: Transform) -> [Transform.JSON]? { + return input?.flatMap { value in + return transform.transformToJSON(value) + } +} + +private func toJSONDictionaryWithTransform(_ input: [String: Transform.Object]?, transform: Transform) -> [String: Transform.JSON]? { + return input?.filterMap { value in + return transform.transformToJSON(value) + } +} diff --git a/Pods/ObjectMapper/Sources/TransformType.swift b/Pods/ObjectMapper/Sources/TransformType.swift new file mode 100644 index 0000000..61578c3 --- /dev/null +++ b/Pods/ObjectMapper/Sources/TransformType.swift @@ -0,0 +1,35 @@ +// +// TransformType.swift +// ObjectMapper +// +// Created by Syo Ikeda on 2/4/15. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Hearst +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +public protocol TransformType { + associatedtype Object + associatedtype JSON + + func transformFromJSON(_ value: Any?) -> Object? + func transformToJSON(_ value: Object?) -> JSON? +} diff --git a/Pods/ObjectMapper/Sources/URLTransform.swift b/Pods/ObjectMapper/Sources/URLTransform.swift new file mode 100644 index 0000000..683a934 --- /dev/null +++ b/Pods/ObjectMapper/Sources/URLTransform.swift @@ -0,0 +1,67 @@ +// +// URLTransform.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2014-10-27. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Hearst +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +open class URLTransform: TransformType { + public typealias Object = URL + public typealias JSON = String + private let shouldEncodeURLString: Bool + private let allowedCharacterSet: CharacterSet + + /** + Initializes the URLTransform with an option to encode URL strings before converting them to an NSURL + - parameter shouldEncodeUrlString: when true (the default) the string is encoded before passing + to `NSURL(string:)` + - returns: an initialized transformer + */ + public init(shouldEncodeURLString: Bool = true, allowedCharacterSet: CharacterSet = .urlQueryAllowed) { + self.shouldEncodeURLString = shouldEncodeURLString + self.allowedCharacterSet = allowedCharacterSet + } + + open func transformFromJSON(_ value: Any?) -> URL? { + guard let URLString = value as? String else { return nil } + + if !shouldEncodeURLString { + return URL(string: URLString) + } + + guard let escapedURLString = URLString.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) else { + return nil + } + return URL(string: escapedURLString) + } + + open func transformToJSON(_ value: URL?) -> String? { + if let URL = value { + return URL.absoluteString + } + return nil + } +} diff --git a/Pods/Pods.xcodeproj/project.pbxproj b/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 0000000..df299db --- /dev/null +++ b/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,890 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 048BE8B1399E22885B758F58B5103AAF /* UIImage+Haneke.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93CBD23FBCF96807BB7BE9663ECADEBC /* UIImage+Haneke.swift */; }; + 0DA289E3CFC0496E8A393A78831458C6 /* Fetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2613C906D6AFBBA644025BD1EA644895 /* Fetch.swift */; }; + 0F981C56836FE34E921BC7253826A170 /* CustomDateFormatTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E036BAFF595B69843BCD7B7EF60056C /* CustomDateFormatTransform.swift */; }; + 134859C42E05396F62489E4329ECF6EA /* ToJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06DFDAF6276623367F2579F1DE19AA73 /* ToJSON.swift */; }; + 1894026C296B8A77711607C98ED40C86 /* IntegerOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B3696F26C30D04D7545C92212133B16 /* IntegerOperators.swift */; }; + 18E9B5E96557418567FCB7DCC559299F /* TransformOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59B6723EA41D26F831E2F42781DA27A4 /* TransformOperators.swift */; }; + 194858D10B9B1DD9FFEFBE4EAA0700F3 /* TransformOf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B65A91424CB56E7C8D1CF807E527251 /* TransformOf.swift */; }; + 233D0C74026D4F77CB562E90B2714777 /* DiskFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 901E7C95499CC8E278373DAD4DAFC101 /* DiskFetcher.swift */; }; + 255C4ADB2BD82FEEF86A3D4D43F31C63 /* ISO8601DateTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63D057B45A7D037105096E2E5D4FD6DF /* ISO8601DateTransform.swift */; }; + 25F558B3167CC7FAFCCC902B83ED0599 /* String+Haneke.swift in Sources */ = {isa = PBXBuildFile; fileRef = 921B5842657D979B778281636B01485A /* String+Haneke.swift */; }; + 27156C9092B7A82E24CF96312A941150 /* TransformType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39F227B45BA8436E70BE1E7B0C232CCA /* TransformType.swift */; }; + 2D89AB26203628C04B3E87D045525701 /* MapError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B224E2D13E925FAF4CE462D42A0D403 /* MapError.swift */; }; + 2D93F149491F25BCC11EBF259DE1791D /* NSURLResponse+Haneke.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7029014F55D046272F507252C9D3BA63 /* NSURLResponse+Haneke.swift */; }; + 34BA8F11703FC6F1FC94812A2B451A2D /* HanekeSwift-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = CBE413E65BCF6B47BACAF1942A88C1DC /* HanekeSwift-dummy.m */; }; + 368FBAAE5E624FDDB6F39D1ACB1DA144 /* UIImageView+Haneke.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D47E80624453AED56A9F89FCA0168F5 /* UIImageView+Haneke.swift */; }; + 4215D7313CE6E738AAD80E9FEC6C60CC /* DateFormatterTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 939DDB80AAEE87010A040616093C21F1 /* DateFormatterTransform.swift */; }; + 424F2EE8F3FF0206A8C0455939698D41 /* Fetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A08D8DD917D15549FFAA3E8D3F142E6 /* Fetcher.swift */; }; + 44ACFD0543993523C7B2875814A25A65 /* DiskCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = ACF0980E664E99559706A4C27CB477B6 /* DiskCache.swift */; }; + 45D941F68F765620760E8EC56F4C3904 /* NetworkFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D95B8EF46999EA62F07B8797D7D7C45 /* NetworkFetcher.swift */; }; + 516B284EC38BCC14EBF5A275790CFA9E /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BF8DE48B535D96E66C45D3F9951660 /* Data.swift */; }; + 551FB4DF0E5072BB849BB4FCE74F7361 /* HexColorTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A3485664735BFA9B00EEBB97EA82D54 /* HexColorTransform.swift */; }; + 59109302859941E04E87DC7044DFEE89 /* ObjectMapper-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 69D899AA6446F76156595D517423A3B5 /* ObjectMapper-dummy.m */; }; + 5946A4834D77660F3D8188ED70FDC603 /* NSHTTPURLResponse+Haneke.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD591D76F0FB2A74D8B40CFD5B029008 /* NSHTTPURLResponse+Haneke.swift */; }; + 67A4D8A24085ADC44A65404E73461B43 /* Mappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC4397D7169C748DA87E82BB18BF156 /* Mappable.swift */; }; + 6C2FE27FDBD6621AAB57E4082419C347 /* NSDecimalNumberTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADEF959F2041E20654F552A521D48A2E /* NSDecimalNumberTransform.swift */; }; + 6F41805C2984D3172CEBDCB232A9E205 /* CryptoSwiftMD5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40E03F1C07DEF6BC922E82F1E020D3CE /* CryptoSwiftMD5.swift */; }; + 706840688BA7E9BDE5F4DD2C0E558835 /* EnumOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 862947DE41FB6A519B419B95A2D55AB6 /* EnumOperators.swift */; }; + 734D2D7728F4FDB196AFBDA6FE131376 /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A6811C5C8AF730A7EB9696D7B6BA835 /* Log.swift */; }; + 77CA4CD47748C0B69982A6D82C2799D5 /* Mapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEF6161B3C1D51F4825809FA03485559 /* Mapper.swift */; }; + 78C198E9BB56FB59BD494C8FA759645B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6604A7D69453B4569E4E4827FB9155A9 /* Foundation.framework */; }; + 7E867974234ECCA3F0419879A37EF9A1 /* Haneke.swift in Sources */ = {isa = PBXBuildFile; fileRef = 461E98A8884597C41858FC49107F73AD /* Haneke.swift */; }; + 83AF0ACAB3309F7307C6BD6CF82E0DB1 /* Pods-Pokedex-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = DF737C2699172F343717EDCBDAEB66F1 /* Pods-Pokedex-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 990478AA09857AE10ADAD5E40BDCF9B4 /* Pods-Pokedex-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = D3248D37C8B083C91EF2B6D5E7BABD38 /* Pods-Pokedex-dummy.m */; }; + 9D751AE797836951F9FD0A4E9E6AE344 /* CGSize+Swift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93E3F17A43F4587D5F1F9C41F457AB72 /* CGSize+Swift.swift */; }; + 9F0ED20EDA02495C3CE53351168BDA34 /* UIView+Haneke.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55C32F35EE75DBB5209610906EDDFB97 /* UIView+Haneke.swift */; }; + A128DBCF691E0F4D2AC3EEA36F7BD562 /* ObjectMapper-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 45DD9DC616AAB8A9C629C48F3E784DDC /* ObjectMapper-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A257C7E3394A9813188DC886B978193F /* UIButton+Haneke.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EDFBF89C0B3284630BDA7EA12BAEE5B /* UIButton+Haneke.swift */; }; + A5BFC49ED41BC416BEBF4772517AB741 /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDA90427C93A1E4B2E9E7D299E6C03A /* Map.swift */; }; + AF0E4ECBE65891C25ACE312E832217ED /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6604A7D69453B4569E4E4827FB9155A9 /* Foundation.framework */; }; + B2EFEFFB34D517F8E9A203B674AEBD13 /* DictionaryTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC08825B1EFDC34D05108FC923A13F68 /* DictionaryTransform.swift */; }; + B9C39C539A810D1958AEEF1AEC0FD75C /* ImmutableMappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DAE22DD7ADFC0669449010B7190C91C /* ImmutableMappable.swift */; }; + C9FDF6F209E90829A8E96B03077116BB /* NSFileManager+Haneke.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47301DA91D929E5A7E846A2821D3778A /* NSFileManager+Haneke.swift */; }; + D734F5980CF4609635307AEE7ECB65B2 /* Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC9BC18A1863115791F92BBB3C0FE303 /* Cache.swift */; }; + DB87FF0D3B17ABB5452FDD4D70C9A84D /* FromJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59D2A2CE3026D0721367516AD69D673A /* FromJSON.swift */; }; + EA67527CAF7ED571C8A84B66DDD70FBE /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = C50CBD4C620825D21B01481E75FD64A4 /* Operators.swift */; }; + EAC47BB7AFEF34F9797A031154BFE74D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6604A7D69453B4569E4E4827FB9155A9 /* Foundation.framework */; }; + EC1A896625476730D64BF9645624BBAD /* DataTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0CBBB6DA54ACFA748EE392D949B143A /* DataTransform.swift */; }; + F211DBF02AD9CCDECA9BD1C3F58CD42E /* Format.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B17AD3324B1A997107E7E8E6B20FCA5 /* Format.swift */; }; + F527B0A072DFD754B471E4C1F6B16C48 /* URLTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7A9C4D46B4E15D6A6F205B0915A3E39 /* URLTransform.swift */; }; + F9B63BDA169DB048D41DA8395261AEBA /* DateTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3762E9268BC61CA73EB836276625AFBC /* DateTransform.swift */; }; + F9C156883B938B995522ECC76E4A65DD /* HanekeSwift-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 5ABEFBD4542A778DEEEBE6ACFD7A49B4 /* HanekeSwift-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FCE734BD83FB03D3DC9F8AA843ECD73B /* EnumTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AC00159C0A469A986A1FBF1E3A3296D /* EnumTransform.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + C5C448A2D4C887B9F868C28C631F76AA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = CD6C9FB6B052E1CF663F8A56041EA163; + remoteInfo = ObjectMapper; + }; + E56F134377D168FDF16FF3AF1B60D015 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = AE4759774042D8E013517E82C6F7A058; + remoteInfo = HanekeSwift; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 02DA0DCBE799EBF2FF0A720143617FDC /* Pods-Pokedex-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-Pokedex-acknowledgements.markdown"; sourceTree = ""; }; + 06DFDAF6276623367F2579F1DE19AA73 /* ToJSON.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ToJSON.swift; path = Sources/ToJSON.swift; sourceTree = ""; }; + 0A08D8DD917D15549FFAA3E8D3F142E6 /* Fetcher.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Fetcher.swift; path = Haneke/Fetcher.swift; sourceTree = ""; }; + 0AC00159C0A469A986A1FBF1E3A3296D /* EnumTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = EnumTransform.swift; path = Sources/EnumTransform.swift; sourceTree = ""; }; + 15C534A9FD25C3C336E2EE386CFEB8D2 /* ObjectMapper.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = ObjectMapper.xcconfig; sourceTree = ""; }; + 1B224E2D13E925FAF4CE462D42A0D403 /* MapError.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MapError.swift; path = Sources/MapError.swift; sourceTree = ""; }; + 2613C906D6AFBBA644025BD1EA644895 /* Fetch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Fetch.swift; path = Haneke/Fetch.swift; sourceTree = ""; }; + 2B65A91424CB56E7C8D1CF807E527251 /* TransformOf.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TransformOf.swift; path = Sources/TransformOf.swift; sourceTree = ""; }; + 3762E9268BC61CA73EB836276625AFBC /* DateTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DateTransform.swift; path = Sources/DateTransform.swift; sourceTree = ""; }; + 3772BB295362669DA71DD034B23EA5FB /* Pods_Pokedex.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Pokedex.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 39F227B45BA8436E70BE1E7B0C232CCA /* TransformType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TransformType.swift; path = Sources/TransformType.swift; sourceTree = ""; }; + 40E03F1C07DEF6BC922E82F1E020D3CE /* CryptoSwiftMD5.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CryptoSwiftMD5.swift; path = Haneke/CryptoSwiftMD5.swift; sourceTree = ""; }; + 41BA2A930FD5CA74D50DB1070E886036 /* HanekeSwift.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = HanekeSwift.xcconfig; sourceTree = ""; }; + 45DD9DC616AAB8A9C629C48F3E784DDC /* ObjectMapper-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "ObjectMapper-umbrella.h"; sourceTree = ""; }; + 45F42A872D178B88D5E1FEC507FDAD83 /* ObjectMapper-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "ObjectMapper-prefix.pch"; sourceTree = ""; }; + 461E98A8884597C41858FC49107F73AD /* Haneke.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Haneke.swift; path = Haneke/Haneke.swift; sourceTree = ""; }; + 47301DA91D929E5A7E846A2821D3778A /* NSFileManager+Haneke.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSFileManager+Haneke.swift"; path = "Haneke/NSFileManager+Haneke.swift"; sourceTree = ""; }; + 4DAE22DD7ADFC0669449010B7190C91C /* ImmutableMappable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ImmutableMappable.swift; path = Sources/ImmutableMappable.swift; sourceTree = ""; }; + 4DF0BC7442C18668B61930A9D37429FB /* Pods-Pokedex-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Pokedex-resources.sh"; sourceTree = ""; }; + 4EDFBF89C0B3284630BDA7EA12BAEE5B /* UIButton+Haneke.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIButton+Haneke.swift"; path = "Haneke/UIButton+Haneke.swift"; sourceTree = ""; }; + 55C32F35EE75DBB5209610906EDDFB97 /* UIView+Haneke.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIView+Haneke.swift"; path = "Haneke/UIView+Haneke.swift"; sourceTree = ""; }; + 563C9F1B6B4974A0B84D1C00B8CE5920 /* Pods-Pokedex.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Pokedex.debug.xcconfig"; sourceTree = ""; }; + 59B6723EA41D26F831E2F42781DA27A4 /* TransformOperators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TransformOperators.swift; path = Sources/TransformOperators.swift; sourceTree = ""; }; + 59D2A2CE3026D0721367516AD69D673A /* FromJSON.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FromJSON.swift; path = Sources/FromJSON.swift; sourceTree = ""; }; + 5A6811C5C8AF730A7EB9696D7B6BA835 /* Log.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Log.swift; path = Haneke/Log.swift; sourceTree = ""; }; + 5ABEFBD4542A778DEEEBE6ACFD7A49B4 /* HanekeSwift-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "HanekeSwift-umbrella.h"; sourceTree = ""; }; + 63D057B45A7D037105096E2E5D4FD6DF /* ISO8601DateTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ISO8601DateTransform.swift; path = Sources/ISO8601DateTransform.swift; sourceTree = ""; }; + 6604A7D69453B4569E4E4827FB9155A9 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + 69D899AA6446F76156595D517423A3B5 /* ObjectMapper-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "ObjectMapper-dummy.m"; sourceTree = ""; }; + 7029014F55D046272F507252C9D3BA63 /* NSURLResponse+Haneke.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSURLResponse+Haneke.swift"; path = "Haneke/NSURLResponse+Haneke.swift"; sourceTree = ""; }; + 71BF8DE48B535D96E66C45D3F9951660 /* Data.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Data.swift; path = Haneke/Data.swift; sourceTree = ""; }; + 7993F07199B998F828EEFC43C689E6E2 /* ObjectMapper.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "sourcecode.module-map"; path = ObjectMapper.modulemap; sourceTree = ""; }; + 7D95B8EF46999EA62F07B8797D7D7C45 /* NetworkFetcher.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NetworkFetcher.swift; path = Haneke/NetworkFetcher.swift; sourceTree = ""; }; + 862947DE41FB6A519B419B95A2D55AB6 /* EnumOperators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = EnumOperators.swift; path = Sources/EnumOperators.swift; sourceTree = ""; }; + 8A3485664735BFA9B00EEBB97EA82D54 /* HexColorTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HexColorTransform.swift; path = Sources/HexColorTransform.swift; sourceTree = ""; }; + 8B17AD3324B1A997107E7E8E6B20FCA5 /* Format.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Format.swift; path = Haneke/Format.swift; sourceTree = ""; }; + 8B9D3E65A17DDEBEEB3E9620E8DCDB2C /* Pods-Pokedex-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Pokedex-acknowledgements.plist"; sourceTree = ""; }; + 8D47E80624453AED56A9F89FCA0168F5 /* UIImageView+Haneke.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIImageView+Haneke.swift"; path = "Haneke/UIImageView+Haneke.swift"; sourceTree = ""; }; + 8E036BAFF595B69843BCD7B7EF60056C /* CustomDateFormatTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CustomDateFormatTransform.swift; path = Sources/CustomDateFormatTransform.swift; sourceTree = ""; }; + 901E7C95499CC8E278373DAD4DAFC101 /* DiskFetcher.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DiskFetcher.swift; path = Haneke/DiskFetcher.swift; sourceTree = ""; }; + 921B5842657D979B778281636B01485A /* String+Haneke.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "String+Haneke.swift"; path = "Haneke/String+Haneke.swift"; sourceTree = ""; }; + 939DDB80AAEE87010A040616093C21F1 /* DateFormatterTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DateFormatterTransform.swift; path = Sources/DateFormatterTransform.swift; sourceTree = ""; }; + 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 93CBD23FBCF96807BB7BE9663ECADEBC /* UIImage+Haneke.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIImage+Haneke.swift"; path = "Haneke/UIImage+Haneke.swift"; sourceTree = ""; }; + 93E3F17A43F4587D5F1F9C41F457AB72 /* CGSize+Swift.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "CGSize+Swift.swift"; path = "Haneke/CGSize+Swift.swift"; sourceTree = ""; }; + 9732961F84924B8D1C8EE34E22B18746 /* ObjectMapper.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ObjectMapper.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 9AED787CA404C61059C8B232AE9F40E4 /* Haneke.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Haneke.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 9B3696F26C30D04D7545C92212133B16 /* IntegerOperators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = IntegerOperators.swift; path = Sources/IntegerOperators.swift; sourceTree = ""; }; + A2DAEF6EA78DBFB1CFC22DFBBCCBA094 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + AAC4397D7169C748DA87E82BB18BF156 /* Mappable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Mappable.swift; path = Sources/Mappable.swift; sourceTree = ""; }; + ACF0980E664E99559706A4C27CB477B6 /* DiskCache.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DiskCache.swift; path = Haneke/DiskCache.swift; sourceTree = ""; }; + ADEA787DBBA361D94B8FF73C036FEECC /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + ADEF959F2041E20654F552A521D48A2E /* NSDecimalNumberTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NSDecimalNumberTransform.swift; path = Sources/NSDecimalNumberTransform.swift; sourceTree = ""; }; + AEF6161B3C1D51F4825809FA03485559 /* Mapper.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Mapper.swift; path = Sources/Mapper.swift; sourceTree = ""; }; + B0CBBB6DA54ACFA748EE392D949B143A /* DataTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DataTransform.swift; path = Sources/DataTransform.swift; sourceTree = ""; }; + BC08825B1EFDC34D05108FC923A13F68 /* DictionaryTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DictionaryTransform.swift; path = Sources/DictionaryTransform.swift; sourceTree = ""; }; + BD591D76F0FB2A74D8B40CFD5B029008 /* NSHTTPURLResponse+Haneke.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSHTTPURLResponse+Haneke.swift"; path = "Haneke/NSHTTPURLResponse+Haneke.swift"; sourceTree = ""; }; + BEEDA786DDC04DEF4B5B7D3FB365E64D /* Pods-Pokedex.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "sourcecode.module-map"; path = "Pods-Pokedex.modulemap"; sourceTree = ""; }; + C50CBD4C620825D21B01481E75FD64A4 /* Operators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Sources/Operators.swift; sourceTree = ""; }; + CBDA90427C93A1E4B2E9E7D299E6C03A /* Map.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Map.swift; path = Sources/Map.swift; sourceTree = ""; }; + CBE413E65BCF6B47BACAF1942A88C1DC /* HanekeSwift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "HanekeSwift-dummy.m"; sourceTree = ""; }; + CC1E8361665F3DBE1A324BC4C90E0E06 /* HanekeSwift.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "sourcecode.module-map"; path = HanekeSwift.modulemap; sourceTree = ""; }; + CC9BC18A1863115791F92BBB3C0FE303 /* Cache.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Cache.swift; path = Haneke/Cache.swift; sourceTree = ""; }; + CF4FB5751CED7C16D2FC91CB60E179A0 /* Pods-Pokedex.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Pokedex.release.xcconfig"; sourceTree = ""; }; + D3248D37C8B083C91EF2B6D5E7BABD38 /* Pods-Pokedex-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-Pokedex-dummy.m"; sourceTree = ""; }; + DF737C2699172F343717EDCBDAEB66F1 /* Pods-Pokedex-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-Pokedex-umbrella.h"; sourceTree = ""; }; + E112A3039FC5908C2D85A01CD311B440 /* Pods-Pokedex-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Pokedex-frameworks.sh"; sourceTree = ""; }; + E4EA4A3FB908D7F1126C2258CEAE1679 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + E7A9C4D46B4E15D6A6F205B0915A3E39 /* URLTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = URLTransform.swift; path = Sources/URLTransform.swift; sourceTree = ""; }; + E881BC42DF69EE3624216C6D6CECA9F6 /* HanekeSwift-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "HanekeSwift-prefix.pch"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 9AA5EF78028B88D38FD0B0E00A797875 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + AF0E4ECBE65891C25ACE312E832217ED /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A7AE8F3FCB72C7CD63ADDAF4C3227F08 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EAC47BB7AFEF34F9797A031154BFE74D /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C4F4068871A73EB6FBE8042AF2063595 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 78C198E9BB56FB59BD494C8FA759645B /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0956B77035BC83F6F3A1B0CB3234EB4C /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + 7B9E93B2370DF8E02DC0354C7B756E84 /* Pods-Pokedex */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; + 1B5AFEDEECCACAF834B736AAD149736C /* Support Files */ = { + isa = PBXGroup; + children = ( + CC1E8361665F3DBE1A324BC4C90E0E06 /* HanekeSwift.modulemap */, + 41BA2A930FD5CA74D50DB1070E886036 /* HanekeSwift.xcconfig */, + CBE413E65BCF6B47BACAF1942A88C1DC /* HanekeSwift-dummy.m */, + E881BC42DF69EE3624216C6D6CECA9F6 /* HanekeSwift-prefix.pch */, + 5ABEFBD4542A778DEEEBE6ACFD7A49B4 /* HanekeSwift-umbrella.h */, + ADEA787DBBA361D94B8FF73C036FEECC /* Info.plist */, + ); + name = "Support Files"; + path = "../Target Support Files/HanekeSwift"; + sourceTree = ""; + }; + 417FCF24940751DA64D912DAB1B47310 /* Products */ = { + isa = PBXGroup; + children = ( + 9AED787CA404C61059C8B232AE9F40E4 /* Haneke.framework */, + 9732961F84924B8D1C8EE34E22B18746 /* ObjectMapper.framework */, + 3772BB295362669DA71DD034B23EA5FB /* Pods_Pokedex.framework */, + ); + name = Products; + sourceTree = ""; + }; + 42A20151A78CC9145B475B5A0A37384E /* Pods */ = { + isa = PBXGroup; + children = ( + 8D00A5EA769DBC5060835D962F6AABC0 /* HanekeSwift */, + 96986AE66261D60407043138DFC1AB82 /* ObjectMapper */, + ); + name = Pods; + sourceTree = ""; + }; + 7B9E93B2370DF8E02DC0354C7B756E84 /* Pods-Pokedex */ = { + isa = PBXGroup; + children = ( + E4EA4A3FB908D7F1126C2258CEAE1679 /* Info.plist */, + BEEDA786DDC04DEF4B5B7D3FB365E64D /* Pods-Pokedex.modulemap */, + 02DA0DCBE799EBF2FF0A720143617FDC /* Pods-Pokedex-acknowledgements.markdown */, + 8B9D3E65A17DDEBEEB3E9620E8DCDB2C /* Pods-Pokedex-acknowledgements.plist */, + D3248D37C8B083C91EF2B6D5E7BABD38 /* Pods-Pokedex-dummy.m */, + E112A3039FC5908C2D85A01CD311B440 /* Pods-Pokedex-frameworks.sh */, + 4DF0BC7442C18668B61930A9D37429FB /* Pods-Pokedex-resources.sh */, + DF737C2699172F343717EDCBDAEB66F1 /* Pods-Pokedex-umbrella.h */, + 563C9F1B6B4974A0B84D1C00B8CE5920 /* Pods-Pokedex.debug.xcconfig */, + CF4FB5751CED7C16D2FC91CB60E179A0 /* Pods-Pokedex.release.xcconfig */, + ); + name = "Pods-Pokedex"; + path = "Target Support Files/Pods-Pokedex"; + sourceTree = ""; + }; + 7DB346D0F39D3F0E887471402A8071AB = { + isa = PBXGroup; + children = ( + 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */, + BC3CA7F9E30CC8F7E2DD044DD34432FC /* Frameworks */, + 42A20151A78CC9145B475B5A0A37384E /* Pods */, + 417FCF24940751DA64D912DAB1B47310 /* Products */, + 0956B77035BC83F6F3A1B0CB3234EB4C /* Targets Support Files */, + ); + sourceTree = ""; + }; + 8D00A5EA769DBC5060835D962F6AABC0 /* HanekeSwift */ = { + isa = PBXGroup; + children = ( + CC9BC18A1863115791F92BBB3C0FE303 /* Cache.swift */, + 93E3F17A43F4587D5F1F9C41F457AB72 /* CGSize+Swift.swift */, + 40E03F1C07DEF6BC922E82F1E020D3CE /* CryptoSwiftMD5.swift */, + 71BF8DE48B535D96E66C45D3F9951660 /* Data.swift */, + ACF0980E664E99559706A4C27CB477B6 /* DiskCache.swift */, + 901E7C95499CC8E278373DAD4DAFC101 /* DiskFetcher.swift */, + 2613C906D6AFBBA644025BD1EA644895 /* Fetch.swift */, + 0A08D8DD917D15549FFAA3E8D3F142E6 /* Fetcher.swift */, + 8B17AD3324B1A997107E7E8E6B20FCA5 /* Format.swift */, + 461E98A8884597C41858FC49107F73AD /* Haneke.swift */, + 5A6811C5C8AF730A7EB9696D7B6BA835 /* Log.swift */, + 7D95B8EF46999EA62F07B8797D7D7C45 /* NetworkFetcher.swift */, + 47301DA91D929E5A7E846A2821D3778A /* NSFileManager+Haneke.swift */, + BD591D76F0FB2A74D8B40CFD5B029008 /* NSHTTPURLResponse+Haneke.swift */, + 7029014F55D046272F507252C9D3BA63 /* NSURLResponse+Haneke.swift */, + 921B5842657D979B778281636B01485A /* String+Haneke.swift */, + 4EDFBF89C0B3284630BDA7EA12BAEE5B /* UIButton+Haneke.swift */, + 93CBD23FBCF96807BB7BE9663ECADEBC /* UIImage+Haneke.swift */, + 8D47E80624453AED56A9F89FCA0168F5 /* UIImageView+Haneke.swift */, + 55C32F35EE75DBB5209610906EDDFB97 /* UIView+Haneke.swift */, + 1B5AFEDEECCACAF834B736AAD149736C /* Support Files */, + ); + path = HanekeSwift; + sourceTree = ""; + }; + 96986AE66261D60407043138DFC1AB82 /* ObjectMapper */ = { + isa = PBXGroup; + children = ( + 8E036BAFF595B69843BCD7B7EF60056C /* CustomDateFormatTransform.swift */, + B0CBBB6DA54ACFA748EE392D949B143A /* DataTransform.swift */, + 939DDB80AAEE87010A040616093C21F1 /* DateFormatterTransform.swift */, + 3762E9268BC61CA73EB836276625AFBC /* DateTransform.swift */, + BC08825B1EFDC34D05108FC923A13F68 /* DictionaryTransform.swift */, + 862947DE41FB6A519B419B95A2D55AB6 /* EnumOperators.swift */, + 0AC00159C0A469A986A1FBF1E3A3296D /* EnumTransform.swift */, + 59D2A2CE3026D0721367516AD69D673A /* FromJSON.swift */, + 8A3485664735BFA9B00EEBB97EA82D54 /* HexColorTransform.swift */, + 4DAE22DD7ADFC0669449010B7190C91C /* ImmutableMappable.swift */, + 9B3696F26C30D04D7545C92212133B16 /* IntegerOperators.swift */, + 63D057B45A7D037105096E2E5D4FD6DF /* ISO8601DateTransform.swift */, + CBDA90427C93A1E4B2E9E7D299E6C03A /* Map.swift */, + 1B224E2D13E925FAF4CE462D42A0D403 /* MapError.swift */, + AAC4397D7169C748DA87E82BB18BF156 /* Mappable.swift */, + AEF6161B3C1D51F4825809FA03485559 /* Mapper.swift */, + ADEF959F2041E20654F552A521D48A2E /* NSDecimalNumberTransform.swift */, + C50CBD4C620825D21B01481E75FD64A4 /* Operators.swift */, + 06DFDAF6276623367F2579F1DE19AA73 /* ToJSON.swift */, + 2B65A91424CB56E7C8D1CF807E527251 /* TransformOf.swift */, + 59B6723EA41D26F831E2F42781DA27A4 /* TransformOperators.swift */, + 39F227B45BA8436E70BE1E7B0C232CCA /* TransformType.swift */, + E7A9C4D46B4E15D6A6F205B0915A3E39 /* URLTransform.swift */, + ECCCAEAFA67726616B770A0DAA14907B /* Support Files */, + ); + path = ObjectMapper; + sourceTree = ""; + }; + BC3CA7F9E30CC8F7E2DD044DD34432FC /* Frameworks */ = { + isa = PBXGroup; + children = ( + D35AF013A5F0BAD4F32504907A52519E /* iOS */, + ); + name = Frameworks; + sourceTree = ""; + }; + D35AF013A5F0BAD4F32504907A52519E /* iOS */ = { + isa = PBXGroup; + children = ( + 6604A7D69453B4569E4E4827FB9155A9 /* Foundation.framework */, + ); + name = iOS; + sourceTree = ""; + }; + ECCCAEAFA67726616B770A0DAA14907B /* Support Files */ = { + isa = PBXGroup; + children = ( + A2DAEF6EA78DBFB1CFC22DFBBCCBA094 /* Info.plist */, + 7993F07199B998F828EEFC43C689E6E2 /* ObjectMapper.modulemap */, + 15C534A9FD25C3C336E2EE386CFEB8D2 /* ObjectMapper.xcconfig */, + 69D899AA6446F76156595D517423A3B5 /* ObjectMapper-dummy.m */, + 45F42A872D178B88D5E1FEC507FDAD83 /* ObjectMapper-prefix.pch */, + 45DD9DC616AAB8A9C629C48F3E784DDC /* ObjectMapper-umbrella.h */, + ); + name = "Support Files"; + path = "../Target Support Files/ObjectMapper"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 1230F5D0018AF9B0BFF25558571D1DB3 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + F9C156883B938B995522ECC76E4A65DD /* HanekeSwift-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9409A3837547DA7A73C695CEF86F2ED7 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 83AF0ACAB3309F7307C6BD6CF82E0DB1 /* Pods-Pokedex-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F57C9456EA5FB7C7D8FC40BACD0F5369 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + A128DBCF691E0F4D2AC3EEA36F7BD562 /* ObjectMapper-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + AE4759774042D8E013517E82C6F7A058 /* HanekeSwift */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6DD468FB375E9C1971E9F0CFE51A4135 /* Build configuration list for PBXNativeTarget "HanekeSwift" */; + buildPhases = ( + 3F39FB05072ED8C17BABEB9BC822959C /* Sources */, + A7AE8F3FCB72C7CD63ADDAF4C3227F08 /* Frameworks */, + 1230F5D0018AF9B0BFF25558571D1DB3 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = HanekeSwift; + productName = HanekeSwift; + productReference = 9AED787CA404C61059C8B232AE9F40E4 /* Haneke.framework */; + productType = "com.apple.product-type.framework"; + }; + B2E279D716CBA3590C2B59941BFC1C02 /* Pods-Pokedex */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2F820C6BD8776D7C930AC05F2598D2CB /* Build configuration list for PBXNativeTarget "Pods-Pokedex" */; + buildPhases = ( + 80F9B6E78BA63EEBF904AB8AB1807D45 /* Sources */, + 9AA5EF78028B88D38FD0B0E00A797875 /* Frameworks */, + 9409A3837547DA7A73C695CEF86F2ED7 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + E1A8261C324CCBA4FB8C82F1F8926272 /* PBXTargetDependency */, + 7FBEAB6421362BCA2DFABA527FD5B538 /* PBXTargetDependency */, + ); + name = "Pods-Pokedex"; + productName = "Pods-Pokedex"; + productReference = 3772BB295362669DA71DD034B23EA5FB /* Pods_Pokedex.framework */; + productType = "com.apple.product-type.framework"; + }; + CD6C9FB6B052E1CF663F8A56041EA163 /* ObjectMapper */ = { + isa = PBXNativeTarget; + buildConfigurationList = 23CFD86DE455F2B998EC09D589DA285D /* Build configuration list for PBXNativeTarget "ObjectMapper" */; + buildPhases = ( + F35FEC988ECD73463D93176BC71A43B1 /* Sources */, + C4F4068871A73EB6FBE8042AF2063595 /* Frameworks */, + F57C9456EA5FB7C7D8FC40BACD0F5369 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ObjectMapper; + productName = ObjectMapper; + productReference = 9732961F84924B8D1C8EE34E22B18746 /* ObjectMapper.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D41D8CD98F00B204E9800998ECF8427E /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0830; + LastUpgradeCheck = 0700; + }; + buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 7DB346D0F39D3F0E887471402A8071AB; + productRefGroup = 417FCF24940751DA64D912DAB1B47310 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + AE4759774042D8E013517E82C6F7A058 /* HanekeSwift */, + CD6C9FB6B052E1CF663F8A56041EA163 /* ObjectMapper */, + B2E279D716CBA3590C2B59941BFC1C02 /* Pods-Pokedex */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 3F39FB05072ED8C17BABEB9BC822959C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D734F5980CF4609635307AEE7ECB65B2 /* Cache.swift in Sources */, + 9D751AE797836951F9FD0A4E9E6AE344 /* CGSize+Swift.swift in Sources */, + 6F41805C2984D3172CEBDCB232A9E205 /* CryptoSwiftMD5.swift in Sources */, + 516B284EC38BCC14EBF5A275790CFA9E /* Data.swift in Sources */, + 44ACFD0543993523C7B2875814A25A65 /* DiskCache.swift in Sources */, + 233D0C74026D4F77CB562E90B2714777 /* DiskFetcher.swift in Sources */, + 0DA289E3CFC0496E8A393A78831458C6 /* Fetch.swift in Sources */, + 424F2EE8F3FF0206A8C0455939698D41 /* Fetcher.swift in Sources */, + F211DBF02AD9CCDECA9BD1C3F58CD42E /* Format.swift in Sources */, + 7E867974234ECCA3F0419879A37EF9A1 /* Haneke.swift in Sources */, + 34BA8F11703FC6F1FC94812A2B451A2D /* HanekeSwift-dummy.m in Sources */, + 734D2D7728F4FDB196AFBDA6FE131376 /* Log.swift in Sources */, + 45D941F68F765620760E8EC56F4C3904 /* NetworkFetcher.swift in Sources */, + C9FDF6F209E90829A8E96B03077116BB /* NSFileManager+Haneke.swift in Sources */, + 5946A4834D77660F3D8188ED70FDC603 /* NSHTTPURLResponse+Haneke.swift in Sources */, + 2D93F149491F25BCC11EBF259DE1791D /* NSURLResponse+Haneke.swift in Sources */, + 25F558B3167CC7FAFCCC902B83ED0599 /* String+Haneke.swift in Sources */, + A257C7E3394A9813188DC886B978193F /* UIButton+Haneke.swift in Sources */, + 048BE8B1399E22885B758F58B5103AAF /* UIImage+Haneke.swift in Sources */, + 368FBAAE5E624FDDB6F39D1ACB1DA144 /* UIImageView+Haneke.swift in Sources */, + 9F0ED20EDA02495C3CE53351168BDA34 /* UIView+Haneke.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 80F9B6E78BA63EEBF904AB8AB1807D45 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 990478AA09857AE10ADAD5E40BDCF9B4 /* Pods-Pokedex-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F35FEC988ECD73463D93176BC71A43B1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0F981C56836FE34E921BC7253826A170 /* CustomDateFormatTransform.swift in Sources */, + EC1A896625476730D64BF9645624BBAD /* DataTransform.swift in Sources */, + 4215D7313CE6E738AAD80E9FEC6C60CC /* DateFormatterTransform.swift in Sources */, + F9B63BDA169DB048D41DA8395261AEBA /* DateTransform.swift in Sources */, + B2EFEFFB34D517F8E9A203B674AEBD13 /* DictionaryTransform.swift in Sources */, + 706840688BA7E9BDE5F4DD2C0E558835 /* EnumOperators.swift in Sources */, + FCE734BD83FB03D3DC9F8AA843ECD73B /* EnumTransform.swift in Sources */, + DB87FF0D3B17ABB5452FDD4D70C9A84D /* FromJSON.swift in Sources */, + 551FB4DF0E5072BB849BB4FCE74F7361 /* HexColorTransform.swift in Sources */, + B9C39C539A810D1958AEEF1AEC0FD75C /* ImmutableMappable.swift in Sources */, + 1894026C296B8A77711607C98ED40C86 /* IntegerOperators.swift in Sources */, + 255C4ADB2BD82FEEF86A3D4D43F31C63 /* ISO8601DateTransform.swift in Sources */, + A5BFC49ED41BC416BEBF4772517AB741 /* Map.swift in Sources */, + 2D89AB26203628C04B3E87D045525701 /* MapError.swift in Sources */, + 67A4D8A24085ADC44A65404E73461B43 /* Mappable.swift in Sources */, + 77CA4CD47748C0B69982A6D82C2799D5 /* Mapper.swift in Sources */, + 6C2FE27FDBD6621AAB57E4082419C347 /* NSDecimalNumberTransform.swift in Sources */, + 59109302859941E04E87DC7044DFEE89 /* ObjectMapper-dummy.m in Sources */, + EA67527CAF7ED571C8A84B66DDD70FBE /* Operators.swift in Sources */, + 134859C42E05396F62489E4329ECF6EA /* ToJSON.swift in Sources */, + 194858D10B9B1DD9FFEFBE4EAA0700F3 /* TransformOf.swift in Sources */, + 18E9B5E96557418567FCB7DCC559299F /* TransformOperators.swift in Sources */, + 27156C9092B7A82E24CF96312A941150 /* TransformType.swift in Sources */, + F527B0A072DFD754B471E4C1F6B16C48 /* URLTransform.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 7FBEAB6421362BCA2DFABA527FD5B538 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = ObjectMapper; + target = CD6C9FB6B052E1CF663F8A56041EA163 /* ObjectMapper */; + targetProxy = C5C448A2D4C887B9F868C28C631F76AA /* PBXContainerItemProxy */; + }; + E1A8261C324CCBA4FB8C82F1F8926272 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = HanekeSwift; + target = AE4759774042D8E013517E82C6F7A058 /* HanekeSwift */; + targetProxy = E56F134377D168FDF16FF3AF1B60D015 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 0A8B4428A5EB653CE57B856B4C2409A0 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = CF4FB5751CED7C16D2FC91CB60E179A0 /* Pods-Pokedex.release.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = "Target Support Files/Pods-Pokedex/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-Pokedex/Pods-Pokedex.modulemap"; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = Pods_Pokedex; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 193CE6A6263DDD9038E8C597F2665427 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 563C9F1B6B4974A0B84D1C00B8CE5920 /* Pods-Pokedex.debug.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = "Target Support Files/Pods-Pokedex/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-Pokedex/Pods-Pokedex.modulemap"; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = Pods_Pokedex; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 5FB3F99BABE79D973032E7EEB58C2A18 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 41BA2A930FD5CA74D50DB1070E886036 /* HanekeSwift.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/HanekeSwift/HanekeSwift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/HanekeSwift/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/HanekeSwift/HanekeSwift.modulemap"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = Haneke; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 8A848143D50DAE92A8CA6F44B4683CAC /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 41BA2A930FD5CA74D50DB1070E886036 /* HanekeSwift.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/HanekeSwift/HanekeSwift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/HanekeSwift/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/HanekeSwift/HanekeSwift.modulemap"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = Haneke; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 9BFC9E4A7AAD7A607ACE06D95A401A5A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGNING_REQUIRED = NO; + COPY_PHASE_STRIP = NO; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_DEBUG=1", + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + ONLY_ACTIVE_ARCH = YES; + PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Debug; + }; + C03B8870130C98D1B02B59D003687524 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGNING_REQUIRED = NO; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_RELEASE=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = "${SRCROOT}/../build"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + D5EB31EB31D6DCD868C220B8AA6A2851 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 15C534A9FD25C3C336E2EE386CFEB8D2 /* ObjectMapper.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/ObjectMapper/ObjectMapper-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/ObjectMapper/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/ObjectMapper/ObjectMapper.modulemap"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = ObjectMapper; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + EB8E3B08D7417C6A83E91BF649652236 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 15C534A9FD25C3C336E2EE386CFEB8D2 /* ObjectMapper.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREFIX_HEADER = "Target Support Files/ObjectMapper/ObjectMapper-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/ObjectMapper/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/ObjectMapper/ObjectMapper.modulemap"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = ObjectMapper; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 23CFD86DE455F2B998EC09D589DA285D /* Build configuration list for PBXNativeTarget "ObjectMapper" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EB8E3B08D7417C6A83E91BF649652236 /* Debug */, + D5EB31EB31D6DCD868C220B8AA6A2851 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9BFC9E4A7AAD7A607ACE06D95A401A5A /* Debug */, + C03B8870130C98D1B02B59D003687524 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2F820C6BD8776D7C930AC05F2598D2CB /* Build configuration list for PBXNativeTarget "Pods-Pokedex" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 193CE6A6263DDD9038E8C597F2665427 /* Debug */, + 0A8B4428A5EB653CE57B856B4C2409A0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6DD468FB375E9C1971E9F0CFE51A4135 /* Build configuration list for PBXNativeTarget "HanekeSwift" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8A848143D50DAE92A8CA6F44B4683CAC /* Debug */, + 5FB3F99BABE79D973032E7EEB58C2A18 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = D41D8CD98F00B204E9800998ECF8427E /* Project object */; +} diff --git a/Pods/Pods.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/HanekeSwift.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/HanekeSwift.xcscheme new file mode 100644 index 0000000..bfe3609 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/HanekeSwift.xcscheme @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/ObjectMapper.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/ObjectMapper.xcscheme new file mode 100644 index 0000000..1d38d2a --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/ObjectMapper.xcscheme @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/Pods-Pokedex.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/Pods-Pokedex.xcscheme new file mode 100644 index 0000000..2bb60ea --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/Pods-Pokedex.xcscheme @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/xcschememanagement.plist b/Pods/Pods.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..a6a8caf --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,42 @@ + + + + + SchemeUserState + + HanekeSwift.xcscheme + + isShown + + + ObjectMapper.xcscheme + + isShown + + + Pods-Pokedex.xcscheme + + isShown + + + + SuppressBuildableAutocreation + + AE4759774042D8E013517E82C6F7A058 + + primary + + + B2E279D716CBA3590C2B59941BFC1C02 + + primary + + + CD6C9FB6B052E1CF663F8A56041EA163 + + primary + + + + + diff --git a/Pods/Target Support Files/HanekeSwift/HanekeSwift-dummy.m b/Pods/Target Support Files/HanekeSwift/HanekeSwift-dummy.m new file mode 100644 index 0000000..073edf1 --- /dev/null +++ b/Pods/Target Support Files/HanekeSwift/HanekeSwift-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_HanekeSwift : NSObject +@end +@implementation PodsDummy_HanekeSwift +@end diff --git a/Pods/Target Support Files/HanekeSwift/HanekeSwift-prefix.pch b/Pods/Target Support Files/HanekeSwift/HanekeSwift-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/HanekeSwift/HanekeSwift-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/Pods/Target Support Files/HanekeSwift/HanekeSwift-umbrella.h b/Pods/Target Support Files/HanekeSwift/HanekeSwift-umbrella.h new file mode 100644 index 0000000..8a0af64 --- /dev/null +++ b/Pods/Target Support Files/HanekeSwift/HanekeSwift-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double HanekeVersionNumber; +FOUNDATION_EXPORT const unsigned char HanekeVersionString[]; + diff --git a/Pods/Target Support Files/HanekeSwift/HanekeSwift.modulemap b/Pods/Target Support Files/HanekeSwift/HanekeSwift.modulemap new file mode 100644 index 0000000..6b5d0f2 --- /dev/null +++ b/Pods/Target Support Files/HanekeSwift/HanekeSwift.modulemap @@ -0,0 +1,6 @@ +framework module Haneke { + umbrella header "HanekeSwift-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/HanekeSwift/HanekeSwift.xcconfig b/Pods/Target Support Files/HanekeSwift/HanekeSwift.xcconfig new file mode 100644 index 0000000..d0b56ba --- /dev/null +++ b/Pods/Target Support Files/HanekeSwift/HanekeSwift.xcconfig @@ -0,0 +1,10 @@ +CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/HanekeSwift +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" +OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/HanekeSwift +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES diff --git a/Pods/Target Support Files/HanekeSwift/Info.plist b/Pods/Target Support Files/HanekeSwift/Info.plist new file mode 100644 index 0000000..0a7e38b --- /dev/null +++ b/Pods/Target Support Files/HanekeSwift/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 0.10.1 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/ObjectMapper/Info.plist b/Pods/Target Support Files/ObjectMapper/Info.plist new file mode 100644 index 0000000..76e3ceb --- /dev/null +++ b/Pods/Target Support Files/ObjectMapper/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 2.2.9 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/ObjectMapper/ObjectMapper-dummy.m b/Pods/Target Support Files/ObjectMapper/ObjectMapper-dummy.m new file mode 100644 index 0000000..7033cce --- /dev/null +++ b/Pods/Target Support Files/ObjectMapper/ObjectMapper-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_ObjectMapper : NSObject +@end +@implementation PodsDummy_ObjectMapper +@end diff --git a/Pods/Target Support Files/ObjectMapper/ObjectMapper-prefix.pch b/Pods/Target Support Files/ObjectMapper/ObjectMapper-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/ObjectMapper/ObjectMapper-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/Pods/Target Support Files/ObjectMapper/ObjectMapper-umbrella.h b/Pods/Target Support Files/ObjectMapper/ObjectMapper-umbrella.h new file mode 100644 index 0000000..e993e40 --- /dev/null +++ b/Pods/Target Support Files/ObjectMapper/ObjectMapper-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double ObjectMapperVersionNumber; +FOUNDATION_EXPORT const unsigned char ObjectMapperVersionString[]; + diff --git a/Pods/Target Support Files/ObjectMapper/ObjectMapper.modulemap b/Pods/Target Support Files/ObjectMapper/ObjectMapper.modulemap new file mode 100644 index 0000000..539c248 --- /dev/null +++ b/Pods/Target Support Files/ObjectMapper/ObjectMapper.modulemap @@ -0,0 +1,6 @@ +framework module ObjectMapper { + umbrella header "ObjectMapper-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/ObjectMapper/ObjectMapper.xcconfig b/Pods/Target Support Files/ObjectMapper/ObjectMapper.xcconfig new file mode 100644 index 0000000..f3b6fb8 --- /dev/null +++ b/Pods/Target Support Files/ObjectMapper/ObjectMapper.xcconfig @@ -0,0 +1,11 @@ +CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/ObjectMapper +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" +OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/ObjectMapper +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +SWIFT_VERSION = 3.2 diff --git a/Pods/Target Support Files/Pods-Pokedex/Info.plist b/Pods/Target Support Files/Pods-Pokedex/Info.plist new file mode 100644 index 0000000..2243fe6 --- /dev/null +++ b/Pods/Target Support Files/Pods-Pokedex/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-acknowledgements.markdown b/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-acknowledgements.markdown new file mode 100644 index 0000000..4088797 --- /dev/null +++ b/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-acknowledgements.markdown @@ -0,0 +1,219 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## HanekeSwift + +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +## ObjectMapper + +The MIT License (MIT) +Copyright (c) 2014 Hearst + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Generated by CocoaPods - https://cocoapods.org diff --git a/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-acknowledgements.plist b/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-acknowledgements.plist new file mode 100644 index 0000000..9b41910 --- /dev/null +++ b/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-acknowledgements.plist @@ -0,0 +1,257 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + License + Apache + Title + HanekeSwift + Type + PSGroupSpecifier + + + FooterText + The MIT License (MIT) +Copyright (c) 2014 Hearst + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + License + MIT + Title + ObjectMapper + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-dummy.m b/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-dummy.m new file mode 100644 index 0000000..032b8c8 --- /dev/null +++ b/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_Pokedex : NSObject +@end +@implementation PodsDummy_Pods_Pokedex +@end diff --git a/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-frameworks.sh b/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-frameworks.sh new file mode 100755 index 0000000..1e3ba82 --- /dev/null +++ b/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-frameworks.sh @@ -0,0 +1,114 @@ +#!/bin/sh +set -e + +echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + +SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" + +# This protects against multiple targets copying the same framework dependency at the same time. The solution +# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html +RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") + +install_framework() +{ + if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then + local source="${BUILT_PRODUCTS_DIR}/$1" + elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then + local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" + elif [ -r "$1" ]; then + local source="$1" + fi + + local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + + if [ -L "${source}" ]; then + echo "Symlinked..." + source="$(readlink "${source}")" + fi + + # Use filter instead of exclude so missing patterns don't throw errors. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" + + local basename + basename="$(basename -s .framework "$1")" + binary="${destination}/${basename}.framework/${basename}" + if ! [ -r "$binary" ]; then + binary="${destination}/${basename}" + fi + + # Strip invalid architectures so "fat" simulator / device frameworks work on device + if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then + strip_invalid_archs "$binary" + fi + + # Resign the code if required by the build settings to avoid unstable apps + code_sign_if_enabled "${destination}/$(basename "$1")" + + # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. + if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then + local swift_runtime_libs + swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) + for lib in $swift_runtime_libs; do + echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" + rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" + code_sign_if_enabled "${destination}/${lib}" + done + fi +} + +# Copies the dSYM of a vendored framework +install_dsym() { + local source="$1" + if [ -r "$source" ]; then + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}" + fi +} + +# Signs a framework with the provided identity +code_sign_if_enabled() { + if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then + # Use the current code_sign_identitiy + echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" + local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'" + + if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + code_sign_cmd="$code_sign_cmd &" + fi + echo "$code_sign_cmd" + eval "$code_sign_cmd" + fi +} + +# Strip invalid architectures +strip_invalid_archs() { + binary="$1" + # Get architectures for current file + archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" + stripped="" + for arch in $archs; do + if ! [[ "${ARCHS}" == *"$arch"* ]]; then + # Strip non-valid architectures in-place + lipo -remove "$arch" -output "$binary" "$binary" || exit 1 + stripped="$stripped $arch" + fi + done + if [[ "$stripped" ]]; then + echo "Stripped $binary of architectures:$stripped" + fi +} + + +if [[ "$CONFIGURATION" == "Debug" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/HanekeSwift/Haneke.framework" + install_framework "${BUILT_PRODUCTS_DIR}/ObjectMapper/ObjectMapper.framework" +fi +if [[ "$CONFIGURATION" == "Release" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/HanekeSwift/Haneke.framework" + install_framework "${BUILT_PRODUCTS_DIR}/ObjectMapper/ObjectMapper.framework" +fi +if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + wait +fi diff --git a/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-resources.sh b/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-resources.sh new file mode 100755 index 0000000..a7df440 --- /dev/null +++ b/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-resources.sh @@ -0,0 +1,106 @@ +#!/bin/sh +set -e + +mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + +RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt +> "$RESOURCES_TO_COPY" + +XCASSET_FILES=() + +# This protects against multiple targets copying the same framework dependency at the same time. The solution +# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html +RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") + +case "${TARGETED_DEVICE_FAMILY}" in + 1,2) + TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" + ;; + 1) + TARGET_DEVICE_ARGS="--target-device iphone" + ;; + 2) + TARGET_DEVICE_ARGS="--target-device ipad" + ;; + 3) + TARGET_DEVICE_ARGS="--target-device tv" + ;; + 4) + TARGET_DEVICE_ARGS="--target-device watch" + ;; + *) + TARGET_DEVICE_ARGS="--target-device mac" + ;; +esac + +install_resource() +{ + if [[ "$1" = /* ]] ; then + RESOURCE_PATH="$1" + else + RESOURCE_PATH="${PODS_ROOT}/$1" + fi + if [[ ! -e "$RESOURCE_PATH" ]] ; then + cat << EOM +error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. +EOM + exit 1 + fi + case $RESOURCE_PATH in + *.storyboard) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true + ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} + ;; + *.xib) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true + ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} + ;; + *.framework) + echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true + mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + ;; + *.xcdatamodel) + echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true + xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" + ;; + *.xcdatamodeld) + echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true + xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" + ;; + *.xcmappingmodel) + echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true + xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" + ;; + *.xcassets) + ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" + XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") + ;; + *) + echo "$RESOURCE_PATH" || true + echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" + ;; + esac +} + +mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then + mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi +rm -f "$RESOURCES_TO_COPY" + +if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] +then + # Find all other xcassets (this unfortunately includes those of path pods and other targets). + OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) + while read line; do + if [[ $line != "${PODS_ROOT}*" ]]; then + XCASSET_FILES+=("$line") + fi + done <<<"$OTHER_XCASSETS" + + printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi diff --git a/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-umbrella.h b/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-umbrella.h new file mode 100644 index 0000000..0159734 --- /dev/null +++ b/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double Pods_PokedexVersionNumber; +FOUNDATION_EXPORT const unsigned char Pods_PokedexVersionString[]; + diff --git a/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex.debug.xcconfig b/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex.debug.xcconfig new file mode 100644 index 0000000..d929373 --- /dev/null +++ b/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex.debug.xcconfig @@ -0,0 +1,11 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/HanekeSwift" "$PODS_CONFIGURATION_BUILD_DIR/ObjectMapper" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/HanekeSwift/Haneke.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/ObjectMapper/ObjectMapper.framework/Headers" +OTHER_LDFLAGS = $(inherited) -framework "Haneke" -framework "ObjectMapper" +OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods diff --git a/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex.modulemap b/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex.modulemap new file mode 100644 index 0000000..19984b9 --- /dev/null +++ b/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex.modulemap @@ -0,0 +1,6 @@ +framework module Pods_Pokedex { + umbrella header "Pods-Pokedex-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex.release.xcconfig b/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex.release.xcconfig new file mode 100644 index 0000000..d929373 --- /dev/null +++ b/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex.release.xcconfig @@ -0,0 +1,11 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/HanekeSwift" "$PODS_CONFIGURATION_BUILD_DIR/ObjectMapper" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/HanekeSwift/Haneke.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/ObjectMapper/ObjectMapper.framework/Headers" +OTHER_LDFLAGS = $(inherited) -framework "Haneke" -framework "ObjectMapper" +OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" +PODS_BUILD_DIR = $BUILD_DIR +PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods diff --git a/Pokedex.xcodeproj/project.pbxproj b/Pokedex.xcodeproj/project.pbxproj new file mode 100644 index 0000000..811949f --- /dev/null +++ b/Pokedex.xcodeproj/project.pbxproj @@ -0,0 +1,674 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 3CFC6F0F1D98716000B4EBB5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CFC6F0E1D98716000B4EBB5 /* AppDelegate.swift */; }; + 3CFC6F111D98716000B4EBB5 /* OpeningViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CFC6F101D98716000B4EBB5 /* OpeningViewController.swift */; }; + 3CFC6F141D98716000B4EBB5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3CFC6F121D98716000B4EBB5 /* Main.storyboard */; }; + 3CFC6F161D98716000B4EBB5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3CFC6F151D98716000B4EBB5 /* Assets.xcassets */; }; + 3CFC6F191D98716000B4EBB5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3CFC6F171D98716000B4EBB5 /* LaunchScreen.storyboard */; }; + 3CFC6F241D98716000B4EBB5 /* PokedexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CFC6F231D98716000B4EBB5 /* PokedexTests.swift */; }; + 3CFC6F2F1D98716000B4EBB5 /* PokedexUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CFC6F2E1D98716000B4EBB5 /* PokedexUITests.swift */; }; + 3CFC6F3D1D98719100B4EBB5 /* pokeData.json in Resources */ = {isa = PBXBuildFile; fileRef = 3CFC6F3C1D98719100B4EBB5 /* pokeData.json */; }; + 3CFC6F3F1D9871F100B4EBB5 /* Pokemon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CFC6F3E1D9871F100B4EBB5 /* Pokemon.swift */; }; + 3CFC6F411D9871FC00B4EBB5 /* PokemonGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CFC6F401D9871FC00B4EBB5 /* PokemonGenerator.swift */; }; + 4A7BFDDCB2AC77B5C6D55938 /* Pods_Pokedex.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FD3D9A9D7EA5605DD0F3127 /* Pods_Pokedex.framework */; }; + D1442FD51F738E8400A13797 /* PokemonTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1442FD41F738E8400A13797 /* PokemonTableViewCell.swift */; }; + D1D4986F1F70CBAF000D37B4 /* PokemonProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1D4986E1F70CBAF000D37B4 /* PokemonProfileViewController.swift */; }; + D1D498711F70CBDB000D37B4 /* PokemonCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1D498701F70CBDB000D37B4 /* PokemonCollectionViewCell.swift */; }; + D1D498731F70D26A000D37B4 /* SearchResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1D498721F70D26A000D37B4 /* SearchResultsViewController.swift */; }; + D1DDD92D1F74879C009170AD /* GoogleSearchWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1DDD92C1F74879C009170AD /* GoogleSearchWebViewController.swift */; }; + D1EAA7281F749FC400938DDE /* FavoritesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1EAA7271F749FC400938DDE /* FavoritesViewController.swift */; }; + F34545711F70C77A005FA8D2 /* CategorySelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34545701F70C77A005FA8D2 /* CategorySelectionViewController.swift */; }; + F34545751F70C7A8005FA8D2 /* SearchBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34545741F70C7A8005FA8D2 /* SearchBarViewController.swift */; }; + F34545781F7497FA005FA8D2 /* TypeSelectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34545721F70C796005FA8D2 /* TypeSelectorViewController.swift */; }; + F345457A1F7498A4005FA8D2 /* TypeTwoTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34545791F7498A4005FA8D2 /* TypeTwoTableViewCell.swift */; }; + F3CBCBB31F74D53C00B90E57 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3CBCBB21F74D53C00B90E57 /* Utils.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 3CFC6F201D98716000B4EBB5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 3CFC6F031D98716000B4EBB5 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 3CFC6F0A1D98716000B4EBB5; + remoteInfo = Pokedex; + }; + 3CFC6F2B1D98716000B4EBB5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 3CFC6F031D98716000B4EBB5 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 3CFC6F0A1D98716000B4EBB5; + remoteInfo = Pokedex; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 3CFC6F0B1D98716000B4EBB5 /* Pokedex.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Pokedex.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 3CFC6F0E1D98716000B4EBB5 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 3CFC6F101D98716000B4EBB5 /* OpeningViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpeningViewController.swift; sourceTree = ""; }; + 3CFC6F131D98716000B4EBB5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 3CFC6F151D98716000B4EBB5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 3CFC6F181D98716000B4EBB5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 3CFC6F1A1D98716000B4EBB5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 3CFC6F1F1D98716000B4EBB5 /* PokedexTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PokedexTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3CFC6F231D98716000B4EBB5 /* PokedexTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PokedexTests.swift; sourceTree = ""; }; + 3CFC6F251D98716000B4EBB5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 3CFC6F2A1D98716000B4EBB5 /* PokedexUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PokedexUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3CFC6F2E1D98716000B4EBB5 /* PokedexUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PokedexUITests.swift; sourceTree = ""; }; + 3CFC6F301D98716000B4EBB5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 3CFC6F3C1D98719100B4EBB5 /* pokeData.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = pokeData.json; sourceTree = ""; }; + 3CFC6F3E1D9871F100B4EBB5 /* Pokemon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Pokemon.swift; sourceTree = ""; }; + 3CFC6F401D9871FC00B4EBB5 /* PokemonGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PokemonGenerator.swift; sourceTree = ""; }; + 6619062D4B7AB1C81C2FAFE2 /* Pods-Pokedex.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Pokedex.release.xcconfig"; path = "Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex.release.xcconfig"; sourceTree = ""; }; + 9FD3D9A9D7EA5605DD0F3127 /* Pods_Pokedex.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Pokedex.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D1442FD41F738E8400A13797 /* PokemonTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PokemonTableViewCell.swift; sourceTree = ""; }; + D1D4986E1F70CBAF000D37B4 /* PokemonProfileViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PokemonProfileViewController.swift; sourceTree = ""; }; + D1D498701F70CBDB000D37B4 /* PokemonCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PokemonCollectionViewCell.swift; sourceTree = ""; }; + D1D498721F70D26A000D37B4 /* SearchResultsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchResultsViewController.swift; sourceTree = ""; }; + D1DDD92C1F74879C009170AD /* GoogleSearchWebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GoogleSearchWebViewController.swift; sourceTree = ""; }; + D1EAA7271F749FC400938DDE /* FavoritesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FavoritesViewController.swift; sourceTree = ""; }; + F34545701F70C77A005FA8D2 /* CategorySelectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CategorySelectionViewController.swift; sourceTree = ""; }; + F34545721F70C796005FA8D2 /* TypeSelectorViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypeSelectorViewController.swift; sourceTree = ""; }; + F34545741F70C7A8005FA8D2 /* SearchBarViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchBarViewController.swift; sourceTree = ""; }; + F34545761F73439E005FA8D2 /* TypeTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypeTableViewCell.swift; sourceTree = ""; }; + F34545791F7498A4005FA8D2 /* TypeTwoTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypeTwoTableViewCell.swift; sourceTree = ""; }; + F3CBCBB21F74D53C00B90E57 /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; + F72D93904C4008A767EE2184 /* Pods-Pokedex.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Pokedex.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 3CFC6F081D98716000B4EBB5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4A7BFDDCB2AC77B5C6D55938 /* Pods_Pokedex.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3CFC6F1C1D98716000B4EBB5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3CFC6F271D98716000B4EBB5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 3C6F5151844E7305F1E34CDF /* Frameworks */ = { + isa = PBXGroup; + children = ( + 9FD3D9A9D7EA5605DD0F3127 /* Pods_Pokedex.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 3CFC6F021D98716000B4EBB5 = { + isa = PBXGroup; + children = ( + 3CFC6F0D1D98716000B4EBB5 /* Pokedex */, + 3CFC6F221D98716000B4EBB5 /* PokedexTests */, + 3CFC6F2D1D98716000B4EBB5 /* PokedexUITests */, + 3CFC6F0C1D98716000B4EBB5 /* Products */, + E8079F6DA8A8CB140B466964 /* Pods */, + 3C6F5151844E7305F1E34CDF /* Frameworks */, + ); + sourceTree = ""; + }; + 3CFC6F0C1D98716000B4EBB5 /* Products */ = { + isa = PBXGroup; + children = ( + 3CFC6F0B1D98716000B4EBB5 /* Pokedex.app */, + 3CFC6F1F1D98716000B4EBB5 /* PokedexTests.xctest */, + 3CFC6F2A1D98716000B4EBB5 /* PokedexUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 3CFC6F0D1D98716000B4EBB5 /* Pokedex */ = { + isa = PBXGroup; + children = ( + F3CBCBB21F74D53C00B90E57 /* Utils.swift */, + 3CFC6F3C1D98719100B4EBB5 /* pokeData.json */, + 3CFC6F0E1D98716000B4EBB5 /* AppDelegate.swift */, + 3CFC6F101D98716000B4EBB5 /* OpeningViewController.swift */, + F34545701F70C77A005FA8D2 /* CategorySelectionViewController.swift */, + F34545721F70C796005FA8D2 /* TypeSelectorViewController.swift */, + F34545761F73439E005FA8D2 /* TypeTableViewCell.swift */, + F34545791F7498A4005FA8D2 /* TypeTwoTableViewCell.swift */, + F34545741F70C7A8005FA8D2 /* SearchBarViewController.swift */, + D1EAA7271F749FC400938DDE /* FavoritesViewController.swift */, + D1D498721F70D26A000D37B4 /* SearchResultsViewController.swift */, + D1442FD41F738E8400A13797 /* PokemonTableViewCell.swift */, + D1D498701F70CBDB000D37B4 /* PokemonCollectionViewCell.swift */, + D1D4986E1F70CBAF000D37B4 /* PokemonProfileViewController.swift */, + D1DDD92C1F74879C009170AD /* GoogleSearchWebViewController.swift */, + 3CFC6F121D98716000B4EBB5 /* Main.storyboard */, + 3CFC6F151D98716000B4EBB5 /* Assets.xcassets */, + 3CFC6F171D98716000B4EBB5 /* LaunchScreen.storyboard */, + 3CFC6F1A1D98716000B4EBB5 /* Info.plist */, + 3CFC6F3E1D9871F100B4EBB5 /* Pokemon.swift */, + 3CFC6F401D9871FC00B4EBB5 /* PokemonGenerator.swift */, + ); + path = Pokedex; + sourceTree = ""; + }; + 3CFC6F221D98716000B4EBB5 /* PokedexTests */ = { + isa = PBXGroup; + children = ( + 3CFC6F231D98716000B4EBB5 /* PokedexTests.swift */, + 3CFC6F251D98716000B4EBB5 /* Info.plist */, + ); + path = PokedexTests; + sourceTree = ""; + }; + 3CFC6F2D1D98716000B4EBB5 /* PokedexUITests */ = { + isa = PBXGroup; + children = ( + 3CFC6F2E1D98716000B4EBB5 /* PokedexUITests.swift */, + 3CFC6F301D98716000B4EBB5 /* Info.plist */, + ); + path = PokedexUITests; + sourceTree = ""; + }; + E8079F6DA8A8CB140B466964 /* Pods */ = { + isa = PBXGroup; + children = ( + F72D93904C4008A767EE2184 /* Pods-Pokedex.debug.xcconfig */, + 6619062D4B7AB1C81C2FAFE2 /* Pods-Pokedex.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 3CFC6F0A1D98716000B4EBB5 /* Pokedex */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3CFC6F331D98716000B4EBB5 /* Build configuration list for PBXNativeTarget "Pokedex" */; + buildPhases = ( + DA83389FAB2A5737D0D7FFFC /* [CP] Check Pods Manifest.lock */, + 3CFC6F071D98716000B4EBB5 /* Sources */, + 3CFC6F081D98716000B4EBB5 /* Frameworks */, + 3CFC6F091D98716000B4EBB5 /* Resources */, + FAF3F461C2E1111880AA1F9A /* [CP] Embed Pods Frameworks */, + C680F4B3A1671113B44B059F /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Pokedex; + productName = Pokedex; + productReference = 3CFC6F0B1D98716000B4EBB5 /* Pokedex.app */; + productType = "com.apple.product-type.application"; + }; + 3CFC6F1E1D98716000B4EBB5 /* PokedexTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3CFC6F361D98716000B4EBB5 /* Build configuration list for PBXNativeTarget "PokedexTests" */; + buildPhases = ( + 3CFC6F1B1D98716000B4EBB5 /* Sources */, + 3CFC6F1C1D98716000B4EBB5 /* Frameworks */, + 3CFC6F1D1D98716000B4EBB5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 3CFC6F211D98716000B4EBB5 /* PBXTargetDependency */, + ); + name = PokedexTests; + productName = PokedexTests; + productReference = 3CFC6F1F1D98716000B4EBB5 /* PokedexTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 3CFC6F291D98716000B4EBB5 /* PokedexUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3CFC6F391D98716000B4EBB5 /* Build configuration list for PBXNativeTarget "PokedexUITests" */; + buildPhases = ( + 3CFC6F261D98716000B4EBB5 /* Sources */, + 3CFC6F271D98716000B4EBB5 /* Frameworks */, + 3CFC6F281D98716000B4EBB5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 3CFC6F2C1D98716000B4EBB5 /* PBXTargetDependency */, + ); + name = PokedexUITests; + productName = PokedexUITests; + productReference = 3CFC6F2A1D98716000B4EBB5 /* PokedexUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 3CFC6F031D98716000B4EBB5 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0800; + LastUpgradeCheck = 0820; + ORGANIZATIONNAME = trainingprogram; + TargetAttributes = { + 3CFC6F0A1D98716000B4EBB5 = { + CreatedOnToolsVersion = 8.0; + ProvisioningStyle = Automatic; + }; + 3CFC6F1E1D98716000B4EBB5 = { + CreatedOnToolsVersion = 8.0; + ProvisioningStyle = Automatic; + TestTargetID = 3CFC6F0A1D98716000B4EBB5; + }; + 3CFC6F291D98716000B4EBB5 = { + CreatedOnToolsVersion = 8.0; + ProvisioningStyle = Automatic; + TestTargetID = 3CFC6F0A1D98716000B4EBB5; + }; + }; + }; + buildConfigurationList = 3CFC6F061D98716000B4EBB5 /* Build configuration list for PBXProject "Pokedex" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 3CFC6F021D98716000B4EBB5; + productRefGroup = 3CFC6F0C1D98716000B4EBB5 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 3CFC6F0A1D98716000B4EBB5 /* Pokedex */, + 3CFC6F1E1D98716000B4EBB5 /* PokedexTests */, + 3CFC6F291D98716000B4EBB5 /* PokedexUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 3CFC6F091D98716000B4EBB5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3CFC6F191D98716000B4EBB5 /* LaunchScreen.storyboard in Resources */, + 3CFC6F161D98716000B4EBB5 /* Assets.xcassets in Resources */, + 3CFC6F3D1D98719100B4EBB5 /* pokeData.json in Resources */, + 3CFC6F141D98716000B4EBB5 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3CFC6F1D1D98716000B4EBB5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3CFC6F281D98716000B4EBB5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + C680F4B3A1671113B44B059F /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + DA83389FAB2A5737D0D7FFFC /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Pokedex-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + FAF3F461C2E1111880AA1F9A /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/HanekeSwift/Haneke.framework", + "${BUILT_PRODUCTS_DIR}/ObjectMapper/ObjectMapper.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Haneke.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ObjectMapper.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Pokedex/Pods-Pokedex-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 3CFC6F071D98716000B4EBB5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F34545751F70C7A8005FA8D2 /* SearchBarViewController.swift in Sources */, + D1D498711F70CBDB000D37B4 /* PokemonCollectionViewCell.swift in Sources */, + D1EAA7281F749FC400938DDE /* FavoritesViewController.swift in Sources */, + D1442FD51F738E8400A13797 /* PokemonTableViewCell.swift in Sources */, + 3CFC6F111D98716000B4EBB5 /* OpeningViewController.swift in Sources */, + F3CBCBB31F74D53C00B90E57 /* Utils.swift in Sources */, + D1DDD92D1F74879C009170AD /* GoogleSearchWebViewController.swift in Sources */, + 3CFC6F411D9871FC00B4EBB5 /* PokemonGenerator.swift in Sources */, + 3CFC6F0F1D98716000B4EBB5 /* AppDelegate.swift in Sources */, + F34545711F70C77A005FA8D2 /* CategorySelectionViewController.swift in Sources */, + D1D4986F1F70CBAF000D37B4 /* PokemonProfileViewController.swift in Sources */, + 3CFC6F3F1D9871F100B4EBB5 /* Pokemon.swift in Sources */, + F345457A1F7498A4005FA8D2 /* TypeTwoTableViewCell.swift in Sources */, + F34545781F7497FA005FA8D2 /* TypeSelectorViewController.swift in Sources */, + D1D498731F70D26A000D37B4 /* SearchResultsViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3CFC6F1B1D98716000B4EBB5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3CFC6F241D98716000B4EBB5 /* PokedexTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3CFC6F261D98716000B4EBB5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3CFC6F2F1D98716000B4EBB5 /* PokedexUITests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 3CFC6F211D98716000B4EBB5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 3CFC6F0A1D98716000B4EBB5 /* Pokedex */; + targetProxy = 3CFC6F201D98716000B4EBB5 /* PBXContainerItemProxy */; + }; + 3CFC6F2C1D98716000B4EBB5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 3CFC6F0A1D98716000B4EBB5 /* Pokedex */; + targetProxy = 3CFC6F2B1D98716000B4EBB5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 3CFC6F121D98716000B4EBB5 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 3CFC6F131D98716000B4EBB5 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 3CFC6F171D98716000B4EBB5 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 3CFC6F181D98716000B4EBB5 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 3CFC6F311D98716000B4EBB5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 3CFC6F321D98716000B4EBB5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 3CFC6F341D98716000B4EBB5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F72D93904C4008A767EE2184 /* Pods-Pokedex.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = Pokedex/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = org.mdb.Pokedex; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + 3CFC6F351D98716000B4EBB5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6619062D4B7AB1C81C2FAFE2 /* Pods-Pokedex.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = Pokedex/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = org.mdb.Pokedex; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; + 3CFC6F371D98716000B4EBB5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = PokedexTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = org.mdb.PokedexTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Pokedex.app/Pokedex"; + }; + name = Debug; + }; + 3CFC6F381D98716000B4EBB5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = PokedexTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = org.mdb.PokedexTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Pokedex.app/Pokedex"; + }; + name = Release; + }; + 3CFC6F3A1D98716000B4EBB5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + INFOPLIST_FILE = PokedexUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = org.mdb.PokedexUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + TEST_TARGET_NAME = Pokedex; + }; + name = Debug; + }; + 3CFC6F3B1D98716000B4EBB5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + INFOPLIST_FILE = PokedexUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = org.mdb.PokedexUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + TEST_TARGET_NAME = Pokedex; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 3CFC6F061D98716000B4EBB5 /* Build configuration list for PBXProject "Pokedex" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3CFC6F311D98716000B4EBB5 /* Debug */, + 3CFC6F321D98716000B4EBB5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3CFC6F331D98716000B4EBB5 /* Build configuration list for PBXNativeTarget "Pokedex" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3CFC6F341D98716000B4EBB5 /* Debug */, + 3CFC6F351D98716000B4EBB5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3CFC6F361D98716000B4EBB5 /* Build configuration list for PBXNativeTarget "PokedexTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3CFC6F371D98716000B4EBB5 /* Debug */, + 3CFC6F381D98716000B4EBB5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3CFC6F391D98716000B4EBB5 /* Build configuration list for PBXNativeTarget "PokedexUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3CFC6F3A1D98716000B4EBB5 /* Debug */, + 3CFC6F3B1D98716000B4EBB5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 3CFC6F031D98716000B4EBB5 /* Project object */; +} diff --git a/Pokedex.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Pokedex.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..65efe0b --- /dev/null +++ b/Pokedex.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Pokedex.xcodeproj/project.xcworkspace/xcuserdata/Annie.xcuserdatad/UserInterfaceState.xcuserstate b/Pokedex.xcodeproj/project.xcworkspace/xcuserdata/Annie.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..6ac2d40c9999fb250a0b2d875548dcf01f7158a2 GIT binary patch literal 50344 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

YB>syT7k+!<)B=sC~6C88)_$N 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 P6C(U__2F@J>TCZ4o^^;2 literal 0 HcmV?d00001 diff --git a/Pokedex.xcodeproj/project.xcworkspace/xcuserdata/sameersuresh.xcuserdatad/UserInterfaceState.xcuserstate b/Pokedex.xcodeproj/project.xcworkspace/xcuserdata/sameersuresh.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..2b8b7522520d8bc7a9dbf12e4fcf22e8f4005475 GIT binary patch literal 13693 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 T&lUhMA;LFzyYTJ%o1XiBjmO;y literal 0 HcmV?d00001 diff --git a/Pokedex.xcodeproj/xcuserdata/Annie.xcuserdatad/xcschemes/Pokedex.xcscheme b/Pokedex.xcodeproj/xcuserdata/Annie.xcuserdatad/xcschemes/Pokedex.xcscheme new file mode 100644 index 0000000..c55e2e2 --- /dev/null +++ b/Pokedex.xcodeproj/xcuserdata/Annie.xcuserdatad/xcschemes/Pokedex.xcscheme @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pokedex.xcodeproj/xcuserdata/Annie.xcuserdatad/xcschemes/xcschememanagement.plist b/Pokedex.xcodeproj/xcuserdata/Annie.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..ca0861d --- /dev/null +++ b/Pokedex.xcodeproj/xcuserdata/Annie.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,32 @@ + + + + + SchemeUserState + + Pokedex.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 3CFC6F0A1D98716000B4EBB5 + + primary + + + 3CFC6F1E1D98716000B4EBB5 + + primary + + + 3CFC6F291D98716000B4EBB5 + + primary + + + + + diff --git a/Pokedex.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Pokedex.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..0fad589 --- /dev/null +++ b/Pokedex.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,23 @@ + + + + + + + + + diff --git a/Pokedex.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/Pokedex.xcscheme b/Pokedex.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/Pokedex.xcscheme new file mode 100644 index 0000000..c55e2e2 --- /dev/null +++ b/Pokedex.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/Pokedex.xcscheme @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pokedex.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/xcschememanagement.plist b/Pokedex.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..ca0861d --- /dev/null +++ b/Pokedex.xcodeproj/xcuserdata/louie_mc.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,32 @@ + + + + + SchemeUserState + + Pokedex.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 3CFC6F0A1D98716000B4EBB5 + + primary + + + 3CFC6F1E1D98716000B4EBB5 + + primary + + + 3CFC6F291D98716000B4EBB5 + + primary + + + + + diff --git a/Pokedex.xcodeproj/xcuserdata/sahillamba.xcuserdatad/xcschemes/Pokedex.xcscheme b/Pokedex.xcodeproj/xcuserdata/sahillamba.xcuserdatad/xcschemes/Pokedex.xcscheme new file mode 100644 index 0000000..81401a4 --- /dev/null +++ b/Pokedex.xcodeproj/xcuserdata/sahillamba.xcuserdatad/xcschemes/Pokedex.xcscheme @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pokedex.xcodeproj/xcuserdata/sahillamba.xcuserdatad/xcschemes/xcschememanagement.plist b/Pokedex.xcodeproj/xcuserdata/sahillamba.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..ca0861d --- /dev/null +++ b/Pokedex.xcodeproj/xcuserdata/sahillamba.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,32 @@ + + + + + SchemeUserState + + Pokedex.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 3CFC6F0A1D98716000B4EBB5 + + primary + + + 3CFC6F1E1D98716000B4EBB5 + + primary + + + 3CFC6F291D98716000B4EBB5 + + primary + + + + + diff --git a/Pokedex.xcodeproj/xcuserdata/sameersuresh.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Pokedex.xcodeproj/xcuserdata/sameersuresh.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..7402bba --- /dev/null +++ b/Pokedex.xcodeproj/xcuserdata/sameersuresh.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,23 @@ + + + + + + + + + diff --git a/Pokedex.xcodeproj/xcuserdata/sameersuresh.xcuserdatad/xcschemes/Pokedex.xcscheme b/Pokedex.xcodeproj/xcuserdata/sameersuresh.xcuserdatad/xcschemes/Pokedex.xcscheme new file mode 100644 index 0000000..08f897e --- /dev/null +++ b/Pokedex.xcodeproj/xcuserdata/sameersuresh.xcuserdatad/xcschemes/Pokedex.xcscheme @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pokedex.xcodeproj/xcuserdata/sameersuresh.xcuserdatad/xcschemes/xcschememanagement.plist b/Pokedex.xcodeproj/xcuserdata/sameersuresh.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..ca0861d --- /dev/null +++ b/Pokedex.xcodeproj/xcuserdata/sameersuresh.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,32 @@ + + + + + SchemeUserState + + Pokedex.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 3CFC6F0A1D98716000B4EBB5 + + primary + + + 3CFC6F1E1D98716000B4EBB5 + + primary + + + 3CFC6F291D98716000B4EBB5 + + primary + + + + + diff --git a/Pokedex.xcworkspace/contents.xcworkspacedata b/Pokedex.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..99d5be8 --- /dev/null +++ b/Pokedex.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Pokedex.xcworkspace/xcuserdata/louie_mc.xcuserdatad/UserInterfaceState.xcuserstate b/Pokedex.xcworkspace/xcuserdata/louie_mc.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..38e7c83922f3f7eba9afd85585598a699c9e7eae GIT binary patch literal 38575 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 gA|2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pokedex/.DS_Store b/Pokedex/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f892562cf7a3add0d0c9db77fe2f883413d60345 GIT binary patch literal 10244 zcmeHM-A)rh6h2c>3rfU9g2X3y+&&Ua?MIWx^UB_fe;l&6UdBFdt&96W=^ z9)-W>x~pWOo?%D>8~*Gy|Fe&46Y=GoTqb3Jl;kn@jd|DD_h_pc&8% z>@dLhgMrF27s*a2<<)_Q3;`f}(Jc$why$dK5y@O6JE4@Szzm}Y5vhtO#1Nr6zBhO{ zWG<4OP=@LxLUj_6Wf4UvLRyEOA%~O5g;GB?1Db)|3~=mzjvmq$J_RLyw`r1mYLY|i z6fC%2$#Ojlqxpc{M;-qq3tB{Hf#Bm~BkuR1_m)b?0qpc7w7>qHw$=2vBHQ1rE!Xjb zsi_|#)6;w6MF%HH(26H2l0-e<9zTvTa4}CC_tr+NQPa*v-|!^K)J; zFrAuRj}3ph;?&AsGw(HOWnbbfn!yHirJ>cq;Z|$<-t7tF#?8C!38OVTJ2PS2nz_?% zXR||N(+?Kbs@v~c@7o_fNm@umw-pFd%V)eEK-!yPz2F&RjEir}o;nHKF`AR<8cy4IK;5Qd>cD`;COt^7<_xq!J=fm{LRV>#0*J*Q{%1l5KscXjHFnLz5N z1+0A?GoA$BE^z(iLCAbh=v<#_bZb9yqi5YETHrN~0 z1Bj27s<{|xR(W*y)l1)rYhEE$llMN{^S%6n6MybL= z&c%eCdAT<>bU8)I82kG}9P3&FYf*aFI%dKCoa&57|B2feN!VDzJgo%&0bH~9h|!q$ z7>B@Q-#FyCW*<}VFDqx6Z>f4ZHrNLhPREa< p^4KYsT+q%%vJ*=5p#1+o19beKI%lEd|L!>>&Oa&9_0f(0e*=&HzJ&k) literal 0 HcmV?d00001 diff --git a/Pokedex/AppDelegate.swift b/Pokedex/AppDelegate.swift new file mode 100644 index 0000000..ee63ed2 --- /dev/null +++ b/Pokedex/AppDelegate.swift @@ -0,0 +1,46 @@ +// +// AppDelegate.swift +// Pokedex +// +// Created by SAMEER SURESH on 9/25/16. +// Copyright © 2016 trainingprogram. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + func applicationWillResignActive(_ application: UIApplication) { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. + } + + func applicationDidEnterBackground(_ application: UIApplication) { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(_ application: UIApplication) { + // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. + } + + func applicationDidBecomeActive(_ application: UIApplication) { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + } + + func applicationWillTerminate(_ application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + +} + diff --git a/Pokedex/Assets.xcassets/.DS_Store b/Pokedex/Assets.xcassets/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..1c3cba566cf24d6a1cc92d2d909683f9c7888849 GIT binary patch literal 6148 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 literal 0 HcmV?d00001 diff --git a/Pokedex/Assets.xcassets/pokeball.imageset/Contents.json b/Pokedex/Assets.xcassets/pokeball.imageset/Contents.json new file mode 100644 index 0000000..6198bba --- /dev/null +++ b/Pokedex/Assets.xcassets/pokeball.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "pokeball.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Pokedex/Assets.xcassets/pokeball.imageset/pokeball.png b/Pokedex/Assets.xcassets/pokeball.imageset/pokeball.png new file mode 100644 index 0000000000000000000000000000000000000000..fb885d8eb13dc4ca2e9441c2667b926f705f7223 GIT binary patch literal 8837 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 Od>swLJ6JXQi2nk{Wr= + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pokedex/Base.lproj/Main.storyboard b/Pokedex/Base.lproj/Main.storyboard new file mode 100644 index 0000000..38ed025 --- /dev/null +++ b/Pokedex/Base.lproj/Main.storyboard @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pokedex/CategorySelectionViewController.swift b/Pokedex/CategorySelectionViewController.swift new file mode 100644 index 0000000..8f54235 --- /dev/null +++ b/Pokedex/CategorySelectionViewController.swift @@ -0,0 +1,300 @@ +// +// CategorySelectionViewController.swift +// Pokedex +// +// Created by Louie McConnell on 9/18/17. +// Copyright © 2017 trainingprogram. All rights reserved. +// + +import UIKit + +class CategorySelectionViewController: UIViewController { + + + // UI + // + // + + // labels + var minAttackPointsLabel: UILabel! + var minDefensePointsLabel: UILabel! + var minHealthPointsLabel: UILabel! + + // sliders + var attackPointsSlider: UISlider! + var defensePointsSlider: UISlider! + var healthPointsSlider: UISlider! + + // type selector button + var typeButton: UIButton! + var submitButton: UIButton! + + // Values + // + // + + var minAttack = 10 + var maxAttack = 100 + var minDefense = 10 + var maxDefense = 100 + var minHealth = 10 + var maxHealth = 100 + + var types: [String] = ["Bug", "Grass", "Dark", "Ground", "Dragon", "Ice", "Electric", "Normal", "Fairy", "Poison", "Fighting", "Psychic", "Fire", "Rock", "Flying", "Steel", "Ghost", "Water"] + + var results: [Pokemon]! + + + override func viewDidLoad() { + super.viewDidLoad() + + // Add in UI Elements + addAttackLabel() + addAttackSlider() + addDefenseLabel() + addDefenseSlider() + addHealthLabel() + addHealthSlider() + addTypeButton() + addSubmitButton() + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if segue.identifier == "toSearchResults" { + let searchResultsVC = segue.destination as! SearchResultsViewController + searchResultsVC.results = self.results + + } + } + + func addAttackLabel() { + // UI + minAttackPointsLabel = UILabel() + minAttackPointsLabel.frame = CGRect( + x: 20, + y: 80, + width: 250, + height: 50 + ) + minAttackPointsLabel.text = "Minimum Attack Points: " + String(minAttack) + minAttackPointsLabel.textAlignment = .left + + self.view.addSubview(minAttackPointsLabel) + } + + func addAttackSlider() { + // TODO: Determine the maximum and minimum values programatically. + + // get max value + + var pokeArray = PokemonGenerator.getPokemonArray() + maxAttack = pokeArray.reduce(pokeArray[0], { + ($0).attack > ($1).attack ? $0 : $1 + }).attack + + minAttack = pokeArray.reduce(pokeArray[0], { + ($0).attack < ($1).attack ? $0 : $1 + }).attack + + // UI + + attackPointsSlider = UISlider() + attackPointsSlider.frame = CGRect( + x: 20, + y: minAttackPointsLabel.frame.maxY, + width: self.view.frame.width - 40, + height: 50 + ) + attackPointsSlider.isContinuous = true + attackPointsSlider.minimumValue = Float(minAttack) + attackPointsSlider.maximumValue = Float(maxAttack) + self.view.addSubview(attackPointsSlider) + + // Events + attackPointsSlider.addTarget(self, action: #selector(attackSliderChanged), for: .valueChanged) + + } + + func addDefenseLabel() { + + + // UI + minDefensePointsLabel = UILabel() + minDefensePointsLabel.frame = CGRect( + x: 20, + y: attackPointsSlider.frame.maxY + 20, + width: 250, + height: 50 + ) + minDefensePointsLabel.text = "Minimum Defense Points: " + String(minDefense) + minDefensePointsLabel.textAlignment = .left + + self.view.addSubview(minDefensePointsLabel) + } + + func addDefenseSlider() { + + var pokeArray = PokemonGenerator.getPokemonArray() + + maxDefense = pokeArray.reduce(pokeArray[0], { + ($0).defense > ($1).defense ? $0 : $1 + }).defense + + minDefense = pokeArray.reduce(pokeArray[0], { + ($0).defense < ($1).defense ? $0 : $1 + }).defense + + // UI + defensePointsSlider = UISlider() + defensePointsSlider.frame = CGRect( + x: 20, + y: minDefensePointsLabel.frame.maxY, + width: self.view.frame.width - 40, + height: 50 + ) + defensePointsSlider.isContinuous = true + defensePointsSlider.minimumValue = Float(minDefense) + defensePointsSlider.maximumValue = Float(maxDefense) + self.view.addSubview(defensePointsSlider) + + // Events + defensePointsSlider.addTarget(self, action: #selector(defenseSliderChanged), for: .valueChanged) + } + + func addHealthLabel() { + // UI + minHealthPointsLabel = UILabel() + minHealthPointsLabel.frame = CGRect( + x: 20, + y: defensePointsSlider.frame.maxY + 20, + width: 250, + height: 50 + ) + minHealthPointsLabel.text = "Minimum Health Points: " + String(minHealth) + minHealthPointsLabel.textAlignment = .left + + self.view.addSubview(minHealthPointsLabel) + } + + func addHealthSlider() { + + var pokeArray = PokemonGenerator.getPokemonArray() + + maxHealth = pokeArray.reduce(pokeArray[0], { + ($0).health > ($1).health ? $0 : $1 + }).health + + minHealth = pokeArray.reduce(pokeArray[0], { + ($0).health < ($1).health ? $0 : $1 + }).health + + + // UI + healthPointsSlider = UISlider() + healthPointsSlider.frame = CGRect( + x: 20, + y: minHealthPointsLabel.frame.maxY, + width: self.view.frame.width - 40, + height: 50 + ) + healthPointsSlider.isContinuous = true + healthPointsSlider.minimumValue = Float(minHealth) + healthPointsSlider.maximumValue = Float(maxHealth) + self.view.addSubview(healthPointsSlider) + + // Events + healthPointsSlider.addTarget(self, action: #selector(healthSliderChanged), for: .valueChanged) + } + + func addTypeButton() { + typeButton = UIButton() + typeButton.frame = CGRect( + x: 20, + y: healthPointsSlider.frame.maxY + 20, + width: self.view.frame.width - 40, + height: 40 + ) + typeButton.setTitle("Type", for: .normal) + typeButton.setTitleColor(UIColor.white, for: .normal) + typeButton.layer.cornerRadius = 16 + typeButton.backgroundColor = UIColor.blue + typeButton.contentHorizontalAlignment = .center + typeButton.addTarget(self, action: #selector(openTypeSelectionVC), for: .touchUpInside) + + self.view.addSubview(typeButton) + } + + func addSubmitButton() { + submitButton = UIButton() + submitButton.frame = CGRect( + x: self.view.center.x - 80, + y: self.view.frame.height - 110, + width: 160, + height: 40 + ) + submitButton.setTitle("Submit", for: .normal) + submitButton.setTitleColor(UIColor.white, for: .normal) + submitButton.layer.cornerRadius = 16 + submitButton.backgroundColor = UIColor.blue + submitButton.contentHorizontalAlignment = .center + self.view.addSubview(submitButton) + submitButton.addTarget(self, action: #selector(toSearchResults), for: .touchUpInside) + } + + func toSearchResults() { + results = PokemonGenerator.getPokemonArray() + .filter({$0.health >= Int(healthPointsSlider.value)}) + .filter({$0.attack >= Int(attackPointsSlider.value)}) + .filter({$0.defense >= Int(defensePointsSlider.value)}) + + // for pokemon in results, we only keep it if one of the types is in types + results = results.filter({ + $0.types.map({ (type: String) -> Bool in + self.types.contains(type) + }).reduce(false, {$0 || $1}) + }) + + /* + func typeInTypes(pokemon: Pokemon) { + var returnVal = false + for type in pokemon.types { + returnVal = returnVal or (type in self.types) + } + return returnVal + } +*/ + print(results) + print("types") + print(types) + self.performSegue(withIdentifier: "toSearchResults", sender: self) + } + + func attackSliderChanged() { + minAttackPointsLabel.text = "Minimum Attack Points: " + String(attackPointsSlider.value) + } + + func defenseSliderChanged() { + minDefensePointsLabel.text = "Minimum Defense Points: " + String(defensePointsSlider.value) + } + + func healthSliderChanged() { + minHealthPointsLabel.text = "Minimum Health Points: " + String(healthPointsSlider.value) + } + + func openTypeSelectionVC() { + self.performSegue(withIdentifier: "toTypeSelector", sender: self) + } + + @IBAction func unwindToCategorySelector(segue: UIStoryboardSegue) {} + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destinationViewController. + // Pass the selected object to the new view controller. + } + */ + +} diff --git a/Pokedex/FavoritesViewController.swift b/Pokedex/FavoritesViewController.swift new file mode 100644 index 0000000..fbd8724 --- /dev/null +++ b/Pokedex/FavoritesViewController.swift @@ -0,0 +1,126 @@ +// +// FavoritesViewController.swift +// Pokedex +// +// Created by Annie Tang on 9/21/17. +// Copyright © 2017 trainingprogram. All rights reserved. +// + +import UIKit +import ObjectMapper + +class FavoritesViewController: UIViewController { + + var tableView: UITableView! + var results: [Pokemon]! = [] + var pokemonImages: [UIImage]! + let userDefaults = UserDefaults.standard + + override func viewDidLoad() { + super.viewDidLoad() + if let jsonifiedPokemon = userDefaults.array(forKey: "favoritesArray") { + for json in jsonifiedPokemon { + results.append(Pokemon(JSONString: json as! String)!) + } + } + + setupTableView() + setUpPokemonImages() + } + + override func viewWillAppear(_ animated: Bool) { + if let jsonifiedPokemon = userDefaults.array(forKey: "favoritesArray") { + for json in jsonifiedPokemon { + results.append(Pokemon(JSONString: json as! String)!) + } + } + tableView.reloadData() + } + + func setupTableView(){ + tableView = UITableView(frame: + CGRect(x: 0, + y: UIApplication.shared.statusBarFrame.maxY + view.frame.height * 0.1 + 10, + width: view.frame.width, + height: view.frame.height - UIApplication.shared.statusBarFrame.maxY)) + + tableView.register(PokemonTableViewCell.self, forCellReuseIdentifier: "tableViewCell") + tableView.delegate = self + tableView.dataSource = self + tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 50/2, right: 0) + view.addSubview(tableView) + } + + func setUpPokemonImages() { + pokemonImages = [] + for p in results { + pokemonImages.append(grabImagesFromURL(p: p)) + } + } + + func grabImagesFromURL(p: Pokemon)->UIImage { + /* taken from stack overflow question: 24231680 */ + //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch + var image: UIImage! + + let url = URL(string: p.imageUrl) + + /* if url is not nil, try to get the contents of it and use it */ + if url != nil { + do { + let data = try Data(contentsOf: url!) + image = UIImage(data: data) + } + catch { + image = #imageLiteral(resourceName: "pokeball") + } + } + else { + print("default") + image = #imageLiteral(resourceName: "question") + } + + if image == nil { + image = #imageLiteral(resourceName: "question") + } + + print("image: ", image) + return image + } +} + +extension FavoritesViewController: UITableViewDataSource, UITableViewDelegate { + /* number of sections/types of cells in tableview */ + func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + /* number of cells in section of tableview */ + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return results.count + } + + /* dequeue & set up cell at indexPath.row + pass over the pokemon image, name, and number into the tableview cell */ + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + + /* dequeue cell and remove/reset from subview; initialize new cell */ + let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as! PokemonTableViewCell + for subview in cell.contentView.subviews { + subview.removeFromSuperview() + } + cell.awakeFromNib() + + let p: Pokemon = results[indexPath.row] + cell.pokePic.image = pokemonImages[indexPath.row] + cell.nameLabel.text = p.name + cell.numberLabel.text = "# " + String(p.number) + return cell + } + + /* sets each row to be 1/10 of frame view */ + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return view.frame.height / 10 + } + +} diff --git a/Pokedex/GoogleSearchWebViewController.swift b/Pokedex/GoogleSearchWebViewController.swift new file mode 100644 index 0000000..5cc9ff2 --- /dev/null +++ b/Pokedex/GoogleSearchWebViewController.swift @@ -0,0 +1,29 @@ +// +// GoogleSearchWebView.swift +// Pokedex +// +// Created by Annie Tang on 9/20/17. +// Copyright © 2017 trainingprogram. All rights reserved. +// + +import UIKit + +class GoogleSearchWebViewController: UIViewController, UIWebViewDelegate { + + /* credit to stack overflow, question 39682344 */ + + var webView: UIWebView! + var pokeName: String! + + override func viewDidLoad() { + super.viewDidLoad() + webView = UIWebView(frame: UIScreen.main.bounds) + webView.delegate = self + view.addSubview(webView) + if let url = URL(string: "https://google.com/search?q=" + pokeName) { + print(url) + let request = URLRequest(url: url) + webView.loadRequest(request) + } + } +} diff --git a/Pokedex/Info.plist b/Pokedex/Info.plist new file mode 100644 index 0000000..7a57b9c --- /dev/null +++ b/Pokedex/Info.plist @@ -0,0 +1,43 @@ + + + + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Pokedex/OpeningViewController.swift b/Pokedex/OpeningViewController.swift new file mode 100644 index 0000000..ff2e372 --- /dev/null +++ b/Pokedex/OpeningViewController.swift @@ -0,0 +1,127 @@ +// +// ViewController.swift +// Pokedex +// +// Created by SAMEER SURESH on 9/25/16. +// Copyright © 2016 trainingprogram. All rights reserved. +// + +import UIKit + +class OpeningViewController: UIViewController { + + var pokedexImageView: UIImageView! + var searchLabel: UILabel! + var categoryButton: UIButton! + var nameButton: UIButton! + var randomButton: UIButton! + var image: UIImage = #imageLiteral(resourceName: "image") + + var results : [Pokemon]! + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view, typically from a nib. + addPokedexImage() + addSearchLabel() + addCategoryButton() + addNameButton() + addRandomButton() + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if segue.identifier == "toSearchResults" { + let searchResultsVC = segue.destination as! SearchResultsViewController + searchResultsVC.results = PokemonGenerator.getRandomPokemon(numPokemon: 20) + } + } + + func addPokedexImage() { + pokedexImageView = UIImageView() + pokedexImageView.frame = CGRect( + x: 40, + y: 100, + width: self.view.frame.width - 80, + height: self.view.frame.width - 80 + ) + pokedexImageView.image = image + self.view.addSubview(pokedexImageView) + } + + func addSearchLabel() { + searchLabel = UILabel() + searchLabel.frame = CGRect( + x: self.view.center.x - 60, + y: self.view.frame.height * 0.6, + width: 120, + height: 50 + ) + searchLabel.text = "search by: " + searchLabel.textAlignment = .center + self.view.addSubview(searchLabel) + } + + func addCategoryButton() { + categoryButton = UIButton() + categoryButton.frame = CGRect( + x: self.view.center.x - 80, + y: searchLabel.frame.maxY + 10, + width: 160, + height: 40 + ) + categoryButton.setTitle("category", for: .normal) + categoryButton.setTitleColor(UIColor.white, for: .normal) + categoryButton.layer.cornerRadius = 16 + categoryButton.backgroundColor = UIColor.blue + categoryButton.contentHorizontalAlignment = .center + self.view.addSubview(categoryButton) + categoryButton.addTarget(self, action: #selector(goToCategorySelectorVC), for: .touchUpInside) + } + + func addNameButton() { + nameButton = UIButton() + nameButton.frame = CGRect( + x: self.view.center.x - 80, + y: categoryButton.frame.maxY + 10, + width: 160, + height: 40 + ) + nameButton.setTitle("name/number", for: .normal) + nameButton.setTitleColor(UIColor.white, for: .normal) + nameButton.layer.cornerRadius = 16 + nameButton.backgroundColor = UIColor.blue + nameButton.contentHorizontalAlignment = .center + nameButton.addTarget(self, action: #selector(goToSearchBarVC), for: .touchUpInside) + self.view.addSubview(nameButton) + } + + func addRandomButton() { + randomButton = UIButton() + randomButton.frame = CGRect( + x: self.view.center.x - 80, + y: nameButton.frame.maxY + 10, + width: 160, + height: 40 + ) + randomButton.setTitle("random", for: .normal) + randomButton.setTitleColor(UIColor.white, for: .normal) + randomButton.layer.cornerRadius = 16 + randomButton.backgroundColor = UIColor.blue + randomButton.contentHorizontalAlignment = .center + randomButton.addTarget(self, action: #selector(getSearchResults), for: .touchUpInside) + self.view.addSubview(randomButton) + } + + func goToCategorySelectorVC() { + self.performSegue(withIdentifier: "toCategorySelector", sender: self) + } + + func goToSearchBarVC() { + self.performSegue(withIdentifier: "toSearchBar", sender: self) + } + + func getSearchResults() { + self.performSegue(withIdentifier: "toSearchResults", sender: self) + } +} + diff --git a/Pokedex/Pokemon.swift b/Pokedex/Pokemon.swift new file mode 100644 index 0000000..32ca51e --- /dev/null +++ b/Pokedex/Pokemon.swift @@ -0,0 +1,78 @@ +// +// Pokemon.swift +// Pokedex +// +// Created by SAMEER SURESH on 9/25/16. +// Copyright © 2016 trainingprogram. All rights reserved. +// + +import Foundation +import ObjectMapper + +class Pokemon : Mappable{ + + /* Note 1: + There are 18 different types of Pokemon, and a single Pokemon can inherit multiple types: + Bug, Grass, Dark, Ground, Dragon, Ice, Electric, Normal, Fairy, + Poison, Fighting, Psychic, Fire, Rock, Flying, Steel, Ghost, Water + */ + + /* Note 2: + The image for each Pokemon is not provided, but a URL is. You should look up how to get an image from it's URL. + */ + + /* Note 3: + You can access the properties of Pokemon using dot notation (e.g. pokemon.name, pokemon.number, etc.) + */ + + var name: String! + var number: Int! + var attack: Int! + var defense: Int! + var health: Int! + var specialAttack: Int! + var specialDefense: Int! + var species: String! + var speed: Int! + var total: Int! + var types: [String]! + var imageUrl: String! + + init(name: String, number: Int, attack: Int, defense: Int, health: Int, spAttack: Int, spDef: Int, species: String, speed: Int, total: Int, types: [String]) { + self.name = name + self.number = number + self.attack = attack + self.defense = defense + self.health = health + self.specialAttack = spAttack + self.specialDefense = spDef + self.species = species + self.speed = speed + self.total = total + self.types = types + // self.imageUrl = "http://img.pokemondb.net/artwork/\(name.components(separatedBy: " ")[0].lowercased()).jpg" + var strippedName = String(name.components(separatedBy: " ")[0].lowercased().characters.filter{"abcdefghijklmnopqrstuvwxyz".characters.contains($0)}) + self.imageUrl = "http://img.pokemondb.net/artwork/\(strippedName).jpg" + } + + required init?(map: Map) { + + } + + + func mapping(map: Map) { + name <- map["name"] + number <- map["number"] + attack <- map["attack"] + defense <- map["defense"] + health <- map["health"] + specialAttack <- map["specialAttack"] + specialDefense <- map["specialDefense"] + species <- map["species"] + speed <- map["speed"] + total <- map["total"] + types <- map["types"] + imageUrl <- map["imageUrl"] + } + +} diff --git a/Pokedex/PokemonCollectionViewCell.swift b/Pokedex/PokemonCollectionViewCell.swift new file mode 100644 index 0000000..6a39a14 --- /dev/null +++ b/Pokedex/PokemonCollectionViewCell.swift @@ -0,0 +1,47 @@ +// +// PokemonCollectionViewCell.swift +// Pokedex +// +// Created by Annie Tang on 9/18/17. +// Copyright © 2017 trainingprogram. All rights reserved. +// + +import UIKit + +class PokemonCollectionViewCell: UICollectionViewCell { + + let grayBlue = UIColor(red:0.58, green:0.67, blue:0.75, alpha:1.0) + let lightGrayBlue = UIColor(red:0.83, green:0.86, blue:0.88, alpha:1.0) + let darkGray = UIColor(red:0.17, green:0.25, blue:0.30, alpha:1.0) + + var pokemonObject: Pokemon! + var pokePic: UIImageView = UIImageView(image: #imageLiteral(resourceName: "pokeball")) + var nameLabel: UILabel! + + override func awakeFromNib() { + super.awakeFromNib() + setupNameLabel() + setupPokePic() + } + + func setupNameLabel() { + nameLabel = UILabel(frame: CGRect(x: contentView.frame.width * 0.05, y: contentView.frame.width * 0.85, width: contentView.frame.width * 0.9 , height: contentView.frame.height * 0.15)) + nameLabel.textColor = darkGray + nameLabel.textAlignment = .center + nameLabel.font = nameLabel.font.withSize(10) + contentView.addSubview(nameLabel) + + nameLabel.layer.zPosition = 1 + nameLabel.layer.cornerRadius = 1 + nameLabel.layer.backgroundColor = lightGrayBlue.cgColor + } + + func setupPokePic() { + pokePic = UIImageView(frame: CGRect(x: 0, y: 0, width: contentView.frame.width, height: contentView.frame.height)) + pokePic.contentMode = .scaleAspectFit + pokePic.clipsToBounds = true + contentView.addSubview(pokePic) + + + } +} diff --git a/Pokedex/PokemonCollectionViewCell.swift.orig b/Pokedex/PokemonCollectionViewCell.swift.orig new file mode 100644 index 0000000..3147858 --- /dev/null +++ b/Pokedex/PokemonCollectionViewCell.swift.orig @@ -0,0 +1,42 @@ +// +// PokemonCollectionViewCell.swift +// Pokedex +// +// Created by Annie Tang on 9/18/17. +// Copyright © 2017 trainingprogram. All rights reserved. +// + +import UIKit + +class PokemonCollectionViewCell: UICollectionViewCell { + var pokemonImageView: UIImageView! + +/* POKEMON PROPERTIES + let name: String! + let number: Int! + let attack: Int! + let defense: Int! + let health: Int! + let specialAttack: Int! + let specialDefense: Int! + let species: String! + let speed: Int! + let total: Int! + let types: [String] + let imageUrl: String! */ + + override func awakeFromNib() { + +<<<<<<< HEAD + pokemonImage = UIImageView(frame: CGRect(x: contentView.frame.width*0.15, y: contentView.frame.height*0.15, width: contentView.frame.width*0.7, height: contentView.frame.height*0.7)) +// pokemonImage = getPokemonImage() + pokemonImage.contentMode = .scaleAspectFill + contentView.addSubview(pokemonImage) + } +======= + pokemonImageView = UIImageView(frame: CGRect(x: contentView.frame.width*0.15, y: contentView.frame.height*0.15, width: contentView.frame.width*0.7, height: contentView.frame.height*0.7)) + pokemonImageView.contentMode = .scaleAspectFill + contentView.addSubview(pokemonImageView) + } +>>>>>>> f13fadab11ac1d63e18959776177fdaee91a9e5c +} diff --git a/Pokedex/PokemonGenerator.swift b/Pokedex/PokemonGenerator.swift new file mode 100644 index 0000000..768859b --- /dev/null +++ b/Pokedex/PokemonGenerator.swift @@ -0,0 +1,62 @@ +// +// PokemonGenerator.swift +// Pokedex +// +// Created by SAMEER SURESH on 9/25/16. +// Copyright © 2016 trainingprogram. All rights reserved. +// + +import Foundation + +class PokemonGenerator { + + static func getPokemonArray() -> [Pokemon] { + var pokemonArray: [Pokemon] = [] + if let path = Bundle.main.path(forResource: "pokeData", ofType: "json") + { + if let jsonData = NSData(contentsOfFile: path) { + do { + let json = try JSONSerialization.jsonObject(with: jsonData as Data, options: .mutableContainers) as! [String:AnyObject] + + for key in json.keys { + let pokemonData = json[key] as! [String:AnyObject] + let number = Int(pokemonData["#"] as! String)! + let attack = Int(pokemonData["Attack"] as! String)! + let defense = Int(pokemonData["Defense"] as! String)! + let hp = Int(pokemonData["HP"] as! String)! + let spatk = Int(pokemonData["Sp. Atk"] as! String)! + let spdef = Int(pokemonData["Sp. Def"] as! String)! + let species = pokemonData["Species"] as! String + let speed = Int(pokemonData["Speed"] as! String)! + let total = Int(pokemonData["Total"] as! String)! + let type = pokemonData["Type"] as! [String] + pokemonArray.append(Pokemon(name: key, number: number, attack: attack, defense: defense, health: hp, spAttack: spatk, spDef: spdef, species: species, speed: speed, total: total, types: type)) + } + } catch { + NSLog("Could not load Pokemon array") + } + + } + } + return pokemonArray + } + + static func getRandomPokemon(numPokemon: Int) -> [Pokemon] { + var results: [Pokemon] = [] + let pokeArray: [Pokemon] = self.getPokemonArray() + while results.count != numPokemon { + + let randomElement = pokeArray[Int(arc4random_uniform(UInt32(pokeArray.count)))] + + // if randomElement in results + if (results.contains{$0.name == randomElement.name}) { + continue + } else { + results.append(randomElement) + } + + } + print(results) + return results + } +} diff --git a/Pokedex/PokemonProfileViewController.swift b/Pokedex/PokemonProfileViewController.swift new file mode 100644 index 0000000..80e4232 --- /dev/null +++ b/Pokedex/PokemonProfileViewController.swift @@ -0,0 +1,203 @@ +// +// PokemonViewController.swift +// Pokedex +// +// Created by Annie Tang on 9/18/17. +// Copyright © 2017 trainingprogram. All rights reserved. +// + +import UIKit +import ObjectMapper + +class PokemonProfileViewController: UIViewController { + + let grayBlue = UIColor(red:0.58, green:0.67, blue:0.75, alpha:1.0) + let lightGrayBlue = UIColor(red:0.83, green:0.86, blue:0.88, alpha:1.0) + let darkGray = UIColor(red:0.17, green:0.25, blue:0.30, alpha:1.0) + + var p: Pokemon! + + var pokemonImage: UIImage! + var pokemonImageView: UIImageView! + var nameLabel: UILabel! + + let userDefaults = UserDefaults.standard + + override func viewDidLoad() { + super.viewDidLoad() + + setupImage() + setupNameAndNumber() + setUpStatisticsLabels() + addSearchButton() + addFavoriteButton() + } + + func setupImage() { + pokemonImageView = UIImageView(frame: + CGRect(x: view.frame.width * 0.1, + y: view.frame.width * 0.25, + width: view.frame.width * 0.8, + height: view.frame.width * 0.5)) + pokemonImageView.image = pokemonImage + pokemonImageView.contentMode = .scaleAspectFit + pokemonImageView.clipsToBounds = true + view.addSubview(pokemonImageView) + + Utils.getImage(url: p.imageUrl) { img in + self.pokemonImageView.image = img + } + if pokemonImageView.image == nil { + pokemonImageView.image = #imageLiteral(resourceName: "pokeball") + } + } + + func setupNameAndNumber() { + let nameLabel = UILabel(frame: + CGRect(x: view.frame.width * 0.1, + y: view.frame.width * 0.67, + width: view.frame.width * 0.8, + height: view.frame.height * 0.2)) + nameLabel.text = p.name + nameLabel.textColor = UIColor.darkGray + nameLabel.textAlignment = .left + nameLabel.font = nameLabel.font.withSize(20) + view.addSubview(nameLabel) + + let numberLabel = UILabel(frame: + CGRect(x: view.frame.width * 0.1, + y: view.frame.width * 0.67, + width: view.frame.width * 0.8, + height: view.frame.height * 0.2)) + numberLabel.text = " # " + String(p.number) + numberLabel.textColor = .lightGray + numberLabel.textAlignment = .right + numberLabel.font = numberLabel.font.withSize(14) + view.addSubview(numberLabel) + } + + func setUpStatisticsLabels() { + var labels: [UILabel] = [] + let labelsNames: [String] = ["Attack", "Defense", "Health", "Special Attack", "Special Defense", "Species", "Speed", "Total", "Type"] + + let info: [String] = [String(p.attack), String(p.defense), String(p.health), String(p.specialAttack), String(p.specialDefense), p.species, String(p.speed), String(p.total)] + + var OFFSET_Y: CGFloat = 0.43 + for i in 0...(labelsNames.count - 1) { + let label = UILabel(frame: + CGRect(x: view.frame.width * 0.1, + y: view.frame.height * OFFSET_Y, + width: view.frame.width * 0.8, + height: view.frame.height * 0.2)) + labels.append(label) + + let info = grabInfo(index: i, infoArr: info, types: p.types) + + label.text = labelsNames[i] + ": " + info + label.textColor = .darkGray + label.textAlignment = .left + label.font = label.font.withSize(15) + view.addSubview(label) + OFFSET_Y += 0.035 + } + } + + func addSearchButton() { + let searchButton = UIButton(frame: + CGRect(x: view.frame.width * 0.1, + y: view.frame.height * 0.85, + width: view.frame.width * 0.35, + height: view.frame.height * 0.08)) + searchButton.layer.cornerRadius = 3 + searchButton.backgroundColor = lightGrayBlue + searchButton.setTitle("Web Search", for: .normal) + searchButton.setTitleColor(darkGray, for: .normal) + searchButton.titleLabel?.font = UIFont(name: (searchButton.titleLabel?.font.fontName)!, size: 14) + searchButton.addTarget(self, action: #selector(searchGoogle), for: .touchUpInside) + + view.addSubview(searchButton) + } + + func addFavoriteButton() { + let favoriteButton = UIButton(frame: + CGRect(x: view.frame.width * 0.55, + y: view.frame.height * 0.85, + width: view.frame.width * 0.35, + height: view.frame.height * 0.08)) + favoriteButton.layer.cornerRadius = 3 + favoriteButton.backgroundColor = lightGrayBlue + favoriteButton.setTitle("Add to Favorites", for: .normal) + favoriteButton.setTitleColor(darkGray, for: .normal) + favoriteButton.titleLabel?.font = UIFont(name: (favoriteButton.titleLabel?.font.fontName)!, size: 14) + favoriteButton.addTarget(self, action: #selector(addToFavorites), for: .touchUpInside) + + view.addSubview(favoriteButton) + } + + func addToFavorites() { + /* + if UserDefaults.standard.object(forKey: p.name) as? NSData == nil { + UserDefaults.standard.set(p, forKey: p.name) + print("successful") + } + */ + + /* + if UserDefaults.standard.object(forKey: "favoritesArr") == nil { + var favorites: [Pokemon] = [p] + var encodedFavorites = NSKeyedArchiver.archivedData(withRootObject: favorites) + UserDefaults.standard.set(encodedFavorites, forKey: "favoritesArr") + } else { + var currentEncodedFavorites = UserDefaults.standard.object(forKey: "favoritesArr") + var decodedFavorites = NSKeyedUnarchiver.unarchiveObject(with: currentEncodedFavorites as! Data) as? [Pokemon] + decodedFavorites!.append(p) + + var newEncodedFavorites = NSKeyedArchiver.archivedData(withRootObject: decodedFavorites) + UserDefaults.standard.set(newEncodedFavorites, forKey: "favoritesArr") + + } + */ + var jsonifiedP = p.toJSONString() + + if userDefaults.object(forKey: "favoritesArray") == nil { + var favorites: [String] = [jsonifiedP!] + userDefaults.set(favorites, forKey: "favoritesArray") + print("howdy") + } else { + var jsonifiedPokemon = userDefaults.array(forKey: "favoritesArray") as! [String] + jsonifiedPokemon.append(jsonifiedP!) + userDefaults.set(jsonifiedPokemon, forKey: "favoritesArray") + } + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if segue.identifier == "segueToWebView" { + let webView = segue.destination as! GoogleSearchWebViewController + webView.pokeName = p.name + } + } + + + + func searchGoogle() { + performSegue(withIdentifier: "segueToWebView", sender: self) + } + + /* helper function to create a string with all of the pokemon's types */ + func grabInfo(index: Int!, infoArr: [String], types: [String]) -> String { + var info: String = "" + let delimiter: String = ", " + if index == infoArr.count { + for i in 0...(types.count - 1) { + if i == (types.count - 1) { + info += types[i] + } else { + info = info + types[i] + delimiter + } + } + } else { + info = infoArr[index] + } + return info + } +} diff --git a/Pokedex/PokemonTableViewCell.swift b/Pokedex/PokemonTableViewCell.swift new file mode 100644 index 0000000..db19347 --- /dev/null +++ b/Pokedex/PokemonTableViewCell.swift @@ -0,0 +1,57 @@ +// +// PokemonTableViewCell.swift +// Pokedex +// +// Created by Annie Tang on 9/20/17. +// Copyright © 2017 trainingprogram. All rights reserved. +// + +import UIKit + +class PokemonTableViewCell: UITableViewCell { + + var pokemonObject: Pokemon! + // how to get pokemon? do that PokemonTableViewCell.pokemonObject = something thing like fruitVC + var pokePic: UIImageView! = UIImageView(image: #imageLiteral(resourceName: "pokeball")) + + var nameLabel: UILabel! + var numberLabel: UILabel! + + //When do you think this is called? + override func awakeFromNib() { + super.awakeFromNib() + setUpImageView() + setUpNameLabel() + setUpNumberLabel() + } + + func setUpImageView() { + pokePic = UIImageView(frame: CGRect(x: 0, y: 0, width: contentView.frame.height, height: contentView.frame.height)) + pokePic.contentMode = .scaleAspectFill + pokePic.clipsToBounds = true + contentView.addSubview(pokePic) + } + + func setUpNameLabel() { + nameLabel = UILabel(frame: CGRect(x: contentView.frame.height * 1.2, y: 0, width: contentView.frame.width - contentView.frame.height * 1.2, height: contentView.frame.height * 0.7)) + nameLabel.textColor = UIColor.black + nameLabel.textAlignment = .left + nameLabel.font = nameLabel.font.withSize(18) + contentView.addSubview(nameLabel) + + } + + func setUpNumberLabel() { + numberLabel = UILabel(frame: CGRect(x: contentView.frame.height * 1.2, y: contentView.frame.height * 0.25, width: contentView.frame.width * 0.5, height: contentView.frame.height * 0.8)) + numberLabel.textColor = UIColor.lightGray + numberLabel.textAlignment = .left + numberLabel.font = nameLabel.font.withSize(14) + contentView.addSubview(numberLabel) + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + } + + +} diff --git a/Pokedex/PokemonTableViewController.swift b/Pokedex/PokemonTableViewController.swift new file mode 100644 index 0000000..19694c9 --- /dev/null +++ b/Pokedex/PokemonTableViewController.swift @@ -0,0 +1,94 @@ +// +// PokemonTableViewController.swift +// Pokedex +// +// Created by Annie Tang on 9/20/17. +// Copyright © 2017 trainingprogram. All rights reserved. +// + +import UIKit + +class PokemonTableViewController: UITableViewController { + + var pokemonArr: [Pokemon]! + + override func viewDidLoad() { + super.viewDidLoad() + + // Uncomment the following line to preserve selection between presentations + self.clearsSelectionOnViewWillAppear = false + + // Uncomment the following line to display an Edit button in the navigation bar for this view controller. + // self.navigationItem.rightBarButtonItem = self.editButtonItem() + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + // MARK: - Table view data source + + override func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return pokemonArr.count + } + + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + + let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) as! PokemonTableViewCell + cell.awakeFromNib() + + return cell + } + + /* + // Override to support conditional editing of the table view. + override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { + // Return false if you do not want the specified item to be editable. + return true + } + */ + + /* + // Override to support editing the table view. + override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { + if editingStyle == .delete { + // Delete the row from the data source + tableView.deleteRows(at: [indexPath], with: .fade) + } else if editingStyle == .insert { + // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view + } + } + */ + + /* + // Override to support rearranging the table view. + override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) { + + } + */ + + /* + // Override to support conditional rearranging of the table view. + override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { + // Return false if you do not want the item to be re-orderable. + return true + } + */ + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destinationViewController. + // Pass the selected object to the new view controller. + } + */ + +} diff --git a/Pokedex/SearchBarViewController.swift b/Pokedex/SearchBarViewController.swift new file mode 100644 index 0000000..f10ab89 --- /dev/null +++ b/Pokedex/SearchBarViewController.swift @@ -0,0 +1,88 @@ +// +// SearchBarViewController.swift +// Pokedex +// +// Created by Louie McConnell on 9/18/17. +// Copyright © 2017 trainingprogram. All rights reserved. +// + +import UIKit + +class SearchBarViewController: UIViewController { + + var searchBar : UITextField! + var submitButton : UIButton! + var results: [Pokemon]! + + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + addSearchBar() + addSubmitButton() + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if segue.identifier == "toSearchResults" { + let searchResultsVC = segue.destination as! SearchResultsViewController + searchResultsVC.results = self.results + print(self.results) + } + } + + func addSearchBar() { + searchBar = UITextField() + searchBar.frame = CGRect( + x: 20, + y: self.view.frame.height / 2 - 50, + width: self.view.frame.width - 40, + height: 40) + searchBar.layer.cornerRadius = 16 + searchBar.layer.borderColor = UIColor.lightGray.cgColor + searchBar.layer.borderWidth = 1 + searchBar.textAlignment = .center + searchBar.placeholder = "pokemon name or number" + view.addSubview(searchBar) + } + + func addSubmitButton() { + submitButton = UIButton() + submitButton.frame = CGRect( + x: self.view.center.x - 80, + y: self.view.frame.height - 110, + width: 160, + height: 40 + ) + submitButton.setTitle("submit", for: .normal) + submitButton.setTitleColor(UIColor.white, for: .normal) + submitButton.layer.cornerRadius = 16 + submitButton.backgroundColor = UIColor.blue + submitButton.contentHorizontalAlignment = .center + submitButton.addTarget(self, action: #selector(queryAndGoToSearchResults), for: .touchUpInside) + self.view.addSubview(submitButton) + } + + func queryAndGoToSearchResults() { + let pokeArray = PokemonGenerator.getPokemonArray() + + if Int(searchBar.text!) != nil { + results = pokeArray.filter{$0.number == Int(searchBar.text!)} + } else { + results = pokeArray.filter{$0.name.lowercased() == searchBar.text!.lowercased()} + } + + performSegue(withIdentifier: "toSearchResults", sender: self) + } + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destinationViewController. + // Pass the selected object to the new view controller. + } + */ + +} diff --git a/Pokedex/SearchResultsViewController.swift b/Pokedex/SearchResultsViewController.swift new file mode 100644 index 0000000..5604d93 --- /dev/null +++ b/Pokedex/SearchResultsViewController.swift @@ -0,0 +1,243 @@ +// +// SearchResultsViewController.swift +// Pokedex +// +// Created by Annie Tang on 9/18/17. +// Copyright © 2017 trainingprogram. All rights reserved. +// + +import UIKit + +class SearchResultsViewController: UIViewController { + + var segmentedControl: UISegmentedControl! + var tableView: UITableView! + var collectionView: UICollectionView! + + /* order of images in pokemonImages should be same as in results */ + var results: [Pokemon]! + // var pokemonImages: [UIImage]! + + var pokemonToPass: Pokemon! + var pokePicToPass: UIImage! + + override func viewDidLoad() { + super.viewDidLoad() + + setupSegmentedControl() + setupTableView() + setupCollectionView() + + } + + /* Initializing SegmentedControl and adding to view */ + func setupSegmentedControl() { + segmentedControl = UISegmentedControl(frame: CGRect(x: 0, y: UIApplication.shared.statusBarFrame.maxY + view.frame.height * 0.05 + 10, width: view.frame.width, height: view.frame.height * 0.05)) + segmentedControl.insertSegment(withTitle: "List", at: 0, animated: true) + segmentedControl.insertSegment(withTitle: "Grid", at: 1, animated: true) + segmentedControl.layer.cornerRadius = 3 + segmentedControl.addTarget(self, action: #selector(switchView), for: .valueChanged) + view.addSubview(segmentedControl) + } + + /* Initializaing table view, and adding it to view */ + func setupTableView(){ + segmentedControl.selectedSegmentIndex = 0 + + tableView = UITableView(frame: + CGRect(x: 0, + y: UIApplication.shared.statusBarFrame.maxY + view.frame.height * 0.1 + 10, + width: view.frame.width, + height: view.frame.height - UIApplication.shared.statusBarFrame.maxY)) + + tableView.register(PokemonTableViewCell.self, forCellReuseIdentifier: "tableViewCell") + tableView.delegate = self + tableView.dataSource = self + tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 50/2, right: 0) + view.addSubview(tableView) + } + + /* Initializaing collection view, and adding it to view */ + func setupCollectionView() { + segmentedControl.selectedSegmentIndex = 1 + + let layout = UICollectionViewFlowLayout() + layout.minimumLineSpacing = 0 + layout.minimumInteritemSpacing = 0 + collectionView = UICollectionView(frame: + CGRect(x: 0, + y: UIApplication.shared.statusBarFrame.maxY + view.frame.height * 0.1 + 10, + width: view.frame.width, + height: view.frame.height * 0.9 - UIApplication.shared.statusBarFrame.maxY - 10), + collectionViewLayout: layout) + collectionView.register(PokemonCollectionViewCell.self, forCellWithReuseIdentifier: "collectionViewCell") + collectionView.delegate = self + collectionView.dataSource = self + collectionView.backgroundColor = .white + view.addSubview(collectionView) + } + + func switchView(sender: UISegmentedControl) { + for subview in view.subviews { + subview.removeFromSuperview() + } + view.addSubview(segmentedControl) + if (sender.selectedSegmentIndex == 0) { + setupTableView() + } else { + setupCollectionView() + } + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if segue.identifier == "segueToPokemonDetails" { + let pokemonDetails = segue.destination as! PokemonProfileViewController + pokemonDetails.p = pokemonToPass + } + } + + + + +// func setUpPokemonImages() { +// pokemonImages = [] +// for p in results { +// pokemonImages.append(grabImagesFromURL(p: p)) +// } +// } +// +// func grabImagesFromURL(p: Pokemon)->UIImage { +// /* taken from stack overflow question: 24231680 */ +// //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch +// var image: UIImage! +// +// let url = URL(string: p.imageUrl) +// +// /* if url is not nil, try to get the contents of it and use it */ +// if url != nil { +// do { +// let data = try Data(contentsOf: url!) +// image = UIImage(data: data) +// } +// catch { +// image = #imageLiteral(resourceName: "pokeball") +// } +// } +// else { +// print("default") +// image = #imageLiteral(resourceName: "question") +// } +// +// if image == nil { +// image = #imageLiteral(resourceName: "question") +// } +// +// print("image: ", image) +// return image +// } + + + +} + + + +/* extension of TABLEVIEWS */ +extension SearchResultsViewController: UITableViewDataSource, UITableViewDelegate { + /* number of sections/types of cells in tableview */ + func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + /* number of cells in section of tableview */ + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return results.count + } + + /* dequeue & set up cell at indexPath.row + pass over the pokemon image, name, and number into the tableview cell */ + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + + /* dequeue cell and remove/reset from subview; initialize new cell */ + let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as! PokemonTableViewCell + for subview in cell.contentView.subviews { + subview.removeFromSuperview() + } + let p: Pokemon = results[indexPath.row] + + cell.pokemonObject = p + + cell.awakeFromNib() + + Utils.getImage(url: p.imageUrl) { img in + cell.pokePic.image = img + } + if cell.pokePic.image == nil { + cell.pokePic.image = #imageLiteral(resourceName: "pokeball") + } + cell.nameLabel.text = p.name + cell.numberLabel.text = "# " + String(p.number) + return cell + } + + /* action after tableCell is selected + "passes" the pokemon object over into the PokemonDetailsVC through segue */ + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + pokemonToPass = results[indexPath.row] + performSegue(withIdentifier: "segueToPokemonDetails", sender: self) + } + + /* sets each row to be 1/10 of frame view */ + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return view.frame.height / 10 + } + +} + +/* EXTENSION OF COLLECTIONVIEW */ +extension SearchResultsViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout { + + /* number of types of cells in collectionView */ + func numberOfSections(in collectionView: UICollectionView) -> Int { + return 1 + } + + /* number of cells in a section */ + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return results.count + } + + /* dequeue & setting up collectionView cell + sets the pokemon's image, name to the collectionView cell */ + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + + /* dequeue cell and remove/reset from subview; initialize new cell */ + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath) as! PokemonCollectionViewCell + for subview in cell.contentView.subviews { + subview.removeFromSuperview() + } + let p: Pokemon = results[indexPath.row] + cell.awakeFromNib() + + // cell.pokePic.image = pokemonImages[indexPath.row] + Utils.getImage(url: p.imageUrl) { img in + cell.pokePic.image = img + } + if cell.pokePic.image == nil { + cell.pokePic.image = #imageLiteral(resourceName: "pokeball") + } + cell.nameLabel.text = p.name + return cell + } + + /* passes the pokemon into PokemonDetails once cell is clicked upon */ + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + pokemonToPass = results[indexPath.row] + performSegue(withIdentifier: "segueToPokemonDetails", sender: self) + } + + /* makes it such that the cells are 1/4 of the view width square */ + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + return CGSize(width: view.frame.width / 4, height: view.frame.width / 4) + } +} diff --git a/Pokedex/TypeSelectorViewController.swift b/Pokedex/TypeSelectorViewController.swift new file mode 100644 index 0000000..6f8aca5 --- /dev/null +++ b/Pokedex/TypeSelectorViewController.swift @@ -0,0 +1,131 @@ +// +// TypeSelectorViewController.swift +// Pokedex +// +// Created by Louie McConnell on 9/18/17. +// Copyright © 2017 trainingprogram. All rights reserved. +// + +import UIKit + +class TypeSelectorViewController: UIViewController { + + var tableView: UITableView! + var doneButton: UIButton! + var types = ["Bug", "Grass", "Dark", "Ground", "Dragon", "Ice", "Electric", "Normal", "Fairy", "Poison", "Fighting", "Psychic", "Fire", "Rock", "Flying", "Steel", "Ghost", "Water"] + var selectedTypes: [String] = [] + + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + //Initialize TableView Object here + initializeTableView() + // add done button + addDoneButton() + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if segue.identifier == "unwindToCategorySelector" { + let categorySelectorVC = segue.destination as! CategorySelectionViewController + categorySelectorVC.types = selectedTypes + } + } + + func initializeTableView() { + tableView = UITableView(frame: CGRect(x: 0, y: UIApplication.shared.statusBarFrame.maxY + 10, width: view.frame.width, height: view.frame.height - UIApplication.shared.statusBarFrame.maxY - 100)) + // Register the tableViewCell you are using + tableView.register(TypeTwoTableViewCell.self, forCellReuseIdentifier: "tableViewCell") + + //Set properties of TableView + tableView.delegate = self as UITableViewDelegate + tableView.dataSource = self as UITableViewDataSource + tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 50/2, right: 0) + //Add tableView to view + view.addSubview(tableView) + } + // add a prepare function before any segue to pass parameters + + func addDoneButton() { + doneButton = UIButton() + doneButton.frame = CGRect( + x: 20, + y: self.view.frame.height - 70, + width: self.view.frame.width - 40, + height: 40 + ) + doneButton.setTitle("Done", for: .normal) + doneButton.setTitleColor(UIColor.white, for: .normal) + doneButton.layer.cornerRadius = 16 + doneButton.backgroundColor = UIColor.blue + doneButton.contentHorizontalAlignment = .center + doneButton.addTarget(self, action: #selector(goBackToCategorySelector), for: .touchUpInside) + self.view.addSubview(doneButton) + } + + func goBackToCategorySelector() { + performSegue(withIdentifier: "unwindToCategorySelector", sender: self) + } + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destinationViewController. + // Pass the selected object to the new view controller. + } + */ + +} + +extension TypeSelectorViewController: UITableViewDataSource, UITableViewDelegate { + + func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return types.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell") as! TypeTwoTableViewCell + + for subview in cell.contentView.subviews{ + subview.removeFromSuperview() + } + + cell.awakeFromNib() + cell.typeLabel.text = types[indexPath.row] + return cell + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + // CHANGE THIS LINE SO YOU ARE SENDING MULTIPLE TYPES AT ONCE + // typesToPass = types[indexPath.row] + + // if the cell text is already in selectedTypes + if let cell = tableView.cellForRow(at: indexPath) { + let selectedType = types[indexPath.row] + if selectedTypes.contains(selectedType) { + cell.accessoryType = .none + selectedTypes = selectedTypes.filter {$0 != selectedType} + } else { + cell.accessoryType = .checkmark + selectedTypes.append(selectedType) + } + } + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return 50 + } + +} diff --git a/Pokedex/TypeTableViewCell.swift b/Pokedex/TypeTableViewCell.swift new file mode 100644 index 0000000..cdc3216 --- /dev/null +++ b/Pokedex/TypeTableViewCell.swift @@ -0,0 +1,29 @@ +// +// TypeTableViewCell.swift +// Pokedex +// +// Created by Louie McConnell on 9/20/17. +// Copyright © 2017 trainingprogram. All rights reserved. +// + +import UIKit + +class TypeTableViewCell: UITableViewCell { + + var typeLabel: UILabel! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + typeLabel = UILabel(frame: CGRect(x: 20, y: contentView.frame.height * (1/4), width: 150, height: contentView.frame.height * (1/2))) + typeLabel.textColor = UIColor.black + contentView.addSubview(typeLabel) + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + +} diff --git a/Pokedex/TypeTwoTableViewCell.swift b/Pokedex/TypeTwoTableViewCell.swift new file mode 100644 index 0000000..849828a --- /dev/null +++ b/Pokedex/TypeTwoTableViewCell.swift @@ -0,0 +1,29 @@ +// +// TypeTableViewCell.swift +// Pokedex +// +// Created by Louie McConnell on 9/20/17. +// Copyright © 2017 trainingprogram. All rights reserved. +// + +import UIKit + +class TypeTwoTableViewCell: UITableViewCell { + + var typeLabel: UILabel! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + typeLabel = UILabel(frame: CGRect(x: 20, y: contentView.frame.height * (1/4), width: 150, height: contentView.frame.height * (1/2))) + typeLabel.textColor = UIColor.black + contentView.addSubview(typeLabel) + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + +} diff --git a/Pokedex/Utils.swift b/Pokedex/Utils.swift new file mode 100644 index 0000000..20411f2 --- /dev/null +++ b/Pokedex/Utils.swift @@ -0,0 +1,21 @@ +// +// Utils.swift +// Pods +// +// Created by Louie McConnell on 9/21/17. +// +// + +import Foundation +import Haneke + +class Utils { + static func getImage(url: String, withBlock: @escaping (UIImage) -> Void) { + let cache = Shared.imageCache + if let imageUrl = URL(string: url) { + cache.fetch(URL: imageUrl).onSuccess({ img in + withBlock(img) + }) + } + } +} diff --git a/Pokedex/imageFromURLRef.swift b/Pokedex/imageFromURLRef.swift new file mode 100644 index 0000000..8b5ca57 --- /dev/null +++ b/Pokedex/imageFromURLRef.swift @@ -0,0 +1,43 @@ +//// +//// imageFromURLRef.swift +//// Pokedex +//// +//// Created by Annie Tang on 9/18/17. +//// Copyright © 2017 trainingprogram. All rights reserved. +//// +// +//import Foundation +///** code retrieved from: https://stackoverflow.com/questions/39813497/swift-3-display-image-from-url **/ +//let pokemonImageURL = URL(string: p.imageUrl)! +// +//// Creating a session object with the default configuration. +//// Read more about it here https://developer.apple.com/reference/foundation/urlsessionconfiguration +//let session = URLSession(configuration: .default) +// +//// Define a download task. The download task will download the contents of the URL as a Data object and then you can do what you wish with that data. +//let downloadPicTask = session.dataTask(with: pokemonImageURL) { (data, response, error) in +// // The download has finished. +// if let e = error { +// print("Error downloading pokemon picture: \(e)") +// let image = UIImage() +// } else { +// // No errors found. +// // It would be weird if we didn't have a response, so check for that too. +// if let res = response as? HTTPURLResponse { +// print("Downloaded pokemon picture with response code \(res.statusCode)") +// if let imageData = data { +// // Finally convert that Data into an image and do what you wish with it. +// let image = UIImage(data: imageData) +// // Do something with your image. +// } else { +// let image = UIImage("") +// } +// } else { +// print("Couldn't get response code for some reason") +// } +// } +//} +// +//downloadPicTask.resume() +//} +// diff --git a/Pokedex/pokeData.json b/Pokedex/pokeData.json new file mode 100644 index 0000000..b404ebd --- /dev/null +++ b/Pokedex/pokeData.json @@ -0,0 +1 @@ +{"Abomasnow":{"#":"460","Attack":"92","Defense":"75","FlavorText":"","HP":"90","Sp. Atk":"92","Sp. Def":"85","Species":"Frost Tree Pok\u00e9mon","Speed":"60","Total":"494","Type":["Grass","Ice"]},"Abomasnow ( Mega Abomasnow )":{"#":"460","Attack":"132","Defense":"105","FlavorText":"","HP":"90","Sp. Atk":"132","Sp. Def":"105","Species":"","Speed":"30","Total":"594","Type":["Grass","Ice"]},"Abra":{"#":"063","Attack":"20","Defense":"15","FlavorText":"","HP":"25","Sp. Atk":"105","Sp. Def":"55","Species":"Psi Pok\u00e9mon","Speed":"90","Total":"310","Type":["Psychic"]},"Absol":{"#":"359","Attack":"130","Defense":"60","FlavorText":"","HP":"65","Sp. Atk":"75","Sp. Def":"60","Species":"Disaster Pok\u00e9mon","Speed":"75","Total":"465","Type":["Dark"]},"Absol ( Mega Absol )":{"#":"359","Attack":"150","Defense":"60","FlavorText":"","HP":"65","Sp. Atk":"115","Sp. Def":"60","Species":"","Speed":"115","Total":"565","Type":["Dark"]},"Accelgor":{"#":"617","Attack":"70","Defense":"40","FlavorText":"When its body dries out, it weakens. So, to prevent dehydration, it wraps itself in many layers of thin membrane.","HP":"80","Sp. Atk":"100","Sp. Def":"60","Species":"Shell Out Pok\u00e9mon","Speed":"145","Total":"495","Type":["Bug"]},"Aegislash ( Blade Forme )":{"#":"681","Attack":"150","Defense":"50","FlavorText":"","HP":"60","Sp. Atk":"150","Sp. Def":"50","Species":"","Speed":"60","Total":"520","Type":["Steel","Ghost"]},"Aegislash ( Shield Forme )":{"#":"681","Attack":"50","Defense":"150","FlavorText":"","HP":"60","Sp. Atk":"50","Sp. Def":"150","Species":"","Speed":"60","Total":"520","Type":["Steel","Ghost"]},"Aerodactyl":{"#":"142","Attack":"105","Defense":"65","FlavorText":"","HP":"80","Sp. Atk":"60","Sp. Def":"75","Species":"Fossil Pok\u00e9mon","Speed":"130","Total":"515","Type":["Rock","Flying"]},"Aerodactyl ( Mega Aerodactyl )":{"#":"142","Attack":"135","Defense":"85","FlavorText":"","HP":"80","Sp. Atk":"70","Sp. Def":"95","Species":"","Speed":"150","Total":"615","Type":["Rock","Flying"]},"Aggron":{"#":"306","Attack":"110","Defense":"180","FlavorText":"","HP":"70","Sp. Atk":"60","Sp. Def":"60","Species":"Iron Armor Pok\u00e9mon","Speed":"50","Total":"530","Type":["Steel","Rock"]},"Aggron ( Mega Aggron )":{"#":"306","Attack":"140","Defense":"230","FlavorText":"","HP":"70","Sp. Atk":"60","Sp. Def":"80","Species":"","Speed":"50","Total":"630","Type":["Steel"]},"Aipom":{"#":"190","Attack":"70","Defense":"55","FlavorText":"","HP":"55","Sp. Atk":"40","Sp. Def":"55","Species":"Long Tail Pok\u00e9mon","Speed":"85","Total":"360","Type":["Normal"]},"Alakazam":{"#":"065","Attack":"50","Defense":"45","FlavorText":"","HP":"55","Sp. Atk":"135","Sp. Def":"95","Species":"Psi Pok\u00e9mon","Speed":"120","Total":"500","Type":["Psychic"]},"Alakazam ( Mega Alakazam )":{"#":"065","Attack":"50","Defense":"65","FlavorText":"","HP":"55","Sp. Atk":"175","Sp. Def":"95","Species":"","Speed":"150","Total":"590","Type":["Psychic"]},"Alomomola":{"#":"594","Attack":"75","Defense":"80","FlavorText":"It gently holds injured and weak Pok\u00e9mon in its fins. Its special membrane heals their wounds.","HP":"165","Sp. Atk":"40","Sp. Def":"45","Species":"Caring Pok\u00e9mon","Speed":"65","Total":"470","Type":["Water"]},"Altaria":{"#":"334","Attack":"70","Defense":"90","FlavorText":"","HP":"75","Sp. Atk":"70","Sp. Def":"105","Species":"Humming Pok\u00e9mon","Speed":"80","Total":"490","Type":["Dragon","Flying"]},"Altaria ( Mega Altaria )":{"#":"334","Attack":"110","Defense":"110","FlavorText":"","HP":"75","Sp. Atk":"110","Sp. Def":"105","Species":"","Speed":"80","Total":"590","Type":["Dragon","Fairy"]},"Amaura":{"#":"698","Attack":"59","Defense":"50","FlavorText":"","HP":"77","Sp. Atk":"67","Sp. Def":"63","Species":"Tundra Pok\u00e9mon","Speed":"46","Total":"362","Type":["Rock","Ice"]},"Ambipom":{"#":"424","Attack":"100","Defense":"66","FlavorText":"","HP":"75","Sp. Atk":"60","Sp. Def":"66","Species":"Long Tail Pok\u00e9mon","Speed":"115","Total":"482","Type":["Normal"]},"Amoonguss":{"#":"591","Attack":"85","Defense":"70","FlavorText":"","HP":"114","Sp. Atk":"85","Sp. Def":"80","Species":"Mushroom Pok\u00e9mon","Speed":"30","Total":"464","Type":["Grass","Poison"]},"Ampharos":{"#":"181","Attack":"75","Defense":"85","FlavorText":"","HP":"90","Sp. Atk":"115","Sp. Def":"90","Species":"Light Pok\u00e9mon","Speed":"55","Total":"510","Type":["Electric"]},"Ampharos ( Mega Ampharos )":{"#":"181","Attack":"95","Defense":"105","FlavorText":"","HP":"90","Sp. Atk":"165","Sp. Def":"110","Species":"","Speed":"45","Total":"610","Type":["Electric","Dragon"]},"Anorith":{"#":"347","Attack":"95","Defense":"50","FlavorText":"","HP":"45","Sp. Atk":"40","Sp. Def":"50","Species":"Old Shrimp Pok\u00e9mon","Speed":"75","Total":"355","Type":["Rock","Bug"]},"Arbok":{"#":"024","Attack":"85","Defense":"69","FlavorText":"","HP":"60","Sp. Atk":"65","Sp. Def":"79","Species":"Cobra Pok\u00e9mon","Speed":"80","Total":"438","Type":["Poison"]},"Arcanine":{"#":"059","Attack":"110","Defense":"80","FlavorText":"","HP":"90","Sp. Atk":"100","Sp. Def":"80","Species":"Legendary Pok\u00e9mon","Speed":"95","Total":"555","Type":["Fire"]},"Arceus":{"#":"493","Attack":"120","Defense":"120","FlavorText":"","HP":"120","Sp. Atk":"120","Sp. Def":"120","Species":"Alpha Pok\u00e9mon","Speed":"120","Total":"720","Type":["Normal"]},"Archen":{"#":"566","Attack":"112","Defense":"45","FlavorText":"","HP":"55","Sp. Atk":"74","Sp. Def":"45","Species":"First Bird Pok\u00e9mon","Speed":"70","Total":"401","Type":["Rock","Flying"]},"Archeops":{"#":"567","Attack":"140","Defense":"65","FlavorText":"","HP":"75","Sp. Atk":"112","Sp. Def":"65","Species":"First Bird Pok\u00e9mon","Speed":"110","Total":"567","Type":["Rock","Flying"]},"Ariados":{"#":"168","Attack":"90","Defense":"70","FlavorText":"Its feet are tipped with tiny hooked claws that enable it to scuttle on ceilings and vertical walls. It constricts its foe with thin and strong silk webbing.","HP":"70","Sp. Atk":"60","Sp. Def":"60","Species":"Long Leg Pok\u00e9mon","Speed":"40","Total":"390","Type":["Bug","Poison"]},"Armaldo":{"#":"348","Attack":"125","Defense":"100","FlavorText":"","HP":"75","Sp. Atk":"70","Sp. Def":"80","Species":"Plate Pok\u00e9mon","Speed":"45","Total":"495","Type":["Rock","Bug"]},"Aromatisse":{"#":"683","Attack":"72","Defense":"72","FlavorText":"","HP":"101","Sp. Atk":"99","Sp. Def":"89","Species":"Fragrance Pok\u00e9mon","Speed":"29","Total":"462","Type":["Fairy"]},"Aron":{"#":"304","Attack":"70","Defense":"100","FlavorText":"","HP":"50","Sp. Atk":"40","Sp. Def":"40","Species":"Iron Armor Pok\u00e9mon","Speed":"30","Total":"330","Type":["Steel","Rock"]},"Articuno":{"#":"144","Attack":"85","Defense":"100","FlavorText":"Legendary bird POK\u00e9MON. As it flies through the sky, it cools the air, causing snow to fall.","HP":"90","Sp. Atk":"95","Sp. Def":"125","Species":"Freeze Pok\u00e9mon","Speed":"85","Total":"580","Type":["Ice","Flying"]},"Audino":{"#":"531","Attack":"60","Defense":"86","FlavorText":"","HP":"103","Sp. Atk":"60","Sp. Def":"86","Species":"Hearing Pok\u00e9mon","Speed":"50","Total":"445","Type":["Normal"]},"Audino ( Mega Audino )":{"#":"531","Attack":"60","Defense":"126","FlavorText":"","HP":"103","Sp. Atk":"80","Sp. Def":"126","Species":"","Speed":"50","Total":"545","Type":["Normal","Fairy"]},"Aurorus":{"#":"699","Attack":"77","Defense":"72","FlavorText":"","HP":"123","Sp. Atk":"99","Sp. Def":"92","Species":"Tundra Pok\u00e9mon","Speed":"58","Total":"521","Type":["Rock","Ice"]},"Avalugg":{"#":"713","Attack":"117","Defense":"184","FlavorText":"","HP":"95","Sp. Atk":"44","Sp. Def":"46","Species":"Iceberg Pok\u00e9mon","Speed":"28","Total":"514","Type":["Ice"]},"Axew":{"#":"610","Attack":"87","Defense":"60","FlavorText":"They mark their territory by leaving gashes in trees with their tusks. If a tusk breaks, a new one grows in quickly.","HP":"46","Sp. Atk":"30","Sp. Def":"40","Species":"Tusk Pok\u00e9mon","Speed":"57","Total":"320","Type":["Dragon"]},"Azelf":{"#":"482","Attack":"125","Defense":"70","FlavorText":"","HP":"75","Sp. Atk":"125","Sp. Def":"70","Species":"Willpower Pok\u00e9mon","Speed":"115","Total":"580","Type":["Psychic"]},"Azumarill":{"#":"184","Attack":"50","Defense":"80","FlavorText":"","HP":"100","Sp. Atk":"60","Sp. Def":"80","Species":"Aqua Rabbit Pok\u00e9mon","Speed":"50","Total":"420","Type":["Water","Fairy"]},"Azurill":{"#":"298","Attack":"20","Defense":"40","FlavorText":"","HP":"50","Sp. Atk":"20","Sp. Def":"40","Species":"Polka Dot Pok\u00e9mon","Speed":"20","Total":"190","Type":["Normal","Fairy"]},"Bagon":{"#":"371","Attack":"75","Defense":"60","FlavorText":"","HP":"45","Sp. Atk":"40","Sp. Def":"30","Species":"Rock Head Pok\u00e9mon","Speed":"50","Total":"300","Type":["Dragon"]},"Baltoy":{"#":"343","Attack":"40","Defense":"55","FlavorText":"","HP":"40","Sp. Atk":"40","Sp. Def":"70","Species":"Clay Doll Pok\u00e9mon","Speed":"55","Total":"300","Type":["Ground","Psychic"]},"Banette":{"#":"354","Attack":"115","Defense":"65","FlavorText":"","HP":"64","Sp. Atk":"83","Sp. Def":"63","Species":"Marionette Pok\u00e9mon","Speed":"65","Total":"455","Type":["Ghost"]},"Banette ( Mega Banette )":{"#":"354","Attack":"165","Defense":"75","FlavorText":"","HP":"64","Sp. Atk":"93","Sp. Def":"83","Species":"","Speed":"75","Total":"555","Type":["Ghost"]},"Barbaracle":{"#":"689","Attack":"105","Defense":"115","FlavorText":"","HP":"72","Sp. Atk":"54","Sp. Def":"86","Species":"Collective Pok\u00e9mon","Speed":"68","Total":"500","Type":["Rock","Water"]},"Barboach":{"#":"339","Attack":"48","Defense":"43","FlavorText":"","HP":"50","Sp. Atk":"46","Sp. Def":"41","Species":"Whiskers Pok\u00e9mon","Speed":"60","Total":"288","Type":["Water","Ground"]},"Basculin":{"#":"550","Attack":"92","Defense":"65","FlavorText":"","HP":"70","Sp. Atk":"80","Sp. Def":"55","Species":"Hostile Pok\u00e9mon","Speed":"98","Total":"460","Type":["Water"]},"Bastiodon":{"#":"411","Attack":"52","Defense":"168","FlavorText":"","HP":"60","Sp. Atk":"47","Sp. Def":"138","Species":"Shield Pok\u00e9mon","Speed":"30","Total":"495","Type":["Rock","Steel"]},"Bayleef":{"#":"153","Attack":"62","Defense":"80","FlavorText":"","HP":"60","Sp. Atk":"63","Sp. Def":"80","Species":"Leaf Pok\u00e9mon","Speed":"60","Total":"405","Type":["Grass"]},"Beartic":{"#":"614","Attack":"110","Defense":"80","FlavorText":"","HP":"95","Sp. Atk":"70","Sp. Def":"80","Species":"Freezing Pok\u00e9mon","Speed":"50","Total":"485","Type":["Ice"]},"Beautifly":{"#":"267","Attack":"70","Defense":"50","FlavorText":"Despite its looks, it is aggressive. It jabs with its long, thin mouth if disturbed while collecting pollen.","HP":"60","Sp. Atk":"100","Sp. Def":"50","Species":"Butterfly Pok\u00e9mon","Speed":"65","Total":"395","Type":["Bug","Flying"]},"Beedrill":{"#":"015","Attack":"90","Defense":"40","FlavorText":"","HP":"65","Sp. Atk":"45","Sp. Def":"80","Species":"Poison Bee Pok\u00e9mon","Speed":"75","Total":"395","Type":["Bug","Poison"]},"Beedrill ( Mega Beedrill )":{"#":"015","Attack":"150","Defense":"40","FlavorText":"","HP":"65","Sp. Atk":"15","Sp. Def":"80","Species":"","Speed":"145","Total":"495","Type":["Bug","Poison"]},"Beheeyem":{"#":"606","Attack":"75","Defense":"75","FlavorText":"","HP":"75","Sp. Atk":"125","Sp. Def":"95","Species":"Cerebral Pok\u00e9mon","Speed":"40","Total":"485","Type":["Psychic"]},"Beldum":{"#":"374","Attack":"55","Defense":"80","FlavorText":"","HP":"40","Sp. Atk":"35","Sp. Def":"60","Species":"Iron Ball Pok\u00e9mon","Speed":"30","Total":"300","Type":["Steel","Psychic"]},"Bellossom":{"#":"182","Attack":"80","Defense":"95","FlavorText":"","HP":"75","Sp. Atk":"90","Sp. Def":"100","Species":"Flower Pok\u00e9mon","Speed":"50","Total":"490","Type":["Grass"]},"Bellsprout":{"#":"069","Attack":"75","Defense":"35","FlavorText":"If it notices anything that moves, it immediately flings its vine at the object.","HP":"50","Sp. Atk":"70","Sp. Def":"30","Species":"Flower Pok\u00e9mon","Speed":"40","Total":"300","Type":["Grass","Poison"]},"Bergmite":{"#":"712","Attack":"69","Defense":"85","FlavorText":"","HP":"55","Sp. Atk":"32","Sp. Def":"35","Species":"Ice Chunk Pok\u00e9mon","Speed":"28","Total":"304","Type":["Ice"]},"Bibarel":{"#":"400","Attack":"85","Defense":"60","FlavorText":"","HP":"79","Sp. Atk":"55","Sp. Def":"60","Species":"Beaver Pok\u00e9mon","Speed":"71","Total":"410","Type":["Normal","Water"]},"Bidoof":{"#":"399","Attack":"45","Defense":"40","FlavorText":"","HP":"59","Sp. Atk":"35","Sp. Def":"40","Species":"Plump Mouse Pok\u00e9mon","Speed":"31","Total":"250","Type":["Normal"]},"Binacle":{"#":"688","Attack":"52","Defense":"67","FlavorText":"","HP":"42","Sp. Atk":"39","Sp. Def":"56","Species":"Two-Handed Pok\u00e9mon","Speed":"50","Total":"306","Type":["Rock","Water"]},"Bisharp":{"#":"625","Attack":"125","Defense":"100","FlavorText":"Bisharp pursues prey in the company of a large group of Pawniard. Then Bisharp finishes off the prey.","HP":"65","Sp. Atk":"60","Sp. Def":"70","Species":"Sword Blade Pok\u00e9mon","Speed":"70","Total":"490","Type":["Dark","Steel"]},"Blastoise":{"#":"009","Attack":"83","Defense":"100","FlavorText":"","HP":"79","Sp. Atk":"85","Sp. Def":"105","Species":"Shellfish Pok\u00e9mon","Speed":"78","Total":"530","Type":["Water"]},"Blastoise ( Mega Blastoise )":{"#":"009","Attack":"103","Defense":"120","FlavorText":"","HP":"79","Sp. Atk":"135","Sp. Def":"115","Species":"","Speed":"78","Total":"630","Type":["Water"]},"Blaziken":{"#":"257","Attack":"120","Defense":"70","FlavorText":"","HP":"80","Sp. Atk":"110","Sp. Def":"70","Species":"Blaze Pok\u00e9mon","Speed":"80","Total":"530","Type":["Fire","Fighting"]},"Blaziken ( Mega Blaziken )":{"#":"257","Attack":"160","Defense":"80","FlavorText":"","HP":"80","Sp. Atk":"130","Sp. Def":"80","Species":"","Speed":"100","Total":"630","Type":["Fire","Fighting"]},"Blissey":{"#":"242","Attack":"10","Defense":"10","FlavorText":"","HP":"255","Sp. Atk":"75","Sp. Def":"135","Species":"Happiness Pok\u00e9mon","Speed":"55","Total":"540","Type":["Normal"]},"Blitzle":{"#":"522","Attack":"60","Defense":"32","FlavorText":"","HP":"45","Sp. Atk":"50","Sp. Def":"32","Species":"Electrified Pok\u00e9mon","Speed":"76","Total":"295","Type":["Electric"]},"Boldore":{"#":"525","Attack":"105","Defense":"105","FlavorText":"","HP":"70","Sp. Atk":"50","Sp. Def":"40","Species":"Ore Pok\u00e9mon","Speed":"20","Total":"390","Type":["Rock"]},"Bonsly":{"#":"438","Attack":"80","Defense":"95","FlavorText":"","HP":"50","Sp. Atk":"10","Sp. Def":"45","Species":"Bonsai Pok\u00e9mon","Speed":"10","Total":"290","Type":["Rock"]},"Bouffalant":{"#":"626","Attack":"110","Defense":"95","FlavorText":"","HP":"95","Sp. Atk":"40","Sp. Def":"95","Species":"Bash Buffalo Pok\u00e9mon","Speed":"55","Total":"490","Type":["Normal"]},"Braixen":{"#":"654","Attack":"59","Defense":"58","FlavorText":"","HP":"59","Sp. Atk":"90","Sp. Def":"70","Species":"Fox Pok\u00e9mon","Speed":"73","Total":"409","Type":["Fire"]},"Braviary":{"#":"628","Attack":"123","Defense":"75","FlavorText":"","HP":"100","Sp. Atk":"57","Sp. Def":"75","Species":"Valiant Pok\u00e9mon","Speed":"80","Total":"510","Type":["Normal","Flying"]},"Breloom":{"#":"286","Attack":"130","Defense":"80","FlavorText":"","HP":"60","Sp. Atk":"60","Sp. Def":"60","Species":"Mushroom Pok\u00e9mon","Speed":"70","Total":"460","Type":["Grass","Fighting"]},"Bronzong":{"#":"437","Attack":"89","Defense":"116","FlavorText":"","HP":"67","Sp. Atk":"79","Sp. Def":"116","Species":"Bronze Bell Pok\u00e9mon","Speed":"33","Total":"500","Type":["Steel","Psychic"]},"Bronzor":{"#":"436","Attack":"24","Defense":"86","FlavorText":"","HP":"57","Sp. Atk":"24","Sp. Def":"86","Species":"Bronze Pok\u00e9mon","Speed":"23","Total":"300","Type":["Steel","Psychic"]},"Budew":{"#":"406","Attack":"30","Defense":"35","FlavorText":"","HP":"40","Sp. Atk":"50","Sp. Def":"70","Species":"Bud Pok\u00e9mon","Speed":"55","Total":"280","Type":["Grass","Poison"]},"Buizel":{"#":"418","Attack":"65","Defense":"35","FlavorText":"","HP":"55","Sp. Atk":"60","Sp. Def":"30","Species":"Sea Weasel Pok\u00e9mon","Speed":"85","Total":"330","Type":["Water"]},"Bulbasaur":{"#":"001","Attack":"49","Defense":"49","FlavorText":"While it is young, it uses the nutrients that are stored in the seeds on its back in order to grow.","HP":"45","Sp. Atk":"65","Sp. Def":"65","Species":"Seed Pok\u00e9mon","Speed":"45","Total":"318","Type":["Grass","Poison"]},"Buneary":{"#":"427","Attack":"66","Defense":"44","FlavorText":"","HP":"55","Sp. Atk":"44","Sp. Def":"56","Species":"Rabbit Pok\u00e9mon","Speed":"85","Total":"350","Type":["Normal"]},"Bunnelby":{"#":"659","Attack":"36","Defense":"38","FlavorText":"","HP":"38","Sp. Atk":"32","Sp. Def":"36","Species":"Digging Pok\u00e9mon","Speed":"57","Total":"237","Type":["Normal"]},"Burmy":{"#":"412","Attack":"29","Defense":"45","FlavorText":"","HP":"40","Sp. Atk":"29","Sp. Def":"45","Species":"Bagworm Pok\u00e9mon","Speed":"36","Total":"224","Type":["Bug"]},"Butterfree":{"#":"012","Attack":"45","Defense":"50","FlavorText":"It flits from flower to flower, collecting honey. It can even identify distant flowers in bloom.","HP":"60","Sp. Atk":"90","Sp. Def":"80","Species":"Butterfly Pok\u00e9mon","Speed":"70","Total":"395","Type":["Bug","Flying"]},"Cacnea":{"#":"331","Attack":"85","Defense":"40","FlavorText":"","HP":"50","Sp. Atk":"85","Sp. Def":"40","Species":"Cactus Pok\u00e9mon","Speed":"35","Total":"335","Type":["Grass"]},"Cacturne":{"#":"332","Attack":"115","Defense":"60","FlavorText":"","HP":"70","Sp. Atk":"115","Sp. Def":"60","Species":"Scarecrow Pok\u00e9mon","Speed":"55","Total":"475","Type":["Grass","Dark"]},"Camerupt":{"#":"323","Attack":"100","Defense":"70","FlavorText":"","HP":"70","Sp. Atk":"105","Sp. Def":"75","Species":"Eruption Pok\u00e9mon","Speed":"40","Total":"460","Type":["Fire","Ground"]},"Camerupt ( Mega Camerupt )":{"#":"323","Attack":"120","Defense":"100","FlavorText":"","HP":"70","Sp. Atk":"145","Sp. Def":"105","Species":"","Speed":"20","Total":"560","Type":["Fire","Ground"]},"Carbink":{"#":"703","Attack":"50","Defense":"150","FlavorText":"","HP":"50","Sp. Atk":"50","Sp. Def":"150","Species":"Jewel Pok\u00e9mon","Speed":"50","Total":"500","Type":["Rock","Fairy"]},"Carnivine":{"#":"455","Attack":"100","Defense":"72","FlavorText":"","HP":"74","Sp. Atk":"90","Sp. Def":"72","Species":"Bug Catcher Pok\u00e9mon","Speed":"46","Total":"454","Type":["Grass"]},"Carracosta":{"#":"565","Attack":"108","Defense":"133","FlavorText":"","HP":"74","Sp. Atk":"83","Sp. Def":"65","Species":"Prototurtle Pok\u00e9mon","Speed":"32","Total":"495","Type":["Water","Rock"]},"Carvanha":{"#":"318","Attack":"90","Defense":"20","FlavorText":"","HP":"45","Sp. Atk":"65","Sp. Def":"20","Species":"Savage Pok\u00e9mon","Speed":"65","Total":"305","Type":["Water","Dark"]},"Cascoon":{"#":"268","Attack":"35","Defense":"55","FlavorText":"","HP":"50","Sp. Atk":"25","Sp. Def":"25","Species":"Cocoon Pok\u00e9mon","Speed":"15","Total":"205","Type":["Bug"]},"Castform":{"#":"351","Attack":"70","Defense":"70","FlavorText":"","HP":"70","Sp. Atk":"70","Sp. Def":"70","Species":"Weather Pok\u00e9mon","Speed":"70","Total":"420","Type":["Normal"]},"Caterpie":{"#":"010","Attack":"30","Defense":"35","FlavorText":"It crawls into foliage where it camouflages itself among leaves that are the same color as its body.","HP":"45","Sp. Atk":"20","Sp. Def":"20","Species":"Worm Pok\u00e9mon","Speed":"45","Total":"195","Type":["Bug"]},"Celebi":{"#":"251","Attack":"100","Defense":"100","FlavorText":"","HP":"100","Sp. Atk":"100","Sp. Def":"100","Species":"Time Travel Pok\u00e9mon","Speed":"100","Total":"600","Type":["Psychic","Grass"]},"Chandelure":{"#":"609","Attack":"55","Defense":"90","FlavorText":"The spirits burned up in its ominous flame lose their way and wander this world forever.","HP":"60","Sp. Atk":"145","Sp. Def":"90","Species":"Luring Pok\u00e9mon","Speed":"80","Total":"520","Type":["Ghost","Fire"]},"Chansey":{"#":"113","Attack":"5","Defense":"5","FlavorText":"","HP":"250","Sp. Atk":"35","Sp. Def":"105","Species":"Egg Pok\u00e9mon","Speed":"50","Total":"450","Type":["Normal"]},"Charizard":{"#":"006","Attack":"84","Defense":"78","FlavorText":"","HP":"78","Sp. Atk":"109","Sp. Def":"85","Species":"Flame Pok\u00e9mon","Speed":"100","Total":"534","Type":["Fire","Flying"]},"Charizard ( Mega Charizard X )":{"#":"006","Attack":"130","Defense":"111","FlavorText":"","HP":"78","Sp. Atk":"130","Sp. Def":"85","Species":"","Speed":"100","Total":"634","Type":["Fire","Dragon"]},"Charizard ( Mega Charizard Y )":{"#":"006","Attack":"104","Defense":"78","FlavorText":"","HP":"78","Sp. Atk":"159","Sp. Def":"115","Species":"","Speed":"100","Total":"634","Type":["Fire","Flying"]},"Charmander":{"#":"004","Attack":"52","Defense":"43","FlavorText":"If it's healthy, the flame on the tip of its tail will burn vigorously, even if it gets a bit wet.","HP":"39","Sp. Atk":"60","Sp. Def":"50","Species":"Lizard Pok\u00e9mon","Speed":"65","Total":"309","Type":["Fire"]},"Charmeleon":{"#":"005","Attack":"64","Defense":"58","FlavorText":"If it becomes agitated during battle, it spouts intense flames, incinerating its surroundings.","HP":"58","Sp. Atk":"80","Sp. Def":"65","Species":"Flame Pok\u00e9mon","Speed":"80","Total":"405","Type":["Fire"]},"Chatot":{"#":"441","Attack":"65","Defense":"45","FlavorText":"","HP":"76","Sp. Atk":"92","Sp. Def":"42","Species":"Music Note Pok\u00e9mon","Speed":"91","Total":"411","Type":["Normal","Flying"]},"Cherrim":{"#":"421","Attack":"60","Defense":"70","FlavorText":"","HP":"70","Sp. Atk":"87","Sp. Def":"78","Species":"Blossom Pok\u00e9mon","Speed":"85","Total":"450","Type":["Grass"]},"Cherubi":{"#":"420","Attack":"35","Defense":"45","FlavorText":"","HP":"45","Sp. Atk":"62","Sp. Def":"53","Species":"Cherry Pok\u00e9mon","Speed":"35","Total":"275","Type":["Grass"]},"Chesnaught":{"#":"652","Attack":"107","Defense":"122","FlavorText":"","HP":"88","Sp. Atk":"74","Sp. Def":"75","Species":"Spiny Armor Pok\u00e9mon","Speed":"64","Total":"530","Type":["Grass","Fighting"]},"Chespin":{"#":"650","Attack":"61","Defense":"65","FlavorText":"","HP":"56","Sp. Atk":"48","Sp. Def":"45","Species":"Spiny Nut Pok\u00e9mon","Speed":"38","Total":"313","Type":["Grass"]},"Chikorita":{"#":"152","Attack":"49","Defense":"65","FlavorText":"","HP":"45","Sp. Atk":"49","Sp. Def":"65","Species":"Leaf Pok\u00e9mon","Speed":"45","Total":"318","Type":["Grass"]},"Chimchar":{"#":"390","Attack":"58","Defense":"44","FlavorText":"","HP":"44","Sp. Atk":"58","Sp. Def":"44","Species":"Chimp Pok\u00e9mon","Speed":"61","Total":"309","Type":["Fire"]},"Chimecho":{"#":"358","Attack":"50","Defense":"70","FlavorText":"Its cries echo inside its hollow body to emerge as beautiful notes for startling and repelling foes.","HP":"65","Sp. Atk":"95","Sp. Def":"80","Species":"Wind Chime Pok\u00e9mon","Speed":"65","Total":"425","Type":["Psychic"]},"Chinchou":{"#":"170","Attack":"38","Defense":"38","FlavorText":"","HP":"75","Sp. Atk":"56","Sp. Def":"56","Species":"Angler Pok\u00e9mon","Speed":"67","Total":"330","Type":["Water","Electric"]},"Chingling":{"#":"433","Attack":"30","Defense":"50","FlavorText":"","HP":"45","Sp. Atk":"65","Sp. Def":"50","Species":"Bell Pok\u00e9mon","Speed":"45","Total":"285","Type":["Psychic"]},"Cinccino":{"#":"573","Attack":"95","Defense":"60","FlavorText":"","HP":"75","Sp. Atk":"65","Sp. Def":"60","Species":"Scarf Pok\u00e9mon","Speed":"115","Total":"470","Type":["Normal"]},"Clamperl":{"#":"366","Attack":"64","Defense":"85","FlavorText":"","HP":"35","Sp. Atk":"74","Sp. Def":"55","Species":"Bivalve Pok\u00e9mon","Speed":"32","Total":"345","Type":["Water"]},"Clauncher":{"#":"692","Attack":"53","Defense":"62","FlavorText":"","HP":"50","Sp. Atk":"58","Sp. Def":"63","Species":"Water Gun Pok\u00e9mon","Speed":"44","Total":"330","Type":["Water"]},"Clawitzer":{"#":"693","Attack":"73","Defense":"88","FlavorText":"","HP":"71","Sp. Atk":"120","Sp. Def":"89","Species":"Howitzer Pok\u00e9mon","Speed":"59","Total":"500","Type":["Water"]},"Claydol":{"#":"344","Attack":"70","Defense":"105","FlavorText":"","HP":"60","Sp. Atk":"70","Sp. Def":"120","Species":"Clay Doll Pok\u00e9mon","Speed":"75","Total":"500","Type":["Ground","Psychic"]},"Clefable":{"#":"036","Attack":"70","Defense":"73","FlavorText":"","HP":"95","Sp. Atk":"95","Sp. Def":"90","Species":"Fairy Pok\u00e9mon","Speed":"60","Total":"483","Type":["Fairy"]},"Clefairy":{"#":"035","Attack":"45","Defense":"48","FlavorText":"","HP":"70","Sp. Atk":"60","Sp. Def":"65","Species":"Fairy Pok\u00e9mon","Speed":"35","Total":"323","Type":["Fairy"]},"Cleffa":{"#":"173","Attack":"25","Defense":"28","FlavorText":"","HP":"50","Sp. Atk":"45","Sp. Def":"55","Species":"Star Shape Pok\u00e9mon","Speed":"15","Total":"218","Type":["Fairy"]},"Cloyster":{"#":"091","Attack":"95","Defense":"180","FlavorText":"","HP":"50","Sp. Atk":"85","Sp. Def":"45","Species":"Bivalve Pok\u00e9mon","Speed":"70","Total":"525","Type":["Water","Ice"]},"Cobalion":{"#":"638","Attack":"90","Defense":"129","FlavorText":"","HP":"91","Sp. Atk":"90","Sp. Def":"72","Species":"Iron Will Pok\u00e9mon","Speed":"108","Total":"580","Type":["Steel","Fighting"]},"Cofagrigus":{"#":"563","Attack":"50","Defense":"145","FlavorText":"","HP":"58","Sp. Atk":"95","Sp. Def":"105","Species":"Coffin Pok\u00e9mon","Speed":"30","Total":"483","Type":["Ghost"]},"Combee":{"#":"415","Attack":"30","Defense":"42","FlavorText":"","HP":"30","Sp. Atk":"30","Sp. Def":"42","Species":"Tiny Bee Pok\u00e9mon","Speed":"70","Total":"244","Type":["Bug","Flying"]},"Combusken":{"#":"256","Attack":"85","Defense":"60","FlavorText":"","HP":"60","Sp. Atk":"85","Sp. Def":"60","Species":"Young Fowl Pok\u00e9mon","Speed":"55","Total":"405","Type":["Fire","Fighting"]},"Conkeldurr":{"#":"534","Attack":"140","Defense":"95","FlavorText":"Rather than rely on force, they master moves that utilize the centrifugal force of spinning concrete.","HP":"105","Sp. Atk":"55","Sp. Def":"65","Species":"Muscular Pok\u00e9mon","Speed":"45","Total":"505","Type":["Fighting"]},"Corphish":{"#":"341","Attack":"80","Defense":"65","FlavorText":"","HP":"43","Sp. Atk":"50","Sp. Def":"35","Species":"Ruffian Pok\u00e9mon","Speed":"35","Total":"308","Type":["Water"]},"Corsola":{"#":"222","Attack":"55","Defense":"85","FlavorText":"","HP":"55","Sp. Atk":"65","Sp. Def":"85","Species":"Coral Pok\u00e9mon","Speed":"35","Total":"380","Type":["Water","Rock"]},"Cottonee":{"#":"546","Attack":"27","Defense":"60","FlavorText":"","HP":"40","Sp. Atk":"37","Sp. Def":"50","Species":"Cotton Puff Pok\u00e9mon","Speed":"66","Total":"280","Type":["Grass","Fairy"]},"Cradily":{"#":"346","Attack":"81","Defense":"97","FlavorText":"","HP":"86","Sp. Atk":"81","Sp. Def":"107","Species":"Barnacle Pok\u00e9mon","Speed":"43","Total":"495","Type":["Rock","Grass"]},"Cranidos":{"#":"408","Attack":"125","Defense":"40","FlavorText":"","HP":"67","Sp. Atk":"30","Sp. Def":"30","Species":"Head Butt Pok\u00e9mon","Speed":"58","Total":"350","Type":["Rock"]},"Crawdaunt":{"#":"342","Attack":"120","Defense":"85","FlavorText":"","HP":"63","Sp. Atk":"90","Sp. Def":"55","Species":"Rogue Pok\u00e9mon","Speed":"55","Total":"468","Type":["Water","Dark"]},"Cresselia":{"#":"488","Attack":"70","Defense":"120","FlavorText":"","HP":"120","Sp. Atk":"75","Sp. Def":"130","Species":"Lunar Pok\u00e9mon","Speed":"85","Total":"600","Type":["Psychic"]},"Croagunk":{"#":"453","Attack":"61","Defense":"40","FlavorText":"","HP":"48","Sp. Atk":"61","Sp. Def":"40","Species":"Toxic Mouth Pok\u00e9mon","Speed":"50","Total":"300","Type":["Poison","Fighting"]},"Crobat":{"#":"169","Attack":"90","Defense":"80","FlavorText":"","HP":"85","Sp. Atk":"70","Sp. Def":"80","Species":"Bat Pok\u00e9mon","Speed":"130","Total":"535","Type":["Poison","Flying"]},"Croconaw":{"#":"159","Attack":"80","Defense":"80","FlavorText":"","HP":"65","Sp. Atk":"59","Sp. Def":"63","Species":"Big Jaw Pok\u00e9mon","Speed":"58","Total":"405","Type":["Water"]},"Crustle":{"#":"558","Attack":"95","Defense":"125","FlavorText":"Competing for territory, Crustle fight viciously. The one whose boulder is broken is the loser of the battle.","HP":"70","Sp. Atk":"65","Sp. Def":"75","Species":"Stone Home Pok\u00e9mon","Speed":"45","Total":"475","Type":["Bug","Rock"]},"Cryogonal":{"#":"615","Attack":"50","Defense":"30","FlavorText":"","HP":"70","Sp. Atk":"95","Sp. Def":"135","Species":"Crystallizing Pok\u00e9mon","Speed":"105","Total":"485","Type":["Ice"]},"Cubchoo":{"#":"613","Attack":"70","Defense":"40","FlavorText":"","HP":"55","Sp. Atk":"60","Sp. Def":"40","Species":"Chill Pok\u00e9mon","Speed":"40","Total":"305","Type":["Ice"]},"Cubone":{"#":"104","Attack":"50","Defense":"95","FlavorText":"","HP":"50","Sp. Atk":"40","Sp. Def":"50","Species":"Lonely Pok\u00e9mon","Speed":"35","Total":"320","Type":["Ground"]},"Cyndaquil":{"#":"155","Attack":"52","Defense":"43","FlavorText":"","HP":"39","Sp. Atk":"60","Sp. Def":"50","Species":"Fire Mouse Pok\u00e9mon","Speed":"65","Total":"309","Type":["Fire"]},"Darkrai":{"#":"491","Attack":"90","Defense":"90","FlavorText":"","HP":"70","Sp. Atk":"135","Sp. Def":"90","Species":"Pitch-Black Pok\u00e9mon","Speed":"125","Total":"600","Type":["Dark"]},"Darmanitan ( Standard Mode )":{"#":"555","Attack":"140","Defense":"55","FlavorText":"","HP":"105","Sp. Atk":"30","Sp. Def":"55","Species":"","Speed":"95","Total":"480","Type":["Fire"]},"Darmanitan ( Zen Mode )":{"#":"555","Attack":"30","Defense":"105","FlavorText":"","HP":"105","Sp. Atk":"140","Sp. Def":"105","Species":"","Speed":"55","Total":"540","Type":["Fire","Psychic"]},"Darumaka":{"#":"554","Attack":"90","Defense":"45","FlavorText":"","HP":"70","Sp. Atk":"15","Sp. Def":"45","Species":"Zen Charm Pok\u00e9mon","Speed":"50","Total":"315","Type":["Fire"]},"Dedenne":{"#":"702","Attack":"58","Defense":"57","FlavorText":"","HP":"67","Sp. Atk":"81","Sp. Def":"67","Species":"Antenna Pok\u00e9mon","Speed":"101","Total":"431","Type":["Electric","Fairy"]},"Deerling":{"#":"585","Attack":"60","Defense":"50","FlavorText":"","HP":"60","Sp. Atk":"40","Sp. Def":"50","Species":"Season Pok\u00e9mon","Speed":"75","Total":"335","Type":["Normal","Grass"]},"Deino":{"#":"633","Attack":"65","Defense":"50","FlavorText":"","HP":"52","Sp. Atk":"45","Sp. Def":"50","Species":"Irate Pok\u00e9mon","Speed":"38","Total":"300","Type":["Dark","Dragon"]},"Delcatty":{"#":"301","Attack":"65","Defense":"65","FlavorText":"","HP":"70","Sp. Atk":"55","Sp. Def":"55","Species":"Prim Pok\u00e9mon","Speed":"70","Total":"380","Type":["Normal"]},"Delibird":{"#":"225","Attack":"55","Defense":"45","FlavorText":"","HP":"45","Sp. Atk":"65","Sp. Def":"45","Species":"Delivery Pok\u00e9mon","Speed":"75","Total":"330","Type":["Ice","Flying"]},"Delphox":{"#":"655","Attack":"69","Defense":"72","FlavorText":"","HP":"75","Sp. Atk":"114","Sp. Def":"100","Species":"Fox Pok\u00e9mon","Speed":"104","Total":"534","Type":["Fire","Psychic"]},"Deoxys ( Attack Forme )":{"#":"386","Attack":"180","Defense":"20","FlavorText":"","HP":"50","Sp. Atk":"180","Sp. Def":"20","Species":"","Speed":"150","Total":"600","Type":["Psychic"]},"Deoxys ( Defense Forme )":{"#":"386","Attack":"70","Defense":"160","FlavorText":"","HP":"50","Sp. Atk":"70","Sp. Def":"160","Species":"","Speed":"90","Total":"600","Type":["Psychic"]},"Deoxys ( Normal Forme )":{"#":"386","Attack":"150","Defense":"50","FlavorText":"","HP":"50","Sp. Atk":"150","Sp. Def":"50","Species":"","Speed":"150","Total":"600","Type":["Psychic"]},"Deoxys ( Speed Forme )":{"#":"386","Attack":"95","Defense":"90","FlavorText":"","HP":"50","Sp. Atk":"95","Sp. Def":"90","Species":"","Speed":"180","Total":"600","Type":["Psychic"]},"Dewgong":{"#":"087","Attack":"70","Defense":"80","FlavorText":"","HP":"90","Sp. Atk":"70","Sp. Def":"95","Species":"Sea Lion Pok\u00e9mon","Speed":"70","Total":"475","Type":["Water","Ice"]},"Dewott":{"#":"502","Attack":"75","Defense":"60","FlavorText":"","HP":"75","Sp. Atk":"83","Sp. Def":"60","Species":"Discipline Pok\u00e9mon","Speed":"60","Total":"413","Type":["Water"]},"Dialga":{"#":"483","Attack":"120","Defense":"120","FlavorText":"","HP":"100","Sp. Atk":"150","Sp. Def":"100","Species":"Temporal Pok\u00e9mon","Speed":"90","Total":"680","Type":["Steel","Dragon"]},"Diancie":{"#":"719","Attack":"100","Defense":"150","FlavorText":"","HP":"50","Sp. Atk":"100","Sp. Def":"150","Species":"Jewel Pok\u00e9mon","Speed":"50","Total":"600","Type":["Rock","Fairy"]},"Diancie ( Mega Diancie )":{"#":"719","Attack":"160","Defense":"110","FlavorText":"","HP":"50","Sp. Atk":"160","Sp. Def":"110","Species":"","Speed":"110","Total":"700","Type":["Rock","Fairy"]},"Diggersby":{"#":"660","Attack":"56","Defense":"77","FlavorText":"","HP":"85","Sp. Atk":"50","Sp. Def":"77","Species":"Digging Pok\u00e9mon","Speed":"78","Total":"423","Type":["Normal","Ground"]},"Diglett":{"#":"050","Attack":"55","Defense":"25","FlavorText":"","HP":"10","Sp. Atk":"35","Sp. Def":"45","Species":"Mole Pok\u00e9mon","Speed":"95","Total":"265","Type":["Ground"]},"Ditto":{"#":"132","Attack":"48","Defense":"48","FlavorText":"","HP":"48","Sp. Atk":"48","Sp. Def":"48","Species":"Transform Pok\u00e9mon","Speed":"48","Total":"288","Type":["Normal"]},"Dodrio":{"#":"085","Attack":"110","Defense":"70","FlavorText":"","HP":"60","Sp. Atk":"60","Sp. Def":"60","Species":"Triple Bird Pok\u00e9mon","Speed":"100","Total":"460","Type":["Normal","Flying"]},"Doduo":{"#":"084","Attack":"85","Defense":"45","FlavorText":"","HP":"35","Sp. Atk":"35","Sp. Def":"35","Species":"Twin Bird Pok\u00e9mon","Speed":"75","Total":"310","Type":["Normal","Flying"]},"Donphan":{"#":"232","Attack":"120","Defense":"120","FlavorText":"","HP":"90","Sp. Atk":"60","Sp. Def":"60","Species":"Armor Pok\u00e9mon","Speed":"50","Total":"500","Type":["Ground"]},"Doublade":{"#":"680","Attack":"110","Defense":"150","FlavorText":"","HP":"59","Sp. Atk":"45","Sp. Def":"49","Species":"Sword Pok\u00e9mon","Speed":"35","Total":"448","Type":["Steel","Ghost"]},"Dragalge":{"#":"691","Attack":"75","Defense":"90","FlavorText":"","HP":"65","Sp. Atk":"97","Sp. Def":"123","Species":"Mock Kelp Pok\u00e9mon","Speed":"44","Total":"494","Type":["Poison","Dragon"]},"Dragonair":{"#":"148","Attack":"84","Defense":"65","FlavorText":"It is called the divine POK\u00e9MON. When its entire body brightens slightly, the weather changes.","HP":"61","Sp. Atk":"70","Sp. Def":"70","Species":"Dragon Pok\u00e9mon","Speed":"70","Total":"420","Type":["Dragon"]},"Dragonite":{"#":"149","Attack":"134","Defense":"95","FlavorText":"It is said that somewhere in the ocean lies an island where these gather. Only they live there.","HP":"91","Sp. Atk":"100","Sp. Def":"100","Species":"Dragon Pok\u00e9mon","Speed":"80","Total":"600","Type":["Dragon","Flying"]},"Drapion":{"#":"452","Attack":"90","Defense":"110","FlavorText":"","HP":"70","Sp. Atk":"60","Sp. Def":"75","Species":"Ogre Scorp Pok\u00e9mon","Speed":"95","Total":"500","Type":["Poison","Dark"]},"Dratini":{"#":"147","Attack":"64","Defense":"45","FlavorText":"It sheds many layers of skin as it grows larger. During this process, it is protected by a rapid waterfall.","HP":"41","Sp. Atk":"50","Sp. Def":"50","Species":"Dragon Pok\u00e9mon","Speed":"50","Total":"300","Type":["Dragon"]},"Drifblim":{"#":"426","Attack":"80","Defense":"44","FlavorText":"","HP":"150","Sp. Atk":"90","Sp. Def":"54","Species":"Blimp Pok\u00e9mon","Speed":"80","Total":"498","Type":["Ghost","Flying"]},"Drifloon":{"#":"425","Attack":"50","Defense":"34","FlavorText":"","HP":"90","Sp. Atk":"60","Sp. Def":"44","Species":"Balloon Pok\u00e9mon","Speed":"70","Total":"348","Type":["Ghost","Flying"]},"Drilbur":{"#":"529","Attack":"85","Defense":"40","FlavorText":"","HP":"60","Sp. Atk":"30","Sp. Def":"45","Species":"Mole Pok\u00e9mon","Speed":"68","Total":"328","Type":["Ground"]},"Drowzee":{"#":"096","Attack":"48","Defense":"45","FlavorText":"When it twitches its nose, it can tell where someone is sleeping and what that person is dreaming about.","HP":"60","Sp. Atk":"43","Sp. Def":"90","Species":"Hypnosis Pok\u00e9mon","Speed":"42","Total":"328","Type":["Psychic"]},"Druddigon":{"#":"621","Attack":"120","Defense":"90","FlavorText":"It warms its body by absorbing sunlight with its wings. When its body temperature falls, it can no longer move.","HP":"77","Sp. Atk":"60","Sp. Def":"90","Species":"Cave Pok\u00e9mon","Speed":"48","Total":"485","Type":["Dragon"]},"Ducklett":{"#":"580","Attack":"44","Defense":"50","FlavorText":"They are better at swimming than flying, and they happily eat their favorite food, peat moss, as they dive underwater.","HP":"62","Sp. Atk":"44","Sp. Def":"50","Species":"Water Bird Pok\u00e9mon","Speed":"55","Total":"305","Type":["Water","Flying"]},"Dugtrio":{"#":"051","Attack":"80","Defense":"50","FlavorText":"","HP":"35","Sp. Atk":"50","Sp. Def":"70","Species":"Mole Pok\u00e9mon","Speed":"120","Total":"405","Type":["Ground"]},"Dunsparce":{"#":"206","Attack":"70","Defense":"70","FlavorText":"","HP":"100","Sp. Atk":"65","Sp. Def":"65","Species":"Land Snake Pok\u00e9mon","Speed":"45","Total":"415","Type":["Normal"]},"Duosion":{"#":"578","Attack":"40","Defense":"50","FlavorText":"When their two divided brains think the same thoughts, their psychic power is maximized.","HP":"65","Sp. Atk":"125","Sp. Def":"60","Species":"Mitosis Pok\u00e9mon","Speed":"30","Total":"370","Type":["Psychic"]},"Durant":{"#":"632","Attack":"109","Defense":"112","FlavorText":"They attack in groups, covering themselves in steel armor to protect themselves from Heatmor.","HP":"58","Sp. Atk":"48","Sp. Def":"48","Species":"Iron Ant Pok\u00e9mon","Speed":"109","Total":"484","Type":["Bug","Steel"]},"Dusclops":{"#":"356","Attack":"70","Defense":"130","FlavorText":"","HP":"40","Sp. Atk":"60","Sp. Def":"130","Species":"Beckon Pok\u00e9mon","Speed":"25","Total":"455","Type":["Ghost"]},"Dusknoir":{"#":"477","Attack":"100","Defense":"135","FlavorText":"","HP":"45","Sp. Atk":"65","Sp. Def":"135","Species":"Gripper Pok\u00e9mon","Speed":"45","Total":"525","Type":["Ghost"]},"Duskull":{"#":"355","Attack":"40","Defense":"90","FlavorText":"","HP":"20","Sp. Atk":"30","Sp. Def":"90","Species":"Requiem Pok\u00e9mon","Speed":"25","Total":"295","Type":["Ghost"]},"Dustox":{"#":"269","Attack":"50","Defense":"70","FlavorText":"Toxic powder is scattered with each flap. At night, it is known to strip leaves off trees lining boulevards.","HP":"60","Sp. Atk":"50","Sp. Def":"90","Species":"Poison Moth Pok\u00e9mon","Speed":"65","Total":"385","Type":["Bug","Poison"]},"Dwebble":{"#":"557","Attack":"65","Defense":"85","FlavorText":"When it finds a stone of a suitable size, it secretes a liquid from its mouth to open up a hole to crawl into.","HP":"50","Sp. Atk":"35","Sp. Def":"35","Species":"Rock Inn Pok\u00e9mon","Speed":"55","Total":"325","Type":["Bug","Rock"]},"Eelektrik":{"#":"603","Attack":"85","Defense":"70","FlavorText":"","HP":"65","Sp. Atk":"75","Sp. Def":"70","Species":"EleFish Pok\u00e9mon","Speed":"40","Total":"405","Type":["Electric"]},"Eelektross":{"#":"604","Attack":"115","Defense":"80","FlavorText":"","HP":"85","Sp. Atk":"105","Sp. Def":"80","Species":"EleFish Pok\u00e9mon","Speed":"50","Total":"515","Type":["Electric"]},"Eevee":{"#":"133","Attack":"55","Defense":"50","FlavorText":"","HP":"55","Sp. Atk":"45","Sp. Def":"65","Species":"Evolution Pok\u00e9mon","Speed":"55","Total":"325","Type":["Normal"]},"Ekans":{"#":"023","Attack":"60","Defense":"44","FlavorText":"","HP":"35","Sp. Atk":"40","Sp. Def":"54","Species":"Snake Pok\u00e9mon","Speed":"55","Total":"288","Type":["Poison"]},"Electabuzz":{"#":"125","Attack":"83","Defense":"57","FlavorText":"","HP":"65","Sp. Atk":"95","Sp. Def":"85","Species":"Electric Pok\u00e9mon","Speed":"105","Total":"490","Type":["Electric"]},"Electivire":{"#":"466","Attack":"123","Defense":"67","FlavorText":"","HP":"75","Sp. Atk":"95","Sp. Def":"85","Species":"Thunderbolt Pok\u00e9mon","Speed":"95","Total":"540","Type":["Electric"]},"Electrike":{"#":"309","Attack":"45","Defense":"40","FlavorText":"It generates electricity using friction from the atmosphere. In seasons with especially arid air, its entire body blazes with violent showers of sparks.","HP":"40","Sp. Atk":"65","Sp. Def":"40","Species":"Lightning Pok\u00e9mon","Speed":"65","Total":"295","Type":["Electric"]},"Electrode":{"#":"101","Attack":"50","Defense":"70","FlavorText":"","HP":"60","Sp. Atk":"80","Sp. Def":"80","Species":"Ball Pok\u00e9mon","Speed":"140","Total":"480","Type":["Electric"]},"Elekid":{"#":"239","Attack":"63","Defense":"37","FlavorText":"If it touches metal and discharges the electricity it has stored in its body, an ELEKID begins swinging its arms in circles to recharge itself.","HP":"45","Sp. Atk":"65","Sp. Def":"55","Species":"Electric Pok\u00e9mon","Speed":"95","Total":"360","Type":["Electric"]},"Elgyem":{"#":"605","Attack":"55","Defense":"55","FlavorText":"","HP":"55","Sp. Atk":"85","Sp. Def":"55","Species":"Cerebral Pok\u00e9mon","Speed":"30","Total":"335","Type":["Psychic"]},"Emboar":{"#":"500","Attack":"123","Defense":"65","FlavorText":"","HP":"110","Sp. Atk":"100","Sp. Def":"65","Species":"Mega Fire Pig Pok\u00e9mon","Speed":"65","Total":"528","Type":["Fire","Fighting"]},"Emolga":{"#":"587","Attack":"75","Defense":"60","FlavorText":"","HP":"55","Sp. Atk":"75","Sp. Def":"60","Species":"Sky Squirrel Pok\u00e9mon","Speed":"103","Total":"428","Type":["Electric","Flying"]},"Empoleon":{"#":"395","Attack":"86","Defense":"88","FlavorText":"","HP":"84","Sp. Atk":"111","Sp. Def":"101","Species":"Emperor Pok\u00e9mon","Speed":"60","Total":"530","Type":["Water","Steel"]},"Entei":{"#":"244","Attack":"115","Defense":"85","FlavorText":"","HP":"115","Sp. Atk":"90","Sp. Def":"75","Species":"Volcano Pok\u00e9mon","Speed":"100","Total":"580","Type":["Fire"]},"Escavalier":{"#":"589","Attack":"135","Defense":"105","FlavorText":"These Pok\u00e9mon evolve by wearing the shell covering of a Shelmet. The steel armor protects their whole body.","HP":"70","Sp. Atk":"60","Sp. Def":"105","Species":"Cavalry Pok\u00e9mon","Speed":"20","Total":"495","Type":["Bug","Steel"]},"Espeon":{"#":"196","Attack":"65","Defense":"60","FlavorText":"","HP":"65","Sp. Atk":"130","Sp. Def":"95","Species":"Sun Pok\u00e9mon","Speed":"110","Total":"525","Type":["Psychic"]},"Espurr":{"#":"677","Attack":"48","Defense":"54","FlavorText":"","HP":"62","Sp. Atk":"63","Sp. Def":"60","Species":"Restraint Pok\u00e9mon","Speed":"68","Total":"355","Type":["Psychic"]},"Excadrill":{"#":"530","Attack":"135","Defense":"60","FlavorText":"","HP":"110","Sp. Atk":"50","Sp. Def":"65","Species":"Subterrene Pok\u00e9mon","Speed":"88","Total":"508","Type":["Ground","Steel"]},"Exeggcute":{"#":"102","Attack":"40","Defense":"80","FlavorText":"If even one is separated from the group, the energy bond between the six will make them rejoin instantly.","HP":"60","Sp. Atk":"60","Sp. Def":"45","Species":"Egg Pok\u00e9mon","Speed":"40","Total":"325","Type":["Grass","Psychic"]},"Exeggutor":{"#":"103","Attack":"95","Defense":"85","FlavorText":"Living in a good environment makes it grow lots of heads. A head that drops off becomes an EXEGGCUTE.","HP":"95","Sp. Atk":"125","Sp. Def":"65","Species":"Coconut Pok\u00e9mon","Speed":"55","Total":"520","Type":["Grass","Psychic"]},"Exploud":{"#":"295","Attack":"91","Defense":"63","FlavorText":"","HP":"104","Sp. Atk":"91","Sp. Def":"73","Species":"Loud Noise Pok\u00e9mon","Speed":"68","Total":"490","Type":["Normal"]},"Farfetch'd":{"#":"083","Attack":"65","Defense":"55","FlavorText":"","HP":"52","Sp. Atk":"58","Sp. Def":"62","Species":"","Speed":"60","Total":"352","Type":["Normal","Flying"]},"Fearow":{"#":"022","Attack":"90","Defense":"65","FlavorText":"It uses its long beak to attack. It has a surprisingly long reach, so it must be treated with caution.","HP":"65","Sp. Atk":"61","Sp. Def":"61","Species":"Beak Pok\u00e9mon","Speed":"100","Total":"442","Type":["Normal","Flying"]},"Feebas":{"#":"349","Attack":"15","Defense":"20","FlavorText":"","HP":"20","Sp. Atk":"10","Sp. Def":"55","Species":"Fish Pok\u00e9mon","Speed":"80","Total":"200","Type":["Water"]},"Fennekin":{"#":"653","Attack":"45","Defense":"40","FlavorText":"","HP":"40","Sp. Atk":"62","Sp. Def":"60","Species":"Fox Pok\u00e9mon","Speed":"60","Total":"307","Type":["Fire"]},"Feraligatr":{"#":"160","Attack":"105","Defense":"100","FlavorText":"","HP":"85","Sp. Atk":"79","Sp. Def":"83","Species":"Big Jaw Pok\u00e9mon","Speed":"78","Total":"530","Type":["Water"]},"Ferroseed":{"#":"597","Attack":"50","Defense":"91","FlavorText":"","HP":"44","Sp. Atk":"24","Sp. Def":"86","Species":"Thorn Seed Pok\u00e9mon","Speed":"10","Total":"305","Type":["Grass","Steel"]},"Ferrothorn":{"#":"598","Attack":"94","Defense":"131","FlavorText":"","HP":"74","Sp. Atk":"54","Sp. Def":"116","Species":"Thorn Pod Pok\u00e9mon","Speed":"20","Total":"489","Type":["Grass","Steel"]},"Finneon":{"#":"456","Attack":"49","Defense":"56","FlavorText":"","HP":"49","Sp. Atk":"49","Sp. Def":"61","Species":"Wing Fish Pok\u00e9mon","Speed":"66","Total":"330","Type":["Water"]},"Flaaffy":{"#":"180","Attack":"55","Defense":"55","FlavorText":"Its fleece quality changes to generate strong static electricity with a small amount of wool. The bare, slick parts of its hide are shielded against electricity.","HP":"70","Sp. Atk":"80","Sp. Def":"60","Species":"Wool Pok\u00e9mon","Speed":"45","Total":"365","Type":["Electric"]},"Flab\u00e9b\u00e9":{"#":"669","Attack":"38","Defense":"39","FlavorText":"","HP":"44","Sp. Atk":"61","Sp. Def":"79","Species":"","Speed":"42","Total":"303","Type":["Fairy"]},"Flareon":{"#":"136","Attack":"130","Defense":"60","FlavorText":"","HP":"65","Sp. Atk":"95","Sp. Def":"110","Species":"Flame Pok\u00e9mon","Speed":"65","Total":"525","Type":["Fire"]},"Fletchinder":{"#":"662","Attack":"73","Defense":"55","FlavorText":"","HP":"62","Sp. Atk":"56","Sp. Def":"52","Species":"Ember Pok\u00e9mon","Speed":"84","Total":"382","Type":["Fire","Flying"]},"Fletchling":{"#":"661","Attack":"50","Defense":"43","FlavorText":"","HP":"45","Sp. Atk":"40","Sp. Def":"38","Species":"Tiny Robin Pok\u00e9mon","Speed":"62","Total":"278","Type":["Normal","Flying"]},"Floatzel":{"#":"419","Attack":"105","Defense":"55","FlavorText":"","HP":"85","Sp. Atk":"85","Sp. Def":"50","Species":"Sea Weasel Pok\u00e9mon","Speed":"115","Total":"495","Type":["Water"]},"Floette":{"#":"670","Attack":"45","Defense":"47","FlavorText":"","HP":"54","Sp. Atk":"75","Sp. Def":"98","Species":"Single Bloom Pok\u00e9mon","Speed":"52","Total":"371","Type":["Fairy"]},"Florges":{"#":"671","Attack":"65","Defense":"68","FlavorText":"","HP":"78","Sp. Atk":"112","Sp. Def":"154","Species":"Garden Pok\u00e9mon","Speed":"75","Total":"552","Type":["Fairy"]},"Flygon":{"#":"330","Attack":"100","Defense":"80","FlavorText":"","HP":"80","Sp. Atk":"80","Sp. Def":"80","Species":"Mystic Pok\u00e9mon","Speed":"100","Total":"520","Type":["Ground","Dragon"]},"Foongus":{"#":"590","Attack":"55","Defense":"45","FlavorText":"","HP":"69","Sp. Atk":"55","Sp. Def":"55","Species":"Mushroom Pok\u00e9mon","Speed":"15","Total":"294","Type":["Grass","Poison"]},"Forretress":{"#":"205","Attack":"90","Defense":"140","FlavorText":"","HP":"75","Sp. Atk":"60","Sp. Def":"60","Species":"Bagworm Pok\u00e9mon","Speed":"40","Total":"465","Type":["Bug","Steel"]},"Fraxure":{"#":"611","Attack":"117","Defense":"70","FlavorText":"A broken tusk will not grow back, so it diligently sharpens its tusks on river rocks after the end of a battle.","HP":"66","Sp. Atk":"40","Sp. Def":"50","Species":"Axe Jaw Pok\u00e9mon","Speed":"67","Total":"410","Type":["Dragon"]},"Frillish":{"#":"592","Attack":"40","Defense":"50","FlavorText":"","HP":"55","Sp. Atk":"65","Sp. Def":"85","Species":"Floating Pok\u00e9mon","Speed":"40","Total":"335","Type":["Water","Ghost"]},"Froakie":{"#":"656","Attack":"56","Defense":"40","FlavorText":"","HP":"41","Sp. Atk":"62","Sp. Def":"44","Species":"Bubble Frog Pok\u00e9mon","Speed":"71","Total":"314","Type":["Water"]},"Frogadier":{"#":"657","Attack":"63","Defense":"52","FlavorText":"","HP":"54","Sp. Atk":"83","Sp. Def":"56","Species":"Bubble Frog Pok\u00e9mon","Speed":"97","Total":"405","Type":["Water"]},"Froslass":{"#":"478","Attack":"80","Defense":"70","FlavorText":"","HP":"70","Sp. Atk":"80","Sp. Def":"70","Species":"Snow Land Pok\u00e9mon","Speed":"110","Total":"480","Type":["Ice","Ghost"]},"Furfrou":{"#":"676","Attack":"80","Defense":"60","FlavorText":"","HP":"75","Sp. Atk":"65","Sp. Def":"90","Species":"Poodle Pok\u00e9mon","Speed":"102","Total":"472","Type":["Normal"]},"Furret":{"#":"162","Attack":"76","Defense":"64","FlavorText":"A FURRET has a very slim build. When under attack, it can squirm through narrow spaces and get away. In spite of its short limbs, it is very nimble and fleet.","HP":"85","Sp. Atk":"45","Sp. Def":"55","Species":"Long Body Pok\u00e9mon","Speed":"90","Total":"415","Type":["Normal"]},"Gabite":{"#":"444","Attack":"90","Defense":"65","FlavorText":"","HP":"68","Sp. Atk":"50","Sp. Def":"55","Species":"Cave Pok\u00e9mon","Speed":"82","Total":"410","Type":["Dragon","Ground"]},"Gallade":{"#":"475","Attack":"125","Defense":"65","FlavorText":"","HP":"68","Sp. Atk":"65","Sp. Def":"115","Species":"Blade Pok\u00e9mon","Speed":"80","Total":"518","Type":["Psychic","Fighting"]},"Gallade ( Mega Gallade )":{"#":"475","Attack":"165","Defense":"95","FlavorText":"","HP":"68","Sp. Atk":"65","Sp. Def":"115","Species":"","Speed":"110","Total":"618","Type":["Psychic","Fighting"]},"Galvantula":{"#":"596","Attack":"77","Defense":"60","FlavorText":"","HP":"70","Sp. Atk":"97","Sp. Def":"60","Species":"EleSpider Pok\u00e9mon","Speed":"108","Total":"472","Type":["Bug","Electric"]},"Garbodor":{"#":"569","Attack":"95","Defense":"82","FlavorText":"Consuming garbage makes new kinds of poison gases and liquids inside their bodies.","HP":"80","Sp. Atk":"60","Sp. Def":"82","Species":"Trash Heap Pok\u00e9mon","Speed":"75","Total":"474","Type":["Poison"]},"Garchomp":{"#":"445","Attack":"130","Defense":"95","FlavorText":"","HP":"108","Sp. Atk":"80","Sp. Def":"85","Species":"Mach Pok\u00e9mon","Speed":"102","Total":"600","Type":["Dragon","Ground"]},"Garchomp ( Mega Garchomp )":{"#":"445","Attack":"170","Defense":"115","FlavorText":"","HP":"108","Sp. Atk":"120","Sp. Def":"95","Species":"","Speed":"92","Total":"700","Type":["Dragon","Ground"]},"Gardevoir":{"#":"282","Attack":"65","Defense":"65","FlavorText":"","HP":"68","Sp. Atk":"125","Sp. Def":"115","Species":"Embrace Pok\u00e9mon","Speed":"80","Total":"518","Type":["Psychic","Fairy"]},"Gardevoir ( Mega Gardevoir )":{"#":"282","Attack":"85","Defense":"65","FlavorText":"","HP":"68","Sp. Atk":"165","Sp. Def":"135","Species":"","Speed":"100","Total":"618","Type":["Psychic","Fairy"]},"Gastly":{"#":"092","Attack":"35","Defense":"30","FlavorText":"","HP":"30","Sp. Atk":"100","Sp. Def":"35","Species":"Gas Pok\u00e9mon","Speed":"80","Total":"310","Type":["Ghost","Poison"]},"Gastrodon":{"#":"423","Attack":"83","Defense":"68","FlavorText":"","HP":"111","Sp. Atk":"92","Sp. Def":"82","Species":"Sea Slug Pok\u00e9mon","Speed":"39","Total":"475","Type":["Water","Ground"]},"Genesect":{"#":"649","Attack":"120","Defense":"95","FlavorText":"","HP":"71","Sp. Atk":"120","Sp. Def":"95","Species":"Paleozoic Pok\u00e9mon","Speed":"99","Total":"600","Type":["Bug","Steel"]},"Gengar":{"#":"094","Attack":"65","Defense":"60","FlavorText":"","HP":"60","Sp. Atk":"130","Sp. Def":"75","Species":"Shadow Pok\u00e9mon","Speed":"110","Total":"500","Type":["Ghost","Poison"]},"Gengar ( Mega Gengar )":{"#":"094","Attack":"65","Defense":"80","FlavorText":"","HP":"60","Sp. Atk":"170","Sp. Def":"95","Species":"","Speed":"130","Total":"600","Type":["Ghost","Poison"]},"Geodude":{"#":"074","Attack":"80","Defense":"100","FlavorText":"","HP":"40","Sp. Atk":"30","Sp. Def":"30","Species":"Rock Pok\u00e9mon","Speed":"20","Total":"300","Type":["Rock","Ground"]},"Gible":{"#":"443","Attack":"70","Defense":"45","FlavorText":"","HP":"58","Sp. Atk":"40","Sp. Def":"45","Species":"Land Shark Pok\u00e9mon","Speed":"42","Total":"300","Type":["Dragon","Ground"]},"Gigalith":{"#":"526","Attack":"135","Defense":"130","FlavorText":"","HP":"85","Sp. Atk":"60","Sp. Def":"80","Species":"Compressed Pok\u00e9mon","Speed":"25","Total":"515","Type":["Rock"]},"Girafarig":{"#":"203","Attack":"80","Defense":"65","FlavorText":"","HP":"70","Sp. Atk":"90","Sp. Def":"65","Species":"Long Neck Pok\u00e9mon","Speed":"85","Total":"455","Type":["Normal","Psychic"]},"Giratina ( Altered Forme )":{"#":"487","Attack":"100","Defense":"120","FlavorText":"","HP":"150","Sp. Atk":"100","Sp. Def":"120","Species":"","Speed":"90","Total":"680","Type":["Ghost","Dragon"]},"Giratina ( Origin Forme )":{"#":"487","Attack":"120","Defense":"100","FlavorText":"","HP":"150","Sp. Atk":"120","Sp. Def":"100","Species":"","Speed":"90","Total":"680","Type":["Ghost","Dragon"]},"Glaceon":{"#":"471","Attack":"60","Defense":"110","FlavorText":"","HP":"65","Sp. Atk":"130","Sp. Def":"95","Species":"Fresh Snow Pok\u00e9mon","Speed":"65","Total":"525","Type":["Ice"]},"Glalie":{"#":"362","Attack":"80","Defense":"80","FlavorText":"","HP":"80","Sp. Atk":"80","Sp. Def":"80","Species":"Face Pok\u00e9mon","Speed":"80","Total":"480","Type":["Ice"]},"Glalie ( Mega Glalie )":{"#":"362","Attack":"120","Defense":"80","FlavorText":"","HP":"80","Sp. Atk":"120","Sp. Def":"80","Species":"","Speed":"100","Total":"580","Type":["Ice"]},"Glameow":{"#":"431","Attack":"55","Defense":"42","FlavorText":"","HP":"49","Sp. Atk":"42","Sp. Def":"37","Species":"Catty Pok\u00e9mon","Speed":"85","Total":"310","Type":["Normal"]},"Gligar":{"#":"207","Attack":"75","Defense":"105","FlavorText":"","HP":"65","Sp. Atk":"35","Sp. Def":"65","Species":"FlyScorpion Pok\u00e9mon","Speed":"85","Total":"430","Type":["Ground","Flying"]},"Gliscor":{"#":"472","Attack":"95","Defense":"125","FlavorText":"If it succeeds in catching even a faint breeze properly, it can circle the globe without flapping once.","HP":"75","Sp. Atk":"45","Sp. Def":"75","Species":"Fang Scorp Pok\u00e9mon","Speed":"95","Total":"510","Type":["Ground","Flying"]},"Gloom":{"#":"044","Attack":"65","Defense":"70","FlavorText":"","HP":"60","Sp. Atk":"85","Sp. Def":"75","Species":"Weed Pok\u00e9mon","Speed":"40","Total":"395","Type":["Grass","Poison"]},"Gogoat":{"#":"673","Attack":"100","Defense":"62","FlavorText":"","HP":"123","Sp. Atk":"97","Sp. Def":"81","Species":"Mount Pok\u00e9mon","Speed":"68","Total":"531","Type":["Grass"]},"Golbat":{"#":"042","Attack":"80","Defense":"70","FlavorText":"","HP":"75","Sp. Atk":"65","Sp. Def":"75","Species":"Bat Pok\u00e9mon","Speed":"90","Total":"455","Type":["Poison","Flying"]},"Goldeen":{"#":"118","Attack":"67","Defense":"60","FlavorText":"","HP":"45","Sp. Atk":"35","Sp. Def":"50","Species":"Goldfish Pok\u00e9mon","Speed":"63","Total":"320","Type":["Water"]},"Golduck":{"#":"055","Attack":"82","Defense":"78","FlavorText":"","HP":"80","Sp. Atk":"95","Sp. Def":"80","Species":"Duck Pok\u00e9mon","Speed":"85","Total":"500","Type":["Water"]},"Golem":{"#":"076","Attack":"120","Defense":"130","FlavorText":"","HP":"80","Sp. Atk":"55","Sp. Def":"65","Species":"Megaton Pok\u00e9mon","Speed":"45","Total":"495","Type":["Rock","Ground"]},"Golett":{"#":"622","Attack":"74","Defense":"50","FlavorText":"Ancient science fashioned this Pok\u00e9mon from clay. It\u2019s been active for thousands of years.","HP":"59","Sp. Atk":"35","Sp. Def":"50","Species":"Automaton Pok\u00e9mon","Speed":"35","Total":"303","Type":["Ground","Ghost"]},"Golurk":{"#":"623","Attack":"124","Defense":"80","FlavorText":"It flies across the sky at Mach speeds. Removing the seal on its chest makes its internal energy go out of control.","HP":"89","Sp. Atk":"55","Sp. Def":"80","Species":"Automaton Pok\u00e9mon","Speed":"55","Total":"483","Type":["Ground","Ghost"]},"Goodra":{"#":"706","Attack":"100","Defense":"70","FlavorText":"","HP":"90","Sp. Atk":"110","Sp. Def":"150","Species":"Dragon Pok\u00e9mon","Speed":"80","Total":"600","Type":["Dragon"]},"Goomy":{"#":"704","Attack":"50","Defense":"35","FlavorText":"","HP":"45","Sp. Atk":"55","Sp. Def":"75","Species":"Soft Tissue Pok\u00e9mon","Speed":"40","Total":"300","Type":["Dragon"]},"Gorebyss":{"#":"368","Attack":"84","Defense":"105","FlavorText":"","HP":"55","Sp. Atk":"114","Sp. Def":"75","Species":"South Sea Pok\u00e9mon","Speed":"52","Total":"485","Type":["Water"]},"Gothita":{"#":"574","Attack":"30","Defense":"50","FlavorText":"They intently observe both Trainers and Pok\u00e9mon. Apparently, they are looking at something that only Gothita can see.","HP":"45","Sp. Atk":"55","Sp. Def":"65","Species":"Fixation Pok\u00e9mon","Speed":"45","Total":"290","Type":["Psychic"]},"Gothitelle":{"#":"576","Attack":"55","Defense":"95","FlavorText":"They can predict the future from the placement and movement of the stars. They can see Trainers\u2019 life spans.","HP":"70","Sp. Atk":"95","Sp. Def":"110","Species":"Astral Body Pok\u00e9mon","Speed":"65","Total":"490","Type":["Psychic"]},"Gothorita":{"#":"575","Attack":"45","Defense":"70","FlavorText":"According to many old tales, it creates friends for itself by controlling sleeping children on starry nights.","HP":"60","Sp. Atk":"75","Sp. Def":"85","Species":"Manipulate Pok\u00e9mon","Speed":"55","Total":"390","Type":["Psychic"]},"Gourgeist ( Average Size )":{"#":"711","Attack":"90","Defense":"122","FlavorText":"","HP":"65","Sp. Atk":"58","Sp. Def":"75","Species":"","Speed":"84","Total":"494","Type":["Ghost","Grass"]},"Gourgeist ( Large Size )":{"#":"711","Attack":"95","Defense":"122","FlavorText":"","HP":"75","Sp. Atk":"58","Sp. Def":"75","Species":"","Speed":"69","Total":"494","Type":["Ghost","Grass"]},"Gourgeist ( Small Size )":{"#":"711","Attack":"85","Defense":"122","FlavorText":"","HP":"55","Sp. Atk":"58","Sp. Def":"75","Species":"","Speed":"99","Total":"494","Type":["Ghost","Grass"]},"Gourgeist ( Super Size )":{"#":"711","Attack":"100","Defense":"122","FlavorText":"","HP":"85","Sp. Atk":"58","Sp. Def":"75","Species":"","Speed":"54","Total":"494","Type":["Ghost","Grass"]},"Granbull":{"#":"210","Attack":"120","Defense":"75","FlavorText":"It has a particularly well-developed lower jaw. The huge fangs are heavy, causing it to tilt its head. Unless it is startled, it will not try to bite.","HP":"90","Sp. Atk":"60","Sp. Def":"60","Species":"Fairy Pok\u00e9mon","Speed":"45","Total":"450","Type":["Fairy"]},"Graveler":{"#":"075","Attack":"95","Defense":"115","FlavorText":"","HP":"55","Sp. Atk":"45","Sp. Def":"45","Species":"Rock Pok\u00e9mon","Speed":"35","Total":"390","Type":["Rock","Ground"]},"Greninja":{"#":"658","Attack":"95","Defense":"67","FlavorText":"","HP":"72","Sp. Atk":"103","Sp. Def":"71","Species":"Ninja Pok\u00e9mon","Speed":"122","Total":"530","Type":["Water","Dark"]},"Grimer":{"#":"088","Attack":"80","Defense":"50","FlavorText":"","HP":"80","Sp. Atk":"40","Sp. Def":"50","Species":"Sludge Pok\u00e9mon","Speed":"25","Total":"325","Type":["Poison"]},"Grotle":{"#":"388","Attack":"89","Defense":"85","FlavorText":"","HP":"75","Sp. Atk":"55","Sp. Def":"65","Species":"Grove Pok\u00e9mon","Speed":"36","Total":"405","Type":["Grass"]},"Groudon":{"#":"383","Attack":"150","Defense":"140","FlavorText":"","HP":"100","Sp. Atk":"100","Sp. Def":"90","Species":"Continent Pok\u00e9mon","Speed":"90","Total":"670","Type":["Ground"]},"Groudon ( Primal Groudon )":{"#":"383","Attack":"180","Defense":"160","FlavorText":"","HP":"100","Sp. Atk":"150","Sp. Def":"90","Species":"","Speed":"90","Total":"770","Type":["Ground","Fire"]},"Grovyle":{"#":"253","Attack":"65","Defense":"45","FlavorText":"","HP":"50","Sp. Atk":"85","Sp. Def":"65","Species":"Wood Gecko Pok\u00e9mon","Speed":"95","Total":"405","Type":["Grass"]},"Growlithe":{"#":"058","Attack":"70","Defense":"45","FlavorText":"","HP":"55","Sp. Atk":"70","Sp. Def":"50","Species":"Puppy Pok\u00e9mon","Speed":"60","Total":"350","Type":["Fire"]},"Grumpig":{"#":"326","Attack":"45","Defense":"65","FlavorText":"","HP":"80","Sp. Atk":"90","Sp. Def":"110","Species":"Manipulate Pok\u00e9mon","Speed":"80","Total":"470","Type":["Psychic"]},"Gulpin":{"#":"316","Attack":"43","Defense":"53","FlavorText":"This POK\u00e9MON\u2019s stomach fluid can even digest scrap iron. In one gulp, it can swallow something that is as large as itself.","HP":"70","Sp. Atk":"43","Sp. Def":"53","Species":"Stomach Pok\u00e9mon","Speed":"40","Total":"302","Type":["Poison"]},"Gurdurr":{"#":"533","Attack":"105","Defense":"85","FlavorText":"This Pok\u00e9mon is so muscular and strongly built that even a group of wrestlers could not make it budge an inch.","HP":"85","Sp. Atk":"40","Sp. Def":"50","Species":"Muscular Pok\u00e9mon","Speed":"40","Total":"405","Type":["Fighting"]},"Gyarados":{"#":"130","Attack":"125","Defense":"79","FlavorText":"","HP":"95","Sp. Atk":"60","Sp. Def":"100","Species":"Atrocious Pok\u00e9mon","Speed":"81","Total":"540","Type":["Water","Flying"]},"Gyarados ( Mega Gyarados )":{"#":"130","Attack":"155","Defense":"109","FlavorText":"","HP":"95","Sp. Atk":"70","Sp. Def":"130","Species":"","Speed":"81","Total":"640","Type":["Water","Dark"]},"Happiny":{"#":"440","Attack":"5","Defense":"5","FlavorText":"","HP":"100","Sp. Atk":"15","Sp. Def":"65","Species":"Playhouse Pok\u00e9mon","Speed":"30","Total":"220","Type":["Normal"]},"Hariyama":{"#":"297","Attack":"120","Defense":"60","FlavorText":"It has the habit of challenging others without hesitation to tests of strength. It\u2019s been known to stand on train tracks and stop trains using forearm thrusts.","HP":"144","Sp. Atk":"40","Sp. Def":"60","Species":"Arm Thrust Pok\u00e9mon","Speed":"50","Total":"474","Type":["Fighting"]},"Haunter":{"#":"093","Attack":"50","Defense":"45","FlavorText":"","HP":"45","Sp. Atk":"115","Sp. Def":"55","Species":"Gas Pok\u00e9mon","Speed":"95","Total":"405","Type":["Ghost","Poison"]},"Hawlucha":{"#":"701","Attack":"92","Defense":"75","FlavorText":"","HP":"78","Sp. Atk":"74","Sp. Def":"63","Species":"Wrestling Pok\u00e9mon","Speed":"118","Total":"500","Type":["Fighting","Flying"]},"Haxorus":{"#":"612","Attack":"147","Defense":"90","FlavorText":"Their sturdy tusks will stay sharp even if used to cut steel beams. These Pok\u00e9mon are covered in hard armor.","HP":"76","Sp. Atk":"60","Sp. Def":"70","Species":"Axe Jaw Pok\u00e9mon","Speed":"97","Total":"540","Type":["Dragon"]},"Heatmor":{"#":"631","Attack":"97","Defense":"66","FlavorText":"It draws in air through its tail, transforms it into fire, and uses it like a tongue. It melts Durant and eats them.","HP":"85","Sp. Atk":"105","Sp. Def":"66","Species":"Anteater Pok\u00e9mon","Speed":"65","Total":"484","Type":["Fire"]},"Heatran":{"#":"485","Attack":"90","Defense":"106","FlavorText":"","HP":"91","Sp. Atk":"130","Sp. Def":"106","Species":"Lava Dome Pok\u00e9mon","Speed":"77","Total":"600","Type":["Fire","Steel"]},"Heliolisk":{"#":"695","Attack":"55","Defense":"52","FlavorText":"","HP":"62","Sp. Atk":"109","Sp. Def":"94","Species":"Generator Pok\u00e9mon","Speed":"109","Total":"481","Type":["Electric","Normal"]},"Helioptile":{"#":"694","Attack":"38","Defense":"33","FlavorText":"","HP":"44","Sp. Atk":"61","Sp. Def":"43","Species":"Generator Pok\u00e9mon","Speed":"70","Total":"289","Type":["Electric","Normal"]},"Heracross":{"#":"214","Attack":"125","Defense":"75","FlavorText":"","HP":"80","Sp. Atk":"40","Sp. Def":"95","Species":"Single Horn Pok\u00e9mon","Speed":"85","Total":"500","Type":["Bug","Fighting"]},"Heracross ( Mega Heracross )":{"#":"214","Attack":"185","Defense":"115","FlavorText":"","HP":"80","Sp. Atk":"40","Sp. Def":"105","Species":"","Speed":"75","Total":"600","Type":["Bug","Fighting"]},"Herdier":{"#":"507","Attack":"80","Defense":"65","FlavorText":"","HP":"65","Sp. Atk":"35","Sp. Def":"65","Species":"Loyal Dog Pok\u00e9mon","Speed":"60","Total":"370","Type":["Normal"]},"Hippopotas":{"#":"449","Attack":"72","Defense":"78","FlavorText":"","HP":"68","Sp. Atk":"38","Sp. Def":"42","Species":"Hippo Pok\u00e9mon","Speed":"32","Total":"330","Type":["Ground"]},"Hippowdon":{"#":"450","Attack":"112","Defense":"118","FlavorText":"","HP":"108","Sp. Atk":"68","Sp. Def":"72","Species":"Heavyweight Pok\u00e9mon","Speed":"47","Total":"525","Type":["Ground"]},"Hitmonchan":{"#":"107","Attack":"105","Defense":"79","FlavorText":"To increase the strength of all its punch moves, it spins its arms just before making contact.","HP":"50","Sp. Atk":"35","Sp. Def":"110","Species":"Punching Pok\u00e9mon","Speed":"76","Total":"455","Type":["Fighting"]},"Hitmonlee":{"#":"106","Attack":"120","Defense":"53","FlavorText":"It is also called the Kick Master. It uses its elastic legs to execute every known kick.","HP":"50","Sp. Atk":"35","Sp. Def":"110","Species":"Kicking Pok\u00e9mon","Speed":"87","Total":"455","Type":["Fighting"]},"Hitmontop":{"#":"237","Attack":"95","Defense":"95","FlavorText":"","HP":"50","Sp. Atk":"35","Sp. Def":"110","Species":"Handstand Pok\u00e9mon","Speed":"70","Total":"455","Type":["Fighting"]},"Ho-oh":{"#":"250","Attack":"130","Defense":"90","FlavorText":"","HP":"106","Sp. Atk":"110","Sp. Def":"154","Species":"Rainbow Pok\u00e9mon","Speed":"90","Total":"680","Type":["Fire","Flying"]},"Honchkrow":{"#":"430","Attack":"125","Defense":"52","FlavorText":"","HP":"100","Sp. Atk":"105","Sp. Def":"52","Species":"Big Boss Pok\u00e9mon","Speed":"71","Total":"505","Type":["Dark","Flying"]},"Honedge":{"#":"679","Attack":"80","Defense":"100","FlavorText":"","HP":"45","Sp. Atk":"35","Sp. Def":"37","Species":"Sword Pok\u00e9mon","Speed":"28","Total":"325","Type":["Steel","Ghost"]},"Hoopa ( Hoopa Confined )":{"#":"720","Attack":"110","Defense":"60","FlavorText":"","HP":"80","Sp. Atk":"150","Sp. Def":"130","Species":"","Speed":"70","Total":"600","Type":["Psychic","Ghost"]},"Hoopa ( Hoopa Unbound )":{"#":"720","Attack":"160","Defense":"60","FlavorText":"","HP":"80","Sp. Atk":"170","Sp. Def":"130","Species":"","Speed":"80","Total":"680","Type":["Psychic","Dark"]},"Hoothoot":{"#":"163","Attack":"30","Defense":"30","FlavorText":"","HP":"60","Sp. Atk":"36","Sp. Def":"56","Species":"Owl Pok\u00e9mon","Speed":"50","Total":"262","Type":["Normal","Flying"]},"Hoppip":{"#":"187","Attack":"35","Defense":"40","FlavorText":"This POK\u00e9MON drifts and floats with the wind. If it senses the approach of strong winds, a HOPPIP links leaves with others to prepare against being blown away.","HP":"35","Sp. Atk":"35","Sp. Def":"55","Species":"Cottonweed Pok\u00e9mon","Speed":"50","Total":"250","Type":["Grass","Flying"]},"Horsea":{"#":"116","Attack":"40","Defense":"70","FlavorText":"","HP":"30","Sp. Atk":"70","Sp. Def":"25","Species":"Dragon Pok\u00e9mon","Speed":"60","Total":"295","Type":["Water"]},"Houndoom":{"#":"229","Attack":"90","Defense":"50","FlavorText":"","HP":"75","Sp. Atk":"110","Sp. Def":"80","Species":"Dark Pok\u00e9mon","Speed":"95","Total":"500","Type":["Dark","Fire"]},"Houndoom ( Mega Houndoom )":{"#":"229","Attack":"90","Defense":"90","FlavorText":"","HP":"75","Sp. Atk":"140","Sp. Def":"90","Species":"","Speed":"115","Total":"600","Type":["Dark","Fire"]},"Houndour":{"#":"228","Attack":"60","Defense":"30","FlavorText":"","HP":"45","Sp. Atk":"80","Sp. Def":"50","Species":"Dark Pok\u00e9mon","Speed":"65","Total":"330","Type":["Dark","Fire"]},"Huntail":{"#":"367","Attack":"104","Defense":"105","FlavorText":"","HP":"55","Sp. Atk":"94","Sp. Def":"75","Species":"Deep Sea Pok\u00e9mon","Speed":"52","Total":"485","Type":["Water"]},"Hydreigon":{"#":"635","Attack":"105","Defense":"90","FlavorText":"","HP":"92","Sp. Atk":"125","Sp. Def":"90","Species":"Brutal Pok\u00e9mon","Speed":"98","Total":"600","Type":["Dark","Dragon"]},"Hypno":{"#":"097","Attack":"73","Defense":"70","FlavorText":"The longer it swings its pendulum, the longer the effects of its hypnosis last.","HP":"85","Sp. Atk":"73","Sp. Def":"115","Species":"Hypnosis Pok\u00e9mon","Speed":"67","Total":"483","Type":["Psychic"]},"Igglybuff":{"#":"174","Attack":"30","Defense":"15","FlavorText":"","HP":"90","Sp. Atk":"40","Sp. Def":"20","Species":"Balloon Pok\u00e9mon","Speed":"15","Total":"210","Type":["Normal","Fairy"]},"Illumise":{"#":"314","Attack":"47","Defense":"55","FlavorText":"A nocturnal POK\u00e9MON that becomes active upon nightfall. It leads a VOLBEAT swarm to draw patterns in the night sky. Over 200 different patterns have been confirmed.","HP":"65","Sp. Atk":"73","Sp. Def":"75","Species":"Firefly Pok\u00e9mon","Speed":"85","Total":"400","Type":["Bug"]},"Infernape":{"#":"392","Attack":"104","Defense":"71","FlavorText":"","HP":"76","Sp. Atk":"104","Sp. Def":"71","Species":"Flame Pok\u00e9mon","Speed":"108","Total":"534","Type":["Fire","Fighting"]},"Inkay":{"#":"686","Attack":"54","Defense":"53","FlavorText":"","HP":"53","Sp. Atk":"37","Sp. Def":"46","Species":"Revolving Pok\u00e9mon","Speed":"45","Total":"288","Type":["Dark","Psychic"]},"Ivysaur":{"#":"002","Attack":"62","Defense":"63","FlavorText":"The bulb on its back grows as it absorbs nutrients. The bulb gives off a pleasant aroma when it blooms.","HP":"60","Sp. Atk":"80","Sp. Def":"80","Species":"Seed Pok\u00e9mon","Speed":"60","Total":"405","Type":["Grass","Poison"]},"Jellicent":{"#":"593","Attack":"60","Defense":"70","FlavorText":"","HP":"100","Sp. Atk":"85","Sp. Def":"105","Species":"Floating Pok\u00e9mon","Speed":"60","Total":"480","Type":["Water","Ghost"]},"Jigglypuff":{"#":"039","Attack":"45","Defense":"20","FlavorText":"","HP":"115","Sp. Atk":"45","Sp. Def":"25","Species":"Balloon Pok\u00e9mon","Speed":"20","Total":"270","Type":["Normal","Fairy"]},"Jirachi":{"#":"385","Attack":"100","Defense":"100","FlavorText":"","HP":"100","Sp. Atk":"100","Sp. Def":"100","Species":"Wish Pok\u00e9mon","Speed":"100","Total":"600","Type":["Steel","Psychic"]},"Jolteon":{"#":"135","Attack":"65","Defense":"60","FlavorText":"","HP":"65","Sp. Atk":"110","Sp. Def":"95","Species":"Lightning Pok\u00e9mon","Speed":"130","Total":"525","Type":["Electric"]},"Joltik":{"#":"595","Attack":"47","Defense":"50","FlavorText":"","HP":"50","Sp. Atk":"57","Sp. Def":"50","Species":"Attaching Pok\u00e9mon","Speed":"65","Total":"319","Type":["Bug","Electric"]},"Jumpluff":{"#":"189","Attack":"55","Defense":"70","FlavorText":"JUMPLUFF ride warm southern winds to cross the sea and fly to foreign lands. This POK\u00e9MON lands when it encounters cold air while it is floating.","HP":"75","Sp. Atk":"55","Sp. Def":"95","Species":"Cottonweed Pok\u00e9mon","Speed":"110","Total":"460","Type":["Grass","Flying"]},"Jynx":{"#":"124","Attack":"50","Defense":"35","FlavorText":"","HP":"65","Sp. Atk":"115","Sp. Def":"95","Species":"Human Shape Pok\u00e9mon","Speed":"95","Total":"455","Type":["Ice","Psychic"]},"Kabuto":{"#":"140","Attack":"80","Defense":"90","FlavorText":"Three hundred million years ago, it hid on the sea floor. It also has eyes on its back that glow.","HP":"30","Sp. Atk":"55","Sp. Def":"45","Species":"Shellfish Pok\u00e9mon","Speed":"55","Total":"355","Type":["Rock","Water"]},"Kabutops":{"#":"141","Attack":"115","Defense":"105","FlavorText":"It was able to swim quickly through the water by compactly folding up its razor-sharp sickles.","HP":"60","Sp. Atk":"65","Sp. Def":"70","Species":"Shellfish Pok\u00e9mon","Speed":"80","Total":"495","Type":["Rock","Water"]},"Kadabra":{"#":"064","Attack":"35","Defense":"30","FlavorText":"","HP":"40","Sp. Atk":"120","Sp. Def":"70","Species":"Psi Pok\u00e9mon","Speed":"105","Total":"400","Type":["Psychic"]},"Kakuna":{"#":"014","Attack":"25","Defense":"50","FlavorText":"","HP":"45","Sp. Atk":"25","Sp. Def":"25","Species":"Cocoon Pok\u00e9mon","Speed":"35","Total":"205","Type":["Bug","Poison"]},"Kangaskhan":{"#":"115","Attack":"95","Defense":"80","FlavorText":"","HP":"105","Sp. Atk":"40","Sp. Def":"80","Species":"Parent Pok\u00e9mon","Speed":"90","Total":"490","Type":["Normal"]},"Kangaskhan ( Mega Kangaskhan )":{"#":"115","Attack":"125","Defense":"100","FlavorText":"","HP":"105","Sp. Atk":"60","Sp. Def":"100","Species":"","Speed":"100","Total":"590","Type":["Normal"]},"Karrablast":{"#":"588","Attack":"75","Defense":"45","FlavorText":"For some reason they evolve when they receive electrical energy while they are attacking Shelmet.","HP":"50","Sp. Atk":"40","Sp. Def":"45","Species":"Clamping Pok\u00e9mon","Speed":"60","Total":"315","Type":["Bug"]},"Kecleon":{"#":"352","Attack":"90","Defense":"70","FlavorText":"","HP":"60","Sp. Atk":"60","Sp. Def":"120","Species":"Color Swap Pok\u00e9mon","Speed":"40","Total":"440","Type":["Normal"]},"Keldeo ( Ordinary Forme )":{"#":"647","Attack":"72","Defense":"90","FlavorText":"","HP":"91","Sp. Atk":"129","Sp. Def":"90","Species":"","Speed":"108","Total":"580","Type":["Water","Fighting"]},"Keldeo ( Resolute Forme )":{"#":"647","Attack":"72","Defense":"90","FlavorText":"","HP":"91","Sp. Atk":"129","Sp. Def":"90","Species":"","Speed":"108","Total":"580","Type":["Water","Fighting"]},"Kingdra":{"#":"230","Attack":"95","Defense":"95","FlavorText":"","HP":"75","Sp. Atk":"95","Sp. Def":"95","Species":"Dragon Pok\u00e9mon","Speed":"85","Total":"540","Type":["Water","Dragon"]},"Kingler":{"#":"099","Attack":"130","Defense":"115","FlavorText":"Its oversized claw is very powerful, but when it's not in battle, the claw just gets in the way.","HP":"55","Sp. Atk":"50","Sp. Def":"50","Species":"Pincer Pok\u00e9mon","Speed":"75","Total":"475","Type":["Water"]},"Kirlia":{"#":"281","Attack":"35","Defense":"35","FlavorText":"","HP":"38","Sp. Atk":"65","Sp. Def":"55","Species":"Emotion Pok\u00e9mon","Speed":"50","Total":"278","Type":["Psychic","Fairy"]},"Klang":{"#":"600","Attack":"80","Defense":"95","FlavorText":"","HP":"60","Sp. Atk":"70","Sp. Def":"85","Species":"Gear Pok\u00e9mon","Speed":"50","Total":"440","Type":["Steel"]},"Klefki":{"#":"707","Attack":"80","Defense":"91","FlavorText":"","HP":"57","Sp. Atk":"80","Sp. Def":"87","Species":"Key Ring Pok\u00e9mon","Speed":"75","Total":"470","Type":["Steel","Fairy"]},"Klink":{"#":"599","Attack":"55","Defense":"70","FlavorText":"","HP":"40","Sp. Atk":"45","Sp. Def":"60","Species":"Gear Pok\u00e9mon","Speed":"30","Total":"300","Type":["Steel"]},"Klinklang":{"#":"601","Attack":"100","Defense":"115","FlavorText":"","HP":"60","Sp. Atk":"70","Sp. Def":"85","Species":"Gear Pok\u00e9mon","Speed":"90","Total":"520","Type":["Steel"]},"Koffing":{"#":"109","Attack":"65","Defense":"95","FlavorText":"","HP":"40","Sp. Atk":"60","Sp. Def":"45","Species":"Poison Gas Pok\u00e9mon","Speed":"35","Total":"340","Type":["Poison"]},"Krabby":{"#":"098","Attack":"105","Defense":"90","FlavorText":"If it is unable to find food, it will absorb nutrients by swallowing a mouthful of sand.","HP":"30","Sp. Atk":"25","Sp. Def":"25","Species":"River Crab Pok\u00e9mon","Speed":"50","Total":"325","Type":["Water"]},"Kricketot":{"#":"401","Attack":"25","Defense":"41","FlavorText":"","HP":"37","Sp. Atk":"25","Sp. Def":"41","Species":"Cricket Pok\u00e9mon","Speed":"25","Total":"194","Type":["Bug"]},"Kricketune":{"#":"402","Attack":"85","Defense":"51","FlavorText":"","HP":"77","Sp. Atk":"55","Sp. Def":"51","Species":"Cricket Pok\u00e9mon","Speed":"65","Total":"384","Type":["Bug"]},"Krokorok":{"#":"552","Attack":"82","Defense":"45","FlavorText":"The special membrane covering its eyes can sense the heat of objects, so it can see its surroundings even in darkness.","HP":"60","Sp. Atk":"45","Sp. Def":"45","Species":"Desert Croc Pok\u00e9mon","Speed":"74","Total":"351","Type":["Ground","Dark"]},"Krookodile":{"#":"553","Attack":"117","Defense":"80","FlavorText":"They never allow prey to escape. Their jaws are so powerful, they can crush the body of an automobile.","HP":"95","Sp. Atk":"65","Sp. Def":"70","Species":"Intimidation Pok\u00e9mon","Speed":"92","Total":"519","Type":["Ground","Dark"]},"Kyogre":{"#":"382","Attack":"100","Defense":"90","FlavorText":"","HP":"100","Sp. Atk":"150","Sp. Def":"140","Species":"Sea Basin Pok\u00e9mon","Speed":"90","Total":"670","Type":["Water"]},"Kyogre ( Primal Kyogre )":{"#":"382","Attack":"150","Defense":"90","FlavorText":"","HP":"100","Sp. Atk":"180","Sp. Def":"160","Species":"","Speed":"90","Total":"770","Type":["Water"]},"Kyurem":{"#":"646","Attack":"130","Defense":"90","FlavorText":"","HP":"125","Sp. Atk":"130","Sp. Def":"90","Species":"Boundary Pok\u00e9mon","Speed":"95","Total":"660","Type":["Dragon","Ice"]},"Kyurem ( Black Kyurem )":{"#":"646","Attack":"170","Defense":"100","FlavorText":"","HP":"125","Sp. Atk":"120","Sp. Def":"90","Species":"","Speed":"95","Total":"700","Type":["Dragon","Ice"]},"Kyurem ( White Kyurem )":{"#":"646","Attack":"120","Defense":"90","FlavorText":"","HP":"125","Sp. Atk":"170","Sp. Def":"100","Species":"","Speed":"95","Total":"700","Type":["Dragon","Ice"]},"Lairon":{"#":"305","Attack":"90","Defense":"140","FlavorText":"","HP":"60","Sp. Atk":"50","Sp. Def":"50","Species":"Iron Armor Pok\u00e9mon","Speed":"40","Total":"430","Type":["Steel","Rock"]},"Lampent":{"#":"608","Attack":"40","Defense":"60","FlavorText":"It arrives near the moment of death and steals spirit from the body.","HP":"60","Sp. Atk":"95","Sp. Def":"60","Species":"Lamp Pok\u00e9mon","Speed":"55","Total":"370","Type":["Ghost","Fire"]},"Landorus ( Incarnate Forme )":{"#":"645","Attack":"125","Defense":"90","FlavorText":"","HP":"89","Sp. Atk":"115","Sp. Def":"80","Species":"","Speed":"101","Total":"600","Type":["Ground","Flying"]},"Landorus ( Therian Forme )":{"#":"645","Attack":"145","Defense":"90","FlavorText":"","HP":"89","Sp. Atk":"105","Sp. Def":"80","Species":"","Speed":"91","Total":"600","Type":["Ground","Flying"]},"Lanturn":{"#":"171","Attack":"58","Defense":"58","FlavorText":"","HP":"125","Sp. Atk":"76","Sp. Def":"76","Species":"Light Pok\u00e9mon","Speed":"67","Total":"460","Type":["Water","Electric"]},"Lapras":{"#":"131","Attack":"85","Defense":"80","FlavorText":"","HP":"130","Sp. Atk":"85","Sp. Def":"95","Species":"Transport Pok\u00e9mon","Speed":"60","Total":"535","Type":["Water","Ice"]},"Larvesta":{"#":"636","Attack":"85","Defense":"55","FlavorText":"","HP":"55","Sp. Atk":"50","Sp. Def":"55","Species":"Torch Pok\u00e9mon","Speed":"60","Total":"360","Type":["Bug","Fire"]},"Larvitar":{"#":"246","Attack":"64","Defense":"50","FlavorText":"A LARVITAR is born deep under the ground. It must eat its way through the soil above and reach the surface for it to see its parents\u2019 faces.","HP":"50","Sp. Atk":"45","Sp. Def":"50","Species":"Rock Skin Pok\u00e9mon","Speed":"41","Total":"300","Type":["Rock","Ground"]},"Latias":{"#":"380","Attack":"80","Defense":"90","FlavorText":"","HP":"80","Sp. Atk":"110","Sp. Def":"130","Species":"Eon Pok\u00e9mon","Speed":"110","Total":"600","Type":["Dragon","Psychic"]},"Latias ( Mega Latias )":{"#":"380","Attack":"100","Defense":"120","FlavorText":"","HP":"80","Sp. Atk":"140","Sp. Def":"150","Species":"","Speed":"110","Total":"700","Type":["Dragon","Psychic"]},"Latios":{"#":"381","Attack":"90","Defense":"80","FlavorText":"","HP":"80","Sp. Atk":"130","Sp. Def":"110","Species":"Eon Pok\u00e9mon","Speed":"110","Total":"600","Type":["Dragon","Psychic"]},"Latios ( Mega Latios )":{"#":"381","Attack":"130","Defense":"100","FlavorText":"","HP":"80","Sp. Atk":"160","Sp. Def":"120","Species":"","Speed":"110","Total":"700","Type":["Dragon","Psychic"]},"Leafeon":{"#":"470","Attack":"110","Defense":"130","FlavorText":"","HP":"65","Sp. Atk":"60","Sp. Def":"65","Species":"Verdant Pok\u00e9mon","Speed":"95","Total":"525","Type":["Grass"]},"Leavanny":{"#":"542","Attack":"103","Defense":"80","FlavorText":"","HP":"75","Sp. Atk":"70","Sp. Def":"80","Species":"Nurturing Pok\u00e9mon","Speed":"92","Total":"500","Type":["Bug","Grass"]},"Ledian":{"#":"166","Attack":"35","Defense":"50","FlavorText":"It is said that in lands with clean air, where the stars fill the sky, there live many LEDIAN. For good reason, they use the light of the stars as energy.","HP":"55","Sp. Atk":"55","Sp. Def":"110","Species":"Five Star Pok\u00e9mon","Speed":"85","Total":"390","Type":["Bug","Flying"]},"Ledyba":{"#":"165","Attack":"20","Defense":"30","FlavorText":"LEDYBA communicate using a fluid that they secrete from where the legs join the body. They are said to convey feelings to others by altering the fluid\u2019s scent.","HP":"40","Sp. Atk":"40","Sp. Def":"80","Species":"Five Star Pok\u00e9mon","Speed":"55","Total":"265","Type":["Bug","Flying"]},"Lickilicky":{"#":"463","Attack":"85","Defense":"95","FlavorText":"","HP":"110","Sp. Atk":"80","Sp. Def":"95","Species":"Licking Pok\u00e9mon","Speed":"50","Total":"515","Type":["Normal"]},"Lickitung":{"#":"108","Attack":"55","Defense":"75","FlavorText":"","HP":"90","Sp. Atk":"60","Sp. Def":"75","Species":"Licking Pok\u00e9mon","Speed":"30","Total":"385","Type":["Normal"]},"Liepard":{"#":"510","Attack":"88","Defense":"50","FlavorText":"Stealthily, it sneaks up on its target, striking from behind before its victim has a chance to react.","HP":"64","Sp. Atk":"88","Sp. Def":"50","Species":"Cruel Pok\u00e9mon","Speed":"106","Total":"446","Type":["Dark"]},"Lileep":{"#":"345","Attack":"41","Defense":"77","FlavorText":"","HP":"66","Sp. Atk":"61","Sp. Def":"87","Species":"Sea Lily Pok\u00e9mon","Speed":"23","Total":"355","Type":["Rock","Grass"]},"Lilligant":{"#":"549","Attack":"60","Defense":"75","FlavorText":"","HP":"70","Sp. Atk":"110","Sp. Def":"75","Species":"Flowering Pok\u00e9mon","Speed":"90","Total":"480","Type":["Grass"]},"Lillipup":{"#":"506","Attack":"60","Defense":"45","FlavorText":"","HP":"45","Sp. Atk":"25","Sp. Def":"45","Species":"Puppy Pok\u00e9mon","Speed":"55","Total":"275","Type":["Normal"]},"Linoone":{"#":"264","Attack":"70","Defense":"61","FlavorText":"It is exceedingly fast if it only has to run in a straight line. When it spots pond-dwelling prey underwater, it quickly leaps in and catches it with its sharp claws.","HP":"78","Sp. Atk":"50","Sp. Def":"61","Species":"Rushing Pok\u00e9mon","Speed":"100","Total":"420","Type":["Normal"]},"Litleo":{"#":"667","Attack":"50","Defense":"58","FlavorText":"","HP":"62","Sp. Atk":"73","Sp. Def":"54","Species":"Lion Cub Pok\u00e9mon","Speed":"72","Total":"369","Type":["Fire","Normal"]},"Litwick":{"#":"607","Attack":"30","Defense":"55","FlavorText":"Litwick shines a light that absorbs the life energy of people and Pok\u00e9mon, which becomes the fuel that it burns.","HP":"50","Sp. Atk":"65","Sp. Def":"55","Species":"Candle Pok\u00e9mon","Speed":"20","Total":"275","Type":["Ghost","Fire"]},"Lombre":{"#":"271","Attack":"50","Defense":"50","FlavorText":"In the evening, it takes great delight in popping out of rivers and startling people. It feeds on aquatic moss that grows on rocks in the riverbed.","HP":"60","Sp. Atk":"60","Sp. Def":"70","Species":"Jolly Pok\u00e9mon","Speed":"50","Total":"340","Type":["Water","Grass"]},"Lopunny":{"#":"428","Attack":"76","Defense":"84","FlavorText":"","HP":"65","Sp. Atk":"54","Sp. Def":"96","Species":"Rabbit Pok\u00e9mon","Speed":"105","Total":"480","Type":["Normal"]},"Lopunny ( Mega Lopunny )":{"#":"428","Attack":"136","Defense":"94","FlavorText":"","HP":"65","Sp. Atk":"54","Sp. Def":"96","Species":"","Speed":"135","Total":"580","Type":["Normal","Fighting"]},"Lotad":{"#":"270","Attack":"30","Defense":"30","FlavorText":"This POK\u00e9MON lives in ponds with clean water. It is known to ferry small POK\u00e9MON across ponds by carrying them on the broad leaf on its head.","HP":"40","Sp. Atk":"40","Sp. Def":"50","Species":"Water Weed Pok\u00e9mon","Speed":"30","Total":"220","Type":["Water","Grass"]},"Loudred":{"#":"294","Attack":"71","Defense":"43","FlavorText":"","HP":"84","Sp. Atk":"71","Sp. Def":"43","Species":"Big Voice Pok\u00e9mon","Speed":"48","Total":"360","Type":["Normal"]},"Lucario":{"#":"448","Attack":"110","Defense":"70","FlavorText":"","HP":"70","Sp. Atk":"115","Sp. Def":"70","Species":"Aura Pok\u00e9mon","Speed":"90","Total":"525","Type":["Fighting","Steel"]},"Lucario ( Mega Lucario )":{"#":"448","Attack":"145","Defense":"88","FlavorText":"","HP":"70","Sp. Atk":"140","Sp. Def":"70","Species":"","Speed":"112","Total":"625","Type":["Fighting","Steel"]},"Ludicolo":{"#":"272","Attack":"70","Defense":"70","FlavorText":"When it hears festive music, all the cells in its body become stimulated, and it begins moving in rhythm. It does not quail even when it faces a tough opponent.","HP":"80","Sp. Atk":"90","Sp. Def":"100","Species":"Carefree Pok\u00e9mon","Speed":"70","Total":"480","Type":["Water","Grass"]},"Lugia":{"#":"249","Attack":"90","Defense":"130","FlavorText":"","HP":"106","Sp. Atk":"90","Sp. Def":"154","Species":"Diving Pok\u00e9mon","Speed":"110","Total":"680","Type":["Psychic","Flying"]},"Lumineon":{"#":"457","Attack":"69","Defense":"76","FlavorText":"","HP":"69","Sp. Atk":"69","Sp. Def":"86","Species":"Neon Pok\u00e9mon","Speed":"91","Total":"460","Type":["Water"]},"Lunatone":{"#":"337","Attack":"55","Defense":"65","FlavorText":"","HP":"70","Sp. Atk":"95","Sp. Def":"85","Species":"Meteorite Pok\u00e9mon","Speed":"70","Total":"440","Type":["Rock","Psychic"]},"Luvdisc":{"#":"370","Attack":"30","Defense":"55","FlavorText":"","HP":"43","Sp. Atk":"40","Sp. Def":"65","Species":"Rendezvous Pok\u00e9mon","Speed":"97","Total":"330","Type":["Water"]},"Luxio":{"#":"404","Attack":"85","Defense":"49","FlavorText":"","HP":"60","Sp. Atk":"60","Sp. Def":"49","Species":"Spark Pok\u00e9mon","Speed":"60","Total":"363","Type":["Electric"]},"Luxray":{"#":"405","Attack":"120","Defense":"79","FlavorText":"","HP":"80","Sp. Atk":"95","Sp. Def":"79","Species":"Gleam Eyes Pok\u00e9mon","Speed":"70","Total":"523","Type":["Electric"]},"Machamp":{"#":"068","Attack":"130","Defense":"80","FlavorText":"","HP":"90","Sp. Atk":"65","Sp. Def":"85","Species":"Superpower Pok\u00e9mon","Speed":"55","Total":"505","Type":["Fighting"]},"Machoke":{"#":"067","Attack":"100","Defense":"70","FlavorText":"","HP":"80","Sp. Atk":"50","Sp. Def":"60","Species":"Superpower Pok\u00e9mon","Speed":"45","Total":"405","Type":["Fighting"]},"Machop":{"#":"066","Attack":"80","Defense":"50","FlavorText":"","HP":"70","Sp. Atk":"35","Sp. Def":"35","Species":"Superpower Pok\u00e9mon","Speed":"35","Total":"305","Type":["Fighting"]},"Magby":{"#":"240","Attack":"75","Defense":"37","FlavorText":"If a MAGBY is spouting yellow flames from its mouth, it is in good health. When it is fatigued, black smoke will be mixed in with the flames.","HP":"45","Sp. Atk":"70","Sp. Def":"55","Species":"Live Coal Pok\u00e9mon","Speed":"83","Total":"365","Type":["Fire"]},"Magcargo":{"#":"219","Attack":"50","Defense":"120","FlavorText":"","HP":"50","Sp. Atk":"80","Sp. Def":"80","Species":"Lava Pok\u00e9mon","Speed":"30","Total":"410","Type":["Fire","Rock"]},"Magikarp":{"#":"129","Attack":"10","Defense":"55","FlavorText":"","HP":"20","Sp. Atk":"15","Sp. Def":"20","Species":"Fish Pok\u00e9mon","Speed":"80","Total":"200","Type":["Water"]},"Magmar":{"#":"126","Attack":"95","Defense":"57","FlavorText":"","HP":"65","Sp. Atk":"100","Sp. Def":"85","Species":"Spitfire Pok\u00e9mon","Speed":"93","Total":"495","Type":["Fire"]},"Magmortar":{"#":"467","Attack":"95","Defense":"67","FlavorText":"","HP":"75","Sp. Atk":"125","Sp. Def":"95","Species":"Blast Pok\u00e9mon","Speed":"83","Total":"540","Type":["Fire"]},"Magnemite":{"#":"081","Attack":"35","Defense":"70","FlavorText":"","HP":"25","Sp. Atk":"95","Sp. Def":"55","Species":"Magnet Pok\u00e9mon","Speed":"45","Total":"325","Type":["Electric","Steel"]},"Magneton":{"#":"082","Attack":"60","Defense":"95","FlavorText":"","HP":"50","Sp. Atk":"120","Sp. Def":"70","Species":"Magnet Pok\u00e9mon","Speed":"70","Total":"465","Type":["Electric","Steel"]},"Magnezone":{"#":"462","Attack":"70","Defense":"115","FlavorText":"","HP":"70","Sp. Atk":"130","Sp. Def":"90","Species":"Magnet Area Pok\u00e9mon","Speed":"60","Total":"535","Type":["Electric","Steel"]},"Makuhita":{"#":"296","Attack":"60","Defense":"30","FlavorText":"It loves to toughen up its body above all else. If you hear quaking rumbles in a cave, it is the sound of MAKUHITA undertaking strenuous training.","HP":"72","Sp. Atk":"20","Sp. Def":"30","Species":"Guts Pok\u00e9mon","Speed":"25","Total":"237","Type":["Fighting"]},"Malamar":{"#":"687","Attack":"92","Defense":"88","FlavorText":"","HP":"86","Sp. Atk":"68","Sp. Def":"75","Species":"Overturning Pok\u00e9mon","Speed":"73","Total":"482","Type":["Dark","Psychic"]},"Mamoswine":{"#":"473","Attack":"130","Defense":"80","FlavorText":"","HP":"110","Sp. Atk":"70","Sp. Def":"60","Species":"Twin Tusk Pok\u00e9mon","Speed":"80","Total":"530","Type":["Ice","Ground"]},"Manaphy":{"#":"490","Attack":"100","Defense":"100","FlavorText":"","HP":"100","Sp. Atk":"100","Sp. Def":"100","Species":"Seafaring Pok\u00e9mon","Speed":"100","Total":"600","Type":["Water"]},"Mandibuzz":{"#":"630","Attack":"65","Defense":"105","FlavorText":"","HP":"110","Sp. Atk":"55","Sp. Def":"95","Species":"Bone Vulture Pok\u00e9mon","Speed":"80","Total":"510","Type":["Dark","Flying"]},"Manectric":{"#":"310","Attack":"75","Defense":"60","FlavorText":"","HP":"70","Sp. Atk":"105","Sp. Def":"60","Species":"Discharge Pok\u00e9mon","Speed":"105","Total":"475","Type":["Electric"]},"Manectric ( Mega Manectric )":{"#":"310","Attack":"75","Defense":"80","FlavorText":"","HP":"70","Sp. Atk":"135","Sp. Def":"80","Species":"","Speed":"135","Total":"575","Type":["Electric"]},"Mankey":{"#":"056","Attack":"80","Defense":"35","FlavorText":"It lives in groups in the treetops. If it loses sight of its group, it becomes infuriated by its loneliness.","HP":"40","Sp. Atk":"35","Sp. Def":"45","Species":"Pig Monkey Pok\u00e9mon","Speed":"70","Total":"305","Type":["Fighting"]},"Mantine":{"#":"226","Attack":"40","Defense":"70","FlavorText":"","HP":"65","Sp. Atk":"80","Sp. Def":"140","Species":"Kite Pok\u00e9mon","Speed":"70","Total":"465","Type":["Water","Flying"]},"Mantyke":{"#":"458","Attack":"20","Defense":"50","FlavorText":"","HP":"45","Sp. Atk":"60","Sp. Def":"120","Species":"Kite Pok\u00e9mon","Speed":"50","Total":"345","Type":["Water","Flying"]},"Maractus":{"#":"556","Attack":"86","Defense":"67","FlavorText":"","HP":"75","Sp. Atk":"106","Sp. Def":"67","Species":"Cactus Pok\u00e9mon","Speed":"60","Total":"461","Type":["Grass"]},"Mareep":{"#":"179","Attack":"40","Defense":"40","FlavorText":"Its fluffy wool rubs together and builds a static charge. The more energy is charged, the more brightly the lightbulb at the tip of its tail glows.","HP":"55","Sp. Atk":"65","Sp. Def":"45","Species":"Wool Pok\u00e9mon","Speed":"35","Total":"280","Type":["Electric"]},"Marill":{"#":"183","Attack":"20","Defense":"50","FlavorText":"","HP":"70","Sp. Atk":"20","Sp. Def":"50","Species":"Aqua Mouse Pok\u00e9mon","Speed":"40","Total":"250","Type":["Water","Fairy"]},"Marowak":{"#":"105","Attack":"80","Defense":"110","FlavorText":"","HP":"60","Sp. Atk":"50","Sp. Def":"80","Species":"Bone Keeper Pok\u00e9mon","Speed":"45","Total":"425","Type":["Ground"]},"Marshtomp":{"#":"259","Attack":"85","Defense":"70","FlavorText":"","HP":"70","Sp. Atk":"60","Sp. Def":"70","Species":"Mud Fish Pok\u00e9mon","Speed":"50","Total":"405","Type":["Water","Ground"]},"Masquerain":{"#":"284","Attack":"60","Defense":"62","FlavorText":"","HP":"70","Sp. Atk":"80","Sp. Def":"82","Species":"Eyeball Pok\u00e9mon","Speed":"60","Total":"414","Type":["Bug","Flying"]},"Mawile":{"#":"303","Attack":"85","Defense":"85","FlavorText":"","HP":"50","Sp. Atk":"55","Sp. Def":"55","Species":"Deceiver Pok\u00e9mon","Speed":"50","Total":"380","Type":["Steel","Fairy"]},"Mawile ( Mega Mawile )":{"#":"303","Attack":"105","Defense":"125","FlavorText":"","HP":"50","Sp. Atk":"55","Sp. Def":"95","Species":"","Speed":"50","Total":"480","Type":["Steel","Fairy"]},"Medicham":{"#":"308","Attack":"60","Defense":"75","FlavorText":"","HP":"60","Sp. Atk":"60","Sp. Def":"75","Species":"Meditate Pok\u00e9mon","Speed":"80","Total":"410","Type":["Fighting","Psychic"]},"Medicham ( Mega Medicham )":{"#":"308","Attack":"100","Defense":"85","FlavorText":"","HP":"60","Sp. Atk":"80","Sp. Def":"85","Species":"","Speed":"100","Total":"510","Type":["Fighting","Psychic"]},"Meditite":{"#":"307","Attack":"40","Defense":"55","FlavorText":"","HP":"30","Sp. Atk":"40","Sp. Def":"55","Species":"Meditate Pok\u00e9mon","Speed":"60","Total":"280","Type":["Fighting","Psychic"]},"Meganium":{"#":"154","Attack":"82","Defense":"100","FlavorText":"","HP":"80","Sp. Atk":"83","Sp. Def":"100","Species":"Herb Pok\u00e9mon","Speed":"80","Total":"525","Type":["Grass"]},"Meloetta ( Aria Forme )":{"#":"648","Attack":"77","Defense":"77","FlavorText":"","HP":"100","Sp. Atk":"128","Sp. Def":"128","Species":"","Speed":"90","Total":"600","Type":["Normal","Psychic"]},"Meloetta ( Pirouette Forme )":{"#":"648","Attack":"128","Defense":"90","FlavorText":"","HP":"100","Sp. Atk":"77","Sp. Def":"77","Species":"","Speed":"128","Total":"600","Type":["Normal","Fighting"]},"Meowstic ( Female )":{"#":"678","Attack":"48","Defense":"76","FlavorText":"","HP":"74","Sp. Atk":"83","Sp. Def":"81","Species":"","Speed":"104","Total":"466","Type":["Psychic"]},"Meowstic ( Male )":{"#":"678","Attack":"48","Defense":"76","FlavorText":"","HP":"74","Sp. Atk":"83","Sp. Def":"81","Species":"","Speed":"104","Total":"466","Type":["Psychic"]},"Meowth":{"#":"052","Attack":"45","Defense":"35","FlavorText":"It loves things that sparkle. When it sees a shiny object, the gold coin on its head shines too.","HP":"40","Sp. Atk":"40","Sp. Def":"40","Species":"Scratch Cat Pok\u00e9mon","Speed":"90","Total":"290","Type":["Normal"]},"Mesprit":{"#":"481","Attack":"105","Defense":"105","FlavorText":"","HP":"80","Sp. Atk":"105","Sp. Def":"105","Species":"Emotion Pok\u00e9mon","Speed":"80","Total":"580","Type":["Psychic"]},"Metagross":{"#":"376","Attack":"135","Defense":"130","FlavorText":"","HP":"80","Sp. Atk":"95","Sp. Def":"90","Species":"Iron Leg Pok\u00e9mon","Speed":"70","Total":"600","Type":["Steel","Psychic"]},"Metagross ( Mega Metagross )":{"#":"376","Attack":"145","Defense":"150","FlavorText":"","HP":"80","Sp. Atk":"105","Sp. Def":"110","Species":"","Speed":"110","Total":"700","Type":["Steel","Psychic"]},"Metang":{"#":"375","Attack":"75","Defense":"100","FlavorText":"","HP":"60","Sp. Atk":"55","Sp. Def":"80","Species":"Iron Claw Pok\u00e9mon","Speed":"50","Total":"420","Type":["Steel","Psychic"]},"Metapod":{"#":"011","Attack":"20","Defense":"55","FlavorText":"","HP":"50","Sp. Atk":"25","Sp. Def":"25","Species":"Cocoon Pok\u00e9mon","Speed":"30","Total":"205","Type":["Bug"]},"Mew":{"#":"151","Attack":"100","Defense":"100","FlavorText":"","HP":"100","Sp. Atk":"100","Sp. Def":"100","Species":"New Species Pok\u00e9mon","Speed":"100","Total":"600","Type":["Psychic"]},"Mewtwo":{"#":"150","Attack":"110","Defense":"90","FlavorText":"","HP":"106","Sp. Atk":"154","Sp. Def":"90","Species":"Genetic Pok\u00e9mon","Speed":"130","Total":"680","Type":["Psychic"]},"Mewtwo ( Mega Mewtwo X )":{"#":"150","Attack":"190","Defense":"100","FlavorText":"","HP":"106","Sp. Atk":"154","Sp. Def":"100","Species":"","Speed":"130","Total":"780","Type":["Psychic","Fighting"]},"Mewtwo ( Mega Mewtwo Y )":{"#":"150","Attack":"150","Defense":"70","FlavorText":"","HP":"106","Sp. Atk":"194","Sp. Def":"120","Species":"","Speed":"140","Total":"780","Type":["Psychic"]},"Mienfoo":{"#":"619","Attack":"85","Defense":"50","FlavorText":"In fights, they dominate with onslaughts of flowing, continuous attacks. With their sharp claws, they cut enemies.","HP":"45","Sp. Atk":"55","Sp. Def":"50","Species":"Martial Arts Pok\u00e9mon","Speed":"65","Total":"350","Type":["Fighting"]},"Mienshao":{"#":"620","Attack":"125","Defense":"60","FlavorText":"Using the long fur on its arms like whips, it launches into combo attacks that, once started, no one can stop.","HP":"65","Sp. Atk":"95","Sp. Def":"60","Species":"Martial Arts Pok\u00e9mon","Speed":"105","Total":"510","Type":["Fighting"]},"Mightyena":{"#":"262","Attack":"90","Defense":"70","FlavorText":"In the wild, MIGHTYENA live in a pack. They never defy their leader\u2019s orders. They defeat foes with perfectly coordinated teamwork.","HP":"70","Sp. Atk":"60","Sp. Def":"60","Species":"Bite Pok\u00e9mon","Speed":"70","Total":"420","Type":["Dark"]},"Milotic":{"#":"350","Attack":"60","Defense":"79","FlavorText":"","HP":"95","Sp. Atk":"100","Sp. Def":"125","Species":"Tender Pok\u00e9mon","Speed":"81","Total":"540","Type":["Water"]},"Miltank":{"#":"241","Attack":"80","Defense":"105","FlavorText":"It gives over five gallons of milk daily. Its sweet milk is enjoyed by children and grown-ups alike. People who can\u2019t drink milk turn it into yogurt and eat it instead.","HP":"95","Sp. Atk":"40","Sp. Def":"70","Species":"Milk Cow Pok\u00e9mon","Speed":"100","Total":"490","Type":["Normal"]},"Mime ( Jr. )":{"#":"439","Attack":"25","Defense":"45","FlavorText":"","HP":"20","Sp. Atk":"70","Sp. Def":"90","Species":"","Speed":"60","Total":"310","Type":["Psychic","Fairy"]},"Minccino":{"#":"572","Attack":"50","Defense":"40","FlavorText":"","HP":"55","Sp. Atk":"40","Sp. Def":"40","Species":"Chinchilla Pok\u00e9mon","Speed":"75","Total":"300","Type":["Normal"]},"Minun":{"#":"312","Attack":"40","Defense":"50","FlavorText":"","HP":"60","Sp. Atk":"75","Sp. Def":"85","Species":"Cheering Pok\u00e9mon","Speed":"95","Total":"405","Type":["Electric"]},"Misdreavus":{"#":"200","Attack":"60","Defense":"60","FlavorText":"","HP":"60","Sp. Atk":"85","Sp. Def":"85","Species":"Screech Pok\u00e9mon","Speed":"85","Total":"435","Type":["Ghost"]},"Mismagius":{"#":"429","Attack":"60","Defense":"60","FlavorText":"","HP":"60","Sp. Atk":"105","Sp. Def":"105","Species":"Magical Pok\u00e9mon","Speed":"105","Total":"495","Type":["Ghost"]},"Moltres":{"#":"146","Attack":"100","Defense":"90","FlavorText":"Legendary bird POK\u00e9MON. It is said to migrate from the south along with the spring.","HP":"90","Sp. Atk":"125","Sp. Def":"85","Species":"Flame Pok\u00e9mon","Speed":"90","Total":"580","Type":["Fire","Flying"]},"Monferno":{"#":"391","Attack":"78","Defense":"52","FlavorText":"","HP":"64","Sp. Atk":"78","Sp. Def":"52","Species":"Playful Pok\u00e9mon","Speed":"81","Total":"405","Type":["Fire","Fighting"]},"Mothim":{"#":"414","Attack":"94","Defense":"50","FlavorText":"","HP":"70","Sp. Atk":"94","Sp. Def":"50","Species":"Moth Pok\u00e9mon","Speed":"66","Total":"424","Type":["Bug","Flying"]},"Mr. ( Mime )":{"#":"122","Attack":"45","Defense":"65","FlavorText":"","HP":"40","Sp. Atk":"100","Sp. Def":"120","Species":"","Speed":"90","Total":"460","Type":["Psychic","Fairy"]},"Mudkip":{"#":"258","Attack":"70","Defense":"50","FlavorText":"","HP":"50","Sp. Atk":"50","Sp. Def":"50","Species":"Mud Fish Pok\u00e9mon","Speed":"40","Total":"310","Type":["Water"]},"Muk":{"#":"089","Attack":"105","Defense":"75","FlavorText":"","HP":"105","Sp. Atk":"65","Sp. Def":"100","Species":"Sludge Pok\u00e9mon","Speed":"50","Total":"500","Type":["Poison"]},"Munchlax":{"#":"446","Attack":"85","Defense":"40","FlavorText":"","HP":"135","Sp. Atk":"40","Sp. Def":"85","Species":"Big Eater Pok\u00e9mon","Speed":"5","Total":"390","Type":["Normal"]},"Munna":{"#":"517","Attack":"25","Defense":"45","FlavorText":"","HP":"76","Sp. Atk":"67","Sp. Def":"55","Species":"Dream Eater Pok\u00e9mon","Speed":"24","Total":"292","Type":["Psychic"]},"Murkrow":{"#":"198","Attack":"85","Defense":"42","FlavorText":"","HP":"60","Sp. Atk":"85","Sp. Def":"42","Species":"Darkness Pok\u00e9mon","Speed":"91","Total":"405","Type":["Dark","Flying"]},"Musharna":{"#":"518","Attack":"55","Defense":"85","FlavorText":"","HP":"116","Sp. Atk":"107","Sp. Def":"95","Species":"Drowsing Pok\u00e9mon","Speed":"29","Total":"487","Type":["Psychic"]},"Natu":{"#":"177","Attack":"50","Defense":"45","FlavorText":"","HP":"40","Sp. Atk":"70","Sp. Def":"45","Species":"Tiny Bird Pok\u00e9mon","Speed":"70","Total":"320","Type":["Psychic","Flying"]},"Nidoking":{"#":"034","Attack":"102","Defense":"77","FlavorText":"","HP":"81","Sp. Atk":"85","Sp. Def":"75","Species":"Drill Pok\u00e9mon","Speed":"85","Total":"505","Type":["Poison","Ground"]},"Nidoqueen":{"#":"031","Attack":"92","Defense":"87","FlavorText":"","HP":"90","Sp. Atk":"75","Sp. Def":"85","Species":"Drill Pok\u00e9mon","Speed":"76","Total":"505","Type":["Poison","Ground"]},"Nidoran\u2640":{"#":"029","Attack":"47","Defense":"52","FlavorText":"","HP":"55","Sp. Atk":"40","Sp. Def":"40","Species":"","Speed":"41","Total":"275","Type":["Poison"]},"Nidoran\u2642":{"#":"032","Attack":"57","Defense":"40","FlavorText":"","HP":"46","Sp. Atk":"40","Sp. Def":"40","Species":"","Speed":"50","Total":"273","Type":["Poison"]},"Nidorina":{"#":"030","Attack":"62","Defense":"67","FlavorText":"","HP":"70","Sp. Atk":"55","Sp. Def":"55","Species":"Poison Pin Pok\u00e9mon","Speed":"56","Total":"365","Type":["Poison"]},"Nidorino":{"#":"033","Attack":"72","Defense":"57","FlavorText":"","HP":"61","Sp. Atk":"55","Sp. Def":"55","Species":"Poison Pin Pok\u00e9mon","Speed":"65","Total":"365","Type":["Poison"]},"Nincada":{"#":"290","Attack":"45","Defense":"90","FlavorText":"","HP":"31","Sp. Atk":"30","Sp. Def":"30","Species":"Trainee Pok\u00e9mon","Speed":"40","Total":"266","Type":["Bug","Ground"]},"Ninetales":{"#":"038","Attack":"76","Defense":"75","FlavorText":"","HP":"73","Sp. Atk":"81","Sp. Def":"100","Species":"Fox Pok\u00e9mon","Speed":"100","Total":"505","Type":["Fire"]},"Ninjask":{"#":"291","Attack":"90","Defense":"45","FlavorText":"","HP":"61","Sp. Atk":"50","Sp. Def":"50","Species":"Ninja Pok\u00e9mon","Speed":"160","Total":"456","Type":["Bug","Flying"]},"Noctowl":{"#":"164","Attack":"50","Defense":"50","FlavorText":"","HP":"100","Sp. Atk":"76","Sp. Def":"96","Species":"Owl Pok\u00e9mon","Speed":"70","Total":"442","Type":["Normal","Flying"]},"Noibat":{"#":"714","Attack":"30","Defense":"35","FlavorText":"","HP":"40","Sp. Atk":"45","Sp. Def":"40","Species":"Sound Wave Pok\u00e9mon","Speed":"55","Total":"245","Type":["Flying","Dragon"]},"Noivern":{"#":"715","Attack":"70","Defense":"80","FlavorText":"","HP":"85","Sp. Atk":"97","Sp. Def":"80","Species":"Sound Wave Pok\u00e9mon","Speed":"123","Total":"535","Type":["Flying","Dragon"]},"Nosepass":{"#":"299","Attack":"45","Defense":"135","FlavorText":"","HP":"30","Sp. Atk":"45","Sp. Def":"90","Species":"Compass Pok\u00e9mon","Speed":"30","Total":"375","Type":["Rock"]},"Numel":{"#":"322","Attack":"60","Defense":"40","FlavorText":"A NUMEL stores boiling magma in the hump on its back. It is a hardy POK\u00e9MON that can transport a 220-pound load. It has served humans at work since long ago.","HP":"60","Sp. Atk":"65","Sp. Def":"45","Species":"Numb Pok\u00e9mon","Speed":"35","Total":"305","Type":["Fire","Ground"]},"Nuzleaf":{"#":"274","Attack":"70","Defense":"40","FlavorText":"","HP":"70","Sp. Atk":"60","Sp. Def":"40","Species":"Wily Pok\u00e9mon","Speed":"60","Total":"340","Type":["Grass","Dark"]},"Octillery":{"#":"224","Attack":"105","Defense":"75","FlavorText":"","HP":"75","Sp. Atk":"105","Sp. Def":"75","Species":"Jet Pok\u00e9mon","Speed":"45","Total":"480","Type":["Water"]},"Oddish":{"#":"043","Attack":"50","Defense":"55","FlavorText":"","HP":"45","Sp. Atk":"75","Sp. Def":"65","Species":"Weed Pok\u00e9mon","Speed":"30","Total":"320","Type":["Grass","Poison"]},"Omanyte":{"#":"138","Attack":"40","Defense":"100","FlavorText":"In prehistoric times, it swam on the sea floor, eating plankton. Its fossils are sometimes found.","HP":"35","Sp. Atk":"90","Sp. Def":"55","Species":"Spiral Pok\u00e9mon","Speed":"35","Total":"355","Type":["Rock","Water"]},"Omastar":{"#":"139","Attack":"60","Defense":"125","FlavorText":"Its heavy shell allowed it to reach only nearby food. This could be the reason it is extinct.","HP":"70","Sp. Atk":"115","Sp. Def":"70","Species":"Spiral Pok\u00e9mon","Speed":"55","Total":"495","Type":["Rock","Water"]},"Onix":{"#":"095","Attack":"45","Defense":"160","FlavorText":"","HP":"35","Sp. Atk":"30","Sp. Def":"45","Species":"Rock Snake Pok\u00e9mon","Speed":"70","Total":"385","Type":["Rock","Ground"]},"Oshawott":{"#":"501","Attack":"55","Defense":"45","FlavorText":"","HP":"55","Sp. Atk":"63","Sp. Def":"45","Species":"Sea Otter Pok\u00e9mon","Speed":"45","Total":"308","Type":["Water"]},"Pachirisu":{"#":"417","Attack":"45","Defense":"70","FlavorText":"","HP":"60","Sp. Atk":"45","Sp. Def":"90","Species":"EleSquirrel Pok\u00e9mon","Speed":"95","Total":"405","Type":["Electric"]},"Palkia":{"#":"484","Attack":"120","Defense":"100","FlavorText":"","HP":"90","Sp. Atk":"150","Sp. Def":"120","Species":"Spatial Pok\u00e9mon","Speed":"100","Total":"680","Type":["Water","Dragon"]},"Palpitoad":{"#":"536","Attack":"65","Defense":"55","FlavorText":"","HP":"75","Sp. Atk":"65","Sp. Def":"55","Species":"Vibration Pok\u00e9mon","Speed":"69","Total":"384","Type":["Water","Ground"]},"Pancham":{"#":"674","Attack":"82","Defense":"62","FlavorText":"","HP":"67","Sp. Atk":"46","Sp. Def":"48","Species":"Playful Pok\u00e9mon","Speed":"43","Total":"348","Type":["Fighting"]},"Pangoro":{"#":"675","Attack":"124","Defense":"78","FlavorText":"","HP":"95","Sp. Atk":"69","Sp. Def":"71","Species":"Daunting Pok\u00e9mon","Speed":"58","Total":"495","Type":["Fighting","Dark"]},"Panpour":{"#":"515","Attack":"53","Defense":"48","FlavorText":"","HP":"50","Sp. Atk":"53","Sp. Def":"48","Species":"Spray Pok\u00e9mon","Speed":"64","Total":"316","Type":["Water"]},"Pansage":{"#":"511","Attack":"53","Defense":"48","FlavorText":"","HP":"50","Sp. Atk":"53","Sp. Def":"48","Species":"Grass Monkey Pok\u00e9mon","Speed":"64","Total":"316","Type":["Grass"]},"Pansear":{"#":"513","Attack":"53","Defense":"48","FlavorText":"","HP":"50","Sp. Atk":"53","Sp. Def":"48","Species":"High Temp Pok\u00e9mon","Speed":"64","Total":"316","Type":["Fire"]},"Paras":{"#":"046","Attack":"70","Defense":"55","FlavorText":"A PARAS has parasitic tochukaso mushrooms growing on its back. They grow by drawing nutrients from the host. They are valued as a medicine for long life.","HP":"35","Sp. Atk":"45","Sp. Def":"55","Species":"Mushroom Pok\u00e9mon","Speed":"25","Total":"285","Type":["Bug","Grass"]},"Parasect":{"#":"047","Attack":"95","Defense":"80","FlavorText":"When nothing's left to extract from the bug, the mushrooms on its back leave spores on the bug's egg.","HP":"60","Sp. Atk":"60","Sp. Def":"80","Species":"Mushroom Pok\u00e9mon","Speed":"30","Total":"405","Type":["Bug","Grass"]},"Patrat":{"#":"504","Attack":"55","Defense":"39","FlavorText":"Extremely cautious, one of them will always be on the lookout, but it won\u2019t notice a foe coming from behind.","HP":"45","Sp. Atk":"35","Sp. Def":"39","Species":"Scout Pok\u00e9mon","Speed":"42","Total":"255","Type":["Normal"]},"Pawniard":{"#":"624","Attack":"85","Defense":"70","FlavorText":"Ignoring their injuries, groups attack by sinking the blades that cover their bodies into their prey.","HP":"45","Sp. Atk":"40","Sp. Def":"40","Species":"Sharp Blade Pok\u00e9mon","Speed":"60","Total":"340","Type":["Dark","Steel"]},"Pelipper":{"#":"279","Attack":"50","Defense":"100","FlavorText":"","HP":"60","Sp. Atk":"85","Sp. Def":"70","Species":"Water Bird Pok\u00e9mon","Speed":"65","Total":"430","Type":["Water","Flying"]},"Persian":{"#":"053","Attack":"70","Defense":"60","FlavorText":"Behind its lithe, elegant appearance lies a barbaric side. It will tear apart its prey on a mere whim.","HP":"65","Sp. Atk":"65","Sp. Def":"65","Species":"Classy Cat Pok\u00e9mon","Speed":"115","Total":"440","Type":["Normal"]},"Petilil":{"#":"548","Attack":"35","Defense":"50","FlavorText":"","HP":"45","Sp. Atk":"70","Sp. Def":"50","Species":"Bulb Pok\u00e9mon","Speed":"30","Total":"280","Type":["Grass"]},"Phanpy":{"#":"231","Attack":"60","Defense":"60","FlavorText":"","HP":"90","Sp. Atk":"40","Sp. Def":"40","Species":"Long Nose Pok\u00e9mon","Speed":"40","Total":"330","Type":["Ground"]},"Phantump":{"#":"708","Attack":"70","Defense":"48","FlavorText":"","HP":"43","Sp. Atk":"50","Sp. Def":"60","Species":"Stump Pok\u00e9mon","Speed":"38","Total":"309","Type":["Ghost","Grass"]},"Phione":{"#":"489","Attack":"80","Defense":"80","FlavorText":"","HP":"80","Sp. Atk":"80","Sp. Def":"80","Species":"Sea Drifter Pok\u00e9mon","Speed":"80","Total":"480","Type":["Water"]},"Pichu":{"#":"172","Attack":"40","Defense":"15","FlavorText":"","HP":"20","Sp. Atk":"35","Sp. Def":"35","Species":"Tiny Mouse Pok\u00e9mon","Speed":"60","Total":"205","Type":["Electric"]},"Pidgeot":{"#":"018","Attack":"80","Defense":"75","FlavorText":"","HP":"83","Sp. Atk":"70","Sp. Def":"70","Species":"Bird Pok\u00e9mon","Speed":"101","Total":"479","Type":["Normal","Flying"]},"Pidgeot ( Mega Pidgeot )":{"#":"018","Attack":"80","Defense":"80","FlavorText":"","HP":"83","Sp. Atk":"135","Sp. Def":"80","Species":"","Speed":"121","Total":"579","Type":["Normal","Flying"]},"Pidgeotto":{"#":"017","Attack":"60","Defense":"55","FlavorText":"","HP":"63","Sp. Atk":"50","Sp. Def":"50","Species":"Bird Pok\u00e9mon","Speed":"71","Total":"349","Type":["Normal","Flying"]},"Pidgey":{"#":"016","Attack":"45","Defense":"40","FlavorText":"","HP":"40","Sp. Atk":"35","Sp. Def":"35","Species":"Tiny Bird Pok\u00e9mon","Speed":"56","Total":"251","Type":["Normal","Flying"]},"Pidove":{"#":"519","Attack":"55","Defense":"50","FlavorText":"","HP":"50","Sp. Atk":"36","Sp. Def":"30","Species":"Tiny Pigeon Pok\u00e9mon","Speed":"43","Total":"264","Type":["Normal","Flying"]},"Pignite":{"#":"499","Attack":"93","Defense":"55","FlavorText":"","HP":"90","Sp. Atk":"70","Sp. Def":"55","Species":"Fire Pig Pok\u00e9mon","Speed":"55","Total":"418","Type":["Fire","Fighting"]},"Pikachu":{"#":"025","Attack":"55","Defense":"40","FlavorText":"","HP":"35","Sp. Atk":"50","Sp. Def":"50","Species":"Mouse Pok\u00e9mon","Speed":"90","Total":"320","Type":["Electric"]},"Piloswine":{"#":"221","Attack":"100","Defense":"80","FlavorText":"","HP":"100","Sp. Atk":"60","Sp. Def":"60","Species":"Swine Pok\u00e9mon","Speed":"50","Total":"450","Type":["Ice","Ground"]},"Pineco":{"#":"204","Attack":"65","Defense":"90","FlavorText":"","HP":"50","Sp. Atk":"35","Sp. Def":"35","Species":"Bagworm Pok\u00e9mon","Speed":"15","Total":"290","Type":["Bug"]},"Pinsir":{"#":"127","Attack":"125","Defense":"100","FlavorText":"","HP":"65","Sp. Atk":"55","Sp. Def":"70","Species":"Stag Beetle Pok\u00e9mon","Speed":"85","Total":"500","Type":["Bug"]},"Pinsir ( Mega Pinsir )":{"#":"127","Attack":"155","Defense":"120","FlavorText":"","HP":"65","Sp. Atk":"65","Sp. Def":"90","Species":"","Speed":"105","Total":"600","Type":["Bug","Flying"]},"Piplup":{"#":"393","Attack":"51","Defense":"53","FlavorText":"","HP":"53","Sp. Atk":"61","Sp. Def":"56","Species":"Penguin Pok\u00e9mon","Speed":"40","Total":"314","Type":["Water"]},"Plusle":{"#":"311","Attack":"50","Defense":"40","FlavorText":"","HP":"60","Sp. Atk":"85","Sp. Def":"75","Species":"Cheering Pok\u00e9mon","Speed":"95","Total":"405","Type":["Electric"]},"Politoed":{"#":"186","Attack":"75","Defense":"75","FlavorText":"The curled hair on its head proves its status as a king. It is said that the longer and curlier the hair, the more respect it earns from its peers.","HP":"90","Sp. Atk":"90","Sp. Def":"100","Species":"Frog Pok\u00e9mon","Speed":"70","Total":"500","Type":["Water"]},"Poliwag":{"#":"060","Attack":"50","Defense":"40","FlavorText":"","HP":"40","Sp. Atk":"40","Sp. Def":"40","Species":"Tadpole Pok\u00e9mon","Speed":"90","Total":"300","Type":["Water"]},"Poliwhirl":{"#":"061","Attack":"65","Defense":"65","FlavorText":"","HP":"65","Sp. Atk":"50","Sp. Def":"50","Species":"Tadpole Pok\u00e9mon","Speed":"90","Total":"385","Type":["Water"]},"Poliwrath":{"#":"062","Attack":"95","Defense":"95","FlavorText":"","HP":"90","Sp. Atk":"70","Sp. Def":"90","Species":"Tadpole Pok\u00e9mon","Speed":"70","Total":"510","Type":["Water","Fighting"]},"Ponyta":{"#":"077","Attack":"85","Defense":"55","FlavorText":"","HP":"50","Sp. Atk":"65","Sp. Def":"65","Species":"Fire Horse Pok\u00e9mon","Speed":"90","Total":"410","Type":["Fire"]},"Poochyena":{"#":"261","Attack":"55","Defense":"35","FlavorText":"It savagely threatens foes with bared fangs. It chases after fleeing targets tenaciously. It turns tail and runs, however, if the foe strikes back.","HP":"35","Sp. Atk":"30","Sp. Def":"30","Species":"Bite Pok\u00e9mon","Speed":"35","Total":"220","Type":["Dark"]},"Porygon":{"#":"137","Attack":"60","Defense":"70","FlavorText":"","HP":"65","Sp. Atk":"85","Sp. Def":"75","Species":"Virtual Pok\u00e9mon","Speed":"40","Total":"395","Type":["Normal"]},"Porygon- ( Z )":{"#":"474","Attack":"80","Defense":"70","FlavorText":"","HP":"85","Sp. Atk":"135","Sp. Def":"75","Species":"","Speed":"90","Total":"535","Type":["Normal"]},"Porygon2":{"#":"233","Attack":"80","Defense":"90","FlavorText":"It was created by humans using the power of science. It has been given artificial intelligence that enables it to learn new gestures and emotions on its own.","HP":"85","Sp. Atk":"105","Sp. Def":"95","Species":"Virtual Pok\u00e9mon","Speed":"60","Total":"515","Type":["Normal"]},"Primeape":{"#":"057","Attack":"105","Defense":"60","FlavorText":"It will beat up anyone who makes it mad, even if it has to chase them until the end of the world.","HP":"65","Sp. Atk":"60","Sp. Def":"70","Species":"Pig Monkey Pok\u00e9mon","Speed":"95","Total":"455","Type":["Fighting"]},"Prinplup":{"#":"394","Attack":"66","Defense":"68","FlavorText":"","HP":"64","Sp. Atk":"81","Sp. Def":"76","Species":"Penguin Pok\u00e9mon","Speed":"50","Total":"405","Type":["Water"]},"Probopass":{"#":"476","Attack":"55","Defense":"145","FlavorText":"","HP":"60","Sp. Atk":"75","Sp. Def":"150","Species":"Compass Pok\u00e9mon","Speed":"40","Total":"525","Type":["Rock","Steel"]},"Psyduck":{"#":"054","Attack":"52","Defense":"48","FlavorText":"","HP":"50","Sp. Atk":"65","Sp. Def":"50","Species":"Duck Pok\u00e9mon","Speed":"55","Total":"320","Type":["Water"]},"Pumpkaboo ( Average Size )":{"#":"710","Attack":"66","Defense":"70","FlavorText":"","HP":"49","Sp. Atk":"44","Sp. Def":"55","Species":"","Speed":"51","Total":"335","Type":["Ghost","Grass"]},"Pumpkaboo ( Large Size )":{"#":"710","Attack":"66","Defense":"70","FlavorText":"","HP":"54","Sp. Atk":"44","Sp. Def":"55","Species":"","Speed":"46","Total":"335","Type":["Ghost","Grass"]},"Pumpkaboo ( Small Size )":{"#":"710","Attack":"66","Defense":"70","FlavorText":"","HP":"44","Sp. Atk":"44","Sp. Def":"55","Species":"","Speed":"56","Total":"335","Type":["Ghost","Grass"]},"Pumpkaboo ( Super Size )":{"#":"710","Attack":"66","Defense":"70","FlavorText":"","HP":"59","Sp. Atk":"44","Sp. Def":"55","Species":"","Speed":"41","Total":"335","Type":["Ghost","Grass"]},"Pupitar":{"#":"247","Attack":"84","Defense":"70","FlavorText":"","HP":"70","Sp. Atk":"65","Sp. Def":"70","Species":"Hard Shell Pok\u00e9mon","Speed":"51","Total":"410","Type":["Rock","Ground"]},"Purrloin":{"#":"509","Attack":"50","Defense":"37","FlavorText":"They steal from people for fun, but their victims can\u2019t help but forgive them. Their deceptively cute act is perfect.","HP":"41","Sp. Atk":"50","Sp. Def":"37","Species":"Devious Pok\u00e9mon","Speed":"66","Total":"281","Type":["Dark"]},"Purugly":{"#":"432","Attack":"82","Defense":"64","FlavorText":"","HP":"71","Sp. Atk":"64","Sp. Def":"59","Species":"Tiger Cat Pok\u00e9mon","Speed":"112","Total":"452","Type":["Normal"]},"Pyroar":{"#":"668","Attack":"68","Defense":"72","FlavorText":"","HP":"86","Sp. Atk":"109","Sp. Def":"66","Species":"Royal Pok\u00e9mon","Speed":"106","Total":"507","Type":["Fire","Normal"]},"Quagsire":{"#":"195","Attack":"85","Defense":"85","FlavorText":"","HP":"95","Sp. Atk":"65","Sp. Def":"65","Species":"Water Fish Pok\u00e9mon","Speed":"35","Total":"430","Type":["Water","Ground"]},"Quilava":{"#":"156","Attack":"64","Defense":"58","FlavorText":"","HP":"58","Sp. Atk":"80","Sp. Def":"65","Species":"Volcano Pok\u00e9mon","Speed":"80","Total":"405","Type":["Fire"]},"Quilladin":{"#":"651","Attack":"78","Defense":"95","FlavorText":"","HP":"61","Sp. Atk":"56","Sp. Def":"58","Species":"Spiny Armor Pok\u00e9mon","Speed":"57","Total":"405","Type":["Grass"]},"Qwilfish":{"#":"211","Attack":"95","Defense":"75","FlavorText":"A QWILFISH uses the pressure of water it swallows to shoot toxic quills all at once from all over its body. It finds swimming to be somewhat challenging.","HP":"65","Sp. Atk":"55","Sp. Def":"55","Species":"Balloon Pok\u00e9mon","Speed":"85","Total":"430","Type":["Water","Poison"]},"Raichu":{"#":"026","Attack":"90","Defense":"55","FlavorText":"","HP":"60","Sp. Atk":"90","Sp. Def":"80","Species":"Mouse Pok\u00e9mon","Speed":"110","Total":"485","Type":["Electric"]},"Raikou":{"#":"243","Attack":"85","Defense":"75","FlavorText":"","HP":"90","Sp. Atk":"115","Sp. Def":"100","Species":"Thunder Pok\u00e9mon","Speed":"115","Total":"580","Type":["Electric"]},"Ralts":{"#":"280","Attack":"25","Defense":"25","FlavorText":"","HP":"28","Sp. Atk":"45","Sp. Def":"35","Species":"Feeling Pok\u00e9mon","Speed":"40","Total":"198","Type":["Psychic","Fairy"]},"Rampardos":{"#":"409","Attack":"165","Defense":"60","FlavorText":"","HP":"97","Sp. Atk":"65","Sp. Def":"50","Species":"Head Butt Pok\u00e9mon","Speed":"58","Total":"495","Type":["Rock"]},"Rapidash":{"#":"078","Attack":"100","Defense":"70","FlavorText":"","HP":"65","Sp. Atk":"80","Sp. Def":"80","Species":"Fire Horse Pok\u00e9mon","Speed":"105","Total":"500","Type":["Fire"]},"Raticate":{"#":"020","Attack":"81","Defense":"60","FlavorText":"","HP":"55","Sp. Atk":"50","Sp. Def":"70","Species":"Mouse Pok\u00e9mon","Speed":"97","Total":"413","Type":["Normal"]},"Rattata":{"#":"019","Attack":"56","Defense":"35","FlavorText":"","HP":"30","Sp. Atk":"25","Sp. Def":"35","Species":"Mouse Pok\u00e9mon","Speed":"72","Total":"253","Type":["Normal"]},"Rayquaza":{"#":"384","Attack":"150","Defense":"90","FlavorText":"","HP":"105","Sp. Atk":"150","Sp. Def":"90","Species":"Sky High Pok\u00e9mon","Speed":"95","Total":"680","Type":["Dragon","Flying"]},"Rayquaza ( Mega Rayquaza )":{"#":"384","Attack":"180","Defense":"100","FlavorText":"","HP":"105","Sp. Atk":"180","Sp. Def":"100","Species":"","Speed":"115","Total":"780","Type":["Dragon","Flying"]},"Regice":{"#":"378","Attack":"50","Defense":"100","FlavorText":"","HP":"80","Sp. Atk":"100","Sp. Def":"200","Species":"Iceberg Pok\u00e9mon","Speed":"50","Total":"580","Type":["Ice"]},"Regigigas":{"#":"486","Attack":"160","Defense":"110","FlavorText":"","HP":"110","Sp. Atk":"80","Sp. Def":"110","Species":"Colossal Pok\u00e9mon","Speed":"100","Total":"670","Type":["Normal"]},"Regirock":{"#":"377","Attack":"100","Defense":"200","FlavorText":"","HP":"80","Sp. Atk":"50","Sp. Def":"100","Species":"Rock Peak Pok\u00e9mon","Speed":"50","Total":"580","Type":["Rock"]},"Registeel":{"#":"379","Attack":"75","Defense":"150","FlavorText":"","HP":"80","Sp. Atk":"75","Sp. Def":"150","Species":"Iron Pok\u00e9mon","Speed":"50","Total":"580","Type":["Steel"]},"Relicanth":{"#":"369","Attack":"90","Defense":"130","FlavorText":"A POK\u00e9MON that was once believed to have been extinct. The species has not changed its form for 100 million years. It walks on the seafloor using its pectoral fins.","HP":"100","Sp. Atk":"45","Sp. Def":"65","Species":"Longevity Pok\u00e9mon","Speed":"55","Total":"485","Type":["Water","Rock"]},"Remoraid":{"#":"223","Attack":"65","Defense":"35","FlavorText":"","HP":"35","Sp. Atk":"65","Sp. Def":"35","Species":"Jet Pok\u00e9mon","Speed":"65","Total":"300","Type":["Water"]},"Reshiram":{"#":"643","Attack":"120","Defense":"100","FlavorText":"","HP":"100","Sp. Atk":"150","Sp. Def":"120","Species":"Vast White Pok\u00e9mon","Speed":"90","Total":"680","Type":["Dragon","Fire"]},"Reuniclus":{"#":"579","Attack":"65","Defense":"75","FlavorText":"When Reuniclus shake hands, a network forms between their brains, increasing their psychic power.","HP":"110","Sp. Atk":"125","Sp. Def":"85","Species":"Multiplying Pok\u00e9mon","Speed":"30","Total":"490","Type":["Psychic"]},"Rhydon":{"#":"112","Attack":"130","Defense":"120","FlavorText":"","HP":"105","Sp. Atk":"45","Sp. Def":"45","Species":"Drill Pok\u00e9mon","Speed":"40","Total":"485","Type":["Ground","Rock"]},"Rhyhorn":{"#":"111","Attack":"85","Defense":"95","FlavorText":"","HP":"80","Sp. Atk":"30","Sp. Def":"30","Species":"Spikes Pok\u00e9mon","Speed":"25","Total":"345","Type":["Ground","Rock"]},"Rhyperior":{"#":"464","Attack":"140","Defense":"130","FlavorText":"It can launch a rock held in its hand like a missile by tightening then expanding muscles instantly.","HP":"115","Sp. Atk":"55","Sp. Def":"55","Species":"Drill Pok\u00e9mon","Speed":"40","Total":"535","Type":["Ground","Rock"]},"Riolu":{"#":"447","Attack":"70","Defense":"40","FlavorText":"","HP":"40","Sp. Atk":"35","Sp. Def":"40","Species":"Emanation Pok\u00e9mon","Speed":"60","Total":"285","Type":["Fighting"]},"Roggenrola":{"#":"524","Attack":"75","Defense":"85","FlavorText":"","HP":"55","Sp. Atk":"25","Sp. Def":"25","Species":"Mantle Pok\u00e9mon","Speed":"15","Total":"280","Type":["Rock"]},"Roselia":{"#":"315","Attack":"60","Defense":"45","FlavorText":"","HP":"50","Sp. Atk":"100","Sp. Def":"80","Species":"Thorn Pok\u00e9mon","Speed":"65","Total":"400","Type":["Grass","Poison"]},"Roserade":{"#":"407","Attack":"70","Defense":"65","FlavorText":"","HP":"60","Sp. Atk":"125","Sp. Def":"105","Species":"Bouquet Pok\u00e9mon","Speed":"90","Total":"515","Type":["Grass","Poison"]},"Rotom":{"#":"479","Attack":"50","Defense":"77","FlavorText":"","HP":"50","Sp. Atk":"95","Sp. Def":"77","Species":"Plasma Pok\u00e9mon","Speed":"91","Total":"440","Type":["Electric","Ghost"]},"Rotom ( Fan Rotom )":{"#":"479","Attack":"65","Defense":"107","FlavorText":"","HP":"50","Sp. Atk":"105","Sp. Def":"107","Species":"","Speed":"86","Total":"520","Type":["Electric","Flying"]},"Rotom ( Frost Rotom )":{"#":"479","Attack":"65","Defense":"107","FlavorText":"","HP":"50","Sp. Atk":"105","Sp. Def":"107","Species":"","Speed":"86","Total":"520","Type":["Electric","Ice"]},"Rotom ( Heat Rotom )":{"#":"479","Attack":"65","Defense":"107","FlavorText":"","HP":"50","Sp. Atk":"105","Sp. Def":"107","Species":"","Speed":"86","Total":"520","Type":["Electric","Fire"]},"Rotom ( Mow Rotom )":{"#":"479","Attack":"65","Defense":"107","FlavorText":"","HP":"50","Sp. Atk":"105","Sp. Def":"107","Species":"","Speed":"86","Total":"520","Type":["Electric","Grass"]},"Rotom ( Wash Rotom )":{"#":"479","Attack":"65","Defense":"107","FlavorText":"","HP":"50","Sp. Atk":"105","Sp. Def":"107","Species":"","Speed":"86","Total":"520","Type":["Electric","Water"]},"Rufflet":{"#":"627","Attack":"83","Defense":"50","FlavorText":"","HP":"70","Sp. Atk":"37","Sp. Def":"50","Species":"Eaglet Pok\u00e9mon","Speed":"60","Total":"350","Type":["Normal","Flying"]},"Sableye":{"#":"302","Attack":"75","Defense":"75","FlavorText":"","HP":"50","Sp. Atk":"65","Sp. Def":"65","Species":"Darkness Pok\u00e9mon","Speed":"50","Total":"380","Type":["Dark","Ghost"]},"Sableye ( Mega Sableye )":{"#":"302","Attack":"85","Defense":"125","FlavorText":"","HP":"50","Sp. Atk":"85","Sp. Def":"115","Species":"","Speed":"20","Total":"480","Type":["Dark","Ghost"]},"Salamence":{"#":"373","Attack":"135","Defense":"80","FlavorText":"","HP":"95","Sp. Atk":"110","Sp. Def":"80","Species":"Dragon Pok\u00e9mon","Speed":"100","Total":"600","Type":["Dragon","Flying"]},"Salamence ( Mega Salamence )":{"#":"373","Attack":"145","Defense":"130","FlavorText":"","HP":"95","Sp. Atk":"120","Sp. Def":"90","Species":"","Speed":"120","Total":"700","Type":["Dragon","Flying"]},"Samurott":{"#":"503","Attack":"100","Defense":"85","FlavorText":"","HP":"95","Sp. Atk":"108","Sp. Def":"70","Species":"Formidable Pok\u00e9mon","Speed":"70","Total":"528","Type":["Water"]},"Sandile":{"#":"551","Attack":"72","Defense":"35","FlavorText":"They live buried in the sands of the desert. The sun-warmed sands prevent their body temperature from dropping.","HP":"50","Sp. Atk":"35","Sp. Def":"35","Species":"Desert Croc Pok\u00e9mon","Speed":"65","Total":"292","Type":["Ground","Dark"]},"Sandshrew":{"#":"027","Attack":"75","Defense":"85","FlavorText":"","HP":"50","Sp. Atk":"20","Sp. Def":"30","Species":"Mouse Pok\u00e9mon","Speed":"40","Total":"300","Type":["Ground"]},"Sandslash":{"#":"028","Attack":"100","Defense":"110","FlavorText":"","HP":"75","Sp. Atk":"45","Sp. Def":"55","Species":"Mouse Pok\u00e9mon","Speed":"65","Total":"450","Type":["Ground"]},"Sawk":{"#":"539","Attack":"125","Defense":"75","FlavorText":"Tying their belts gets them pumped and makes their punches more destructive. Disturbing their training angers them.","HP":"75","Sp. Atk":"30","Sp. Def":"75","Species":"Karate Pok\u00e9mon","Speed":"85","Total":"465","Type":["Fighting"]},"Sawsbuck":{"#":"586","Attack":"100","Defense":"70","FlavorText":"","HP":"80","Sp. Atk":"60","Sp. Def":"70","Species":"Season Pok\u00e9mon","Speed":"95","Total":"475","Type":["Normal","Grass"]},"Scatterbug":{"#":"664","Attack":"35","Defense":"40","FlavorText":"","HP":"38","Sp. Atk":"27","Sp. Def":"25","Species":"Scatterdust Pok\u00e9mon","Speed":"35","Total":"200","Type":["Bug"]},"Sceptile":{"#":"254","Attack":"85","Defense":"65","FlavorText":"","HP":"70","Sp. Atk":"105","Sp. Def":"85","Species":"Forest Pok\u00e9mon","Speed":"120","Total":"530","Type":["Grass"]},"Sceptile ( Mega Sceptile )":{"#":"254","Attack":"110","Defense":"75","FlavorText":"","HP":"70","Sp. Atk":"145","Sp. Def":"85","Species":"","Speed":"145","Total":"630","Type":["Grass","Dragon"]},"Scizor":{"#":"212","Attack":"130","Defense":"100","FlavorText":"","HP":"70","Sp. Atk":"55","Sp. Def":"80","Species":"Pincer Pok\u00e9mon","Speed":"65","Total":"500","Type":["Bug","Steel"]},"Scizor ( Mega Scizor )":{"#":"212","Attack":"150","Defense":"140","FlavorText":"","HP":"70","Sp. Atk":"65","Sp. Def":"100","Species":"","Speed":"75","Total":"600","Type":["Bug","Steel"]},"Scolipede":{"#":"545","Attack":"100","Defense":"89","FlavorText":"With quick movements, it chases down its foes, attacking relentlessly with its horns until it prevails.","HP":"60","Sp. Atk":"55","Sp. Def":"69","Species":"Megapede Pok\u00e9mon","Speed":"112","Total":"485","Type":["Bug","Poison"]},"Scrafty":{"#":"560","Attack":"90","Defense":"115","FlavorText":"It can smash concrete blocks with its kicking attacks. The one with the biggest crest is the group leader.","HP":"65","Sp. Atk":"45","Sp. Def":"115","Species":"Hoodlum Pok\u00e9mon","Speed":"58","Total":"488","Type":["Dark","Fighting"]},"Scraggy":{"#":"559","Attack":"75","Defense":"70","FlavorText":"Proud of its sturdy skull, it suddenly headbutts everything, but its weight makes it unstable, too.","HP":"50","Sp. Atk":"35","Sp. Def":"70","Species":"Shedding Pok\u00e9mon","Speed":"48","Total":"348","Type":["Dark","Fighting"]},"Scyther":{"#":"123","Attack":"110","Defense":"80","FlavorText":"","HP":"70","Sp. Atk":"55","Sp. Def":"80","Species":"Mantis Pok\u00e9mon","Speed":"105","Total":"500","Type":["Bug","Flying"]},"Seadra":{"#":"117","Attack":"65","Defense":"95","FlavorText":"","HP":"55","Sp. Atk":"95","Sp. Def":"45","Species":"Dragon Pok\u00e9mon","Speed":"85","Total":"440","Type":["Water"]},"Seaking":{"#":"119","Attack":"92","Defense":"65","FlavorText":"","HP":"80","Sp. Atk":"65","Sp. Def":"80","Species":"Goldfish Pok\u00e9mon","Speed":"68","Total":"450","Type":["Water"]},"Sealeo":{"#":"364","Attack":"60","Defense":"70","FlavorText":"SEALEO live in herds on ice floes. Using its powerful flippers, it shatters ice. It dives into the sea to hunt prey five times a day.","HP":"90","Sp. Atk":"75","Sp. Def":"70","Species":"Ball Roll Pok\u00e9mon","Speed":"45","Total":"410","Type":["Ice","Water"]},"Seedot":{"#":"273","Attack":"40","Defense":"50","FlavorText":"","HP":"40","Sp. Atk":"30","Sp. Def":"30","Species":"Acorn Pok\u00e9mon","Speed":"30","Total":"220","Type":["Grass"]},"Seel":{"#":"086","Attack":"45","Defense":"55","FlavorText":"","HP":"65","Sp. Atk":"45","Sp. Def":"70","Species":"Sea Lion Pok\u00e9mon","Speed":"45","Total":"325","Type":["Water"]},"Seismitoad":{"#":"537","Attack":"95","Defense":"75","FlavorText":"","HP":"105","Sp. Atk":"85","Sp. Def":"75","Species":"Vibration Pok\u00e9mon","Speed":"74","Total":"509","Type":["Water","Ground"]},"Sentret":{"#":"161","Attack":"46","Defense":"34","FlavorText":"They take turns standing guard when it is time to sleep. The sentry awakens the others if it senses danger. If one becomes separated, it turns sleepless with fear.","HP":"35","Sp. Atk":"35","Sp. Def":"45","Species":"Scout Pok\u00e9mon","Speed":"20","Total":"215","Type":["Normal"]},"Serperior":{"#":"497","Attack":"75","Defense":"95","FlavorText":"","HP":"75","Sp. Atk":"75","Sp. Def":"95","Species":"Regal Pok\u00e9mon","Speed":"113","Total":"528","Type":["Grass"]},"Servine":{"#":"496","Attack":"60","Defense":"75","FlavorText":"","HP":"60","Sp. Atk":"60","Sp. Def":"75","Species":"Grass Snake Pok\u00e9mon","Speed":"83","Total":"413","Type":["Grass"]},"Seviper":{"#":"336","Attack":"100","Defense":"60","FlavorText":"SEVIPER and ZANGOOSE are eternal rivals. It counters a ZANGOOSE\u2019s dazzling agility with its swordlike tail, which also oozes a horrible poison.","HP":"73","Sp. Atk":"100","Sp. Def":"60","Species":"Fang Snake Pok\u00e9mon","Speed":"65","Total":"458","Type":["Poison"]},"Sewaddle":{"#":"540","Attack":"53","Defense":"70","FlavorText":"","HP":"45","Sp. Atk":"40","Sp. Def":"60","Species":"Sewing Pok\u00e9mon","Speed":"42","Total":"310","Type":["Bug","Grass"]},"Sharpedo":{"#":"319","Attack":"120","Defense":"40","FlavorText":"","HP":"70","Sp. Atk":"95","Sp. Def":"40","Species":"Brutal Pok\u00e9mon","Speed":"95","Total":"460","Type":["Water","Dark"]},"Sharpedo ( Mega Sharpedo )":{"#":"319","Attack":"140","Defense":"70","FlavorText":"","HP":"70","Sp. Atk":"110","Sp. Def":"65","Species":"","Speed":"105","Total":"560","Type":["Water","Dark"]},"Shaymin ( Land Forme )":{"#":"492","Attack":"100","Defense":"100","FlavorText":"","HP":"100","Sp. Atk":"100","Sp. Def":"100","Species":"","Speed":"100","Total":"600","Type":["Grass"]},"Shaymin ( Sky Forme )":{"#":"492","Attack":"103","Defense":"75","FlavorText":"","HP":"100","Sp. Atk":"120","Sp. Def":"75","Species":"","Speed":"127","Total":"600","Type":["Grass","Flying"]},"Shedinja":{"#":"292","Attack":"90","Defense":"45","FlavorText":"","HP":"1","Sp. Atk":"30","Sp. Def":"30","Species":"Shed Pok\u00e9mon","Speed":"40","Total":"236","Type":["Bug","Ghost"]},"Shelgon":{"#":"372","Attack":"95","Defense":"100","FlavorText":"","HP":"65","Sp. Atk":"60","Sp. Def":"50","Species":"Endurance Pok\u00e9mon","Speed":"50","Total":"420","Type":["Dragon"]},"Shellder":{"#":"090","Attack":"65","Defense":"100","FlavorText":"","HP":"30","Sp. Atk":"45","Sp. Def":"25","Species":"Bivalve Pok\u00e9mon","Speed":"40","Total":"305","Type":["Water"]},"Shellos":{"#":"422","Attack":"48","Defense":"48","FlavorText":"","HP":"76","Sp. Atk":"57","Sp. Def":"62","Species":"Sea Slug Pok\u00e9mon","Speed":"34","Total":"325","Type":["Water"]},"Shelmet":{"#":"616","Attack":"40","Defense":"85","FlavorText":"It evolves when bathed in an electric-like energy along with Karrablast. The reason is still unknown.","HP":"50","Sp. Atk":"40","Sp. Def":"65","Species":"Snail Pok\u00e9mon","Speed":"25","Total":"305","Type":["Bug"]},"Shieldon":{"#":"410","Attack":"42","Defense":"118","FlavorText":"","HP":"30","Sp. Atk":"42","Sp. Def":"88","Species":"Shield Pok\u00e9mon","Speed":"30","Total":"350","Type":["Rock","Steel"]},"Shiftry":{"#":"275","Attack":"100","Defense":"60","FlavorText":"","HP":"90","Sp. Atk":"90","Sp. Def":"60","Species":"Wicked Pok\u00e9mon","Speed":"80","Total":"480","Type":["Grass","Dark"]},"Shinx":{"#":"403","Attack":"65","Defense":"34","FlavorText":"","HP":"45","Sp. Atk":"40","Sp. Def":"34","Species":"Flash Pok\u00e9mon","Speed":"45","Total":"263","Type":["Electric"]},"Shroomish":{"#":"285","Attack":"40","Defense":"60","FlavorText":"","HP":"60","Sp. Atk":"40","Sp. Def":"60","Species":"Mushroom Pok\u00e9mon","Speed":"35","Total":"295","Type":["Grass"]},"Shuckle":{"#":"213","Attack":"10","Defense":"230","FlavorText":"","HP":"20","Sp. Atk":"10","Sp. Def":"230","Species":"Mold Pok\u00e9mon","Speed":"5","Total":"505","Type":["Bug","Rock"]},"Shuppet":{"#":"353","Attack":"75","Defense":"35","FlavorText":"","HP":"44","Sp. Atk":"63","Sp. Def":"33","Species":"Puppet Pok\u00e9mon","Speed":"45","Total":"295","Type":["Ghost"]},"Sigilyph":{"#":"561","Attack":"58","Defense":"80","FlavorText":"The guardians of an ancient city, they always fly the same route while keeping watch for invaders.","HP":"72","Sp. Atk":"103","Sp. Def":"80","Species":"Avianoid Pok\u00e9mon","Speed":"97","Total":"490","Type":["Psychic","Flying"]},"Silcoon":{"#":"266","Attack":"35","Defense":"55","FlavorText":"","HP":"50","Sp. Atk":"25","Sp. Def":"25","Species":"Cocoon Pok\u00e9mon","Speed":"15","Total":"205","Type":["Bug"]},"Simipour":{"#":"516","Attack":"98","Defense":"63","FlavorText":"","HP":"75","Sp. Atk":"98","Sp. Def":"63","Species":"Geyser Pok\u00e9mon","Speed":"101","Total":"498","Type":["Water"]},"Simisage":{"#":"512","Attack":"98","Defense":"63","FlavorText":"","HP":"75","Sp. Atk":"98","Sp. Def":"63","Species":"Thorn Monkey Pok\u00e9mon","Speed":"101","Total":"498","Type":["Grass"]},"Simisear":{"#":"514","Attack":"98","Defense":"63","FlavorText":"","HP":"75","Sp. Atk":"98","Sp. Def":"63","Species":"Ember Pok\u00e9mon","Speed":"101","Total":"498","Type":["Fire"]},"Skarmory":{"#":"227","Attack":"80","Defense":"140","FlavorText":"","HP":"65","Sp. Atk":"40","Sp. Def":"70","Species":"Armor Bird Pok\u00e9mon","Speed":"70","Total":"465","Type":["Steel","Flying"]},"Skiddo":{"#":"672","Attack":"65","Defense":"48","FlavorText":"","HP":"66","Sp. Atk":"62","Sp. Def":"57","Species":"Mount Pok\u00e9mon","Speed":"52","Total":"350","Type":["Grass"]},"Skiploom":{"#":"188","Attack":"45","Defense":"50","FlavorText":"It blossoms when the temperature rises above 64 degrees F. Because its flower\u2019s blooming changes with the temperature, it is sometimes used as a thermometer.","HP":"55","Sp. Atk":"45","Sp. Def":"65","Species":"Cottonweed Pok\u00e9mon","Speed":"80","Total":"340","Type":["Grass","Flying"]},"Skitty":{"#":"300","Attack":"45","Defense":"45","FlavorText":"","HP":"50","Sp. Atk":"35","Sp. Def":"35","Species":"Kitten Pok\u00e9mon","Speed":"50","Total":"260","Type":["Normal"]},"Skorupi":{"#":"451","Attack":"50","Defense":"90","FlavorText":"","HP":"40","Sp. Atk":"30","Sp. Def":"55","Species":"Scorpion Pok\u00e9mon","Speed":"65","Total":"330","Type":["Poison","Bug"]},"Skrelp":{"#":"690","Attack":"60","Defense":"60","FlavorText":"","HP":"50","Sp. Atk":"60","Sp. Def":"60","Species":"Mock Kelp Pok\u00e9mon","Speed":"30","Total":"320","Type":["Poison","Water"]},"Skuntank":{"#":"435","Attack":"93","Defense":"67","FlavorText":"","HP":"103","Sp. Atk":"71","Sp. Def":"61","Species":"Skunk Pok\u00e9mon","Speed":"84","Total":"479","Type":["Poison","Dark"]},"Slaking":{"#":"289","Attack":"160","Defense":"100","FlavorText":"","HP":"150","Sp. Atk":"95","Sp. Def":"65","Species":"Lazy Pok\u00e9mon","Speed":"100","Total":"670","Type":["Normal"]},"Slakoth":{"#":"287","Attack":"60","Defense":"60","FlavorText":"","HP":"60","Sp. Atk":"35","Sp. Def":"35","Species":"Slacker Pok\u00e9mon","Speed":"30","Total":"280","Type":["Normal"]},"Sliggoo":{"#":"705","Attack":"75","Defense":"53","FlavorText":"","HP":"68","Sp. Atk":"83","Sp. Def":"113","Species":"Soft Tissue Pok\u00e9mon","Speed":"60","Total":"452","Type":["Dragon"]},"Slowbro":{"#":"080","Attack":"75","Defense":"110","FlavorText":"","HP":"95","Sp. Atk":"100","Sp. Def":"80","Species":"Hermit Crab Pok\u00e9mon","Speed":"30","Total":"490","Type":["Water","Psychic"]},"Slowbro ( Mega Slowbro )":{"#":"080","Attack":"75","Defense":"180","FlavorText":"","HP":"95","Sp. Atk":"130","Sp. Def":"80","Species":"","Speed":"30","Total":"590","Type":["Water","Psychic"]},"Slowking":{"#":"199","Attack":"75","Defense":"80","FlavorText":"It undertakes research every day to solve the mysteries of the world. However, it apparently forgets everything if the SHELLDER on its head comes off.","HP":"95","Sp. Atk":"100","Sp. Def":"110","Species":"Royal Pok\u00e9mon","Speed":"30","Total":"490","Type":["Water","Psychic"]},"Slowpoke":{"#":"079","Attack":"65","Defense":"65","FlavorText":"","HP":"90","Sp. Atk":"40","Sp. Def":"40","Species":"Dopey Pok\u00e9mon","Speed":"15","Total":"315","Type":["Water","Psychic"]},"Slugma":{"#":"218","Attack":"40","Defense":"40","FlavorText":"","HP":"40","Sp. Atk":"70","Sp. Def":"40","Species":"Lava Pok\u00e9mon","Speed":"20","Total":"250","Type":["Fire"]},"Slurpuff":{"#":"685","Attack":"80","Defense":"86","FlavorText":"","HP":"82","Sp. Atk":"85","Sp. Def":"75","Species":"Meringue Pok\u00e9mon","Speed":"72","Total":"480","Type":["Fairy"]},"Smeargle":{"#":"235","Attack":"20","Defense":"35","FlavorText":"A SMEARGLE marks its territory using a fluid that leaks out from the tip of its tail. About 5,000 different marks left by this POK\u00e9MON have been found.","HP":"55","Sp. Atk":"20","Sp. Def":"45","Species":"Painter Pok\u00e9mon","Speed":"75","Total":"250","Type":["Normal"]},"Smoochum":{"#":"238","Attack":"30","Defense":"15","FlavorText":"It actively runs about, but also falls often. Whenever it falls, it will check its reflection on a lake\u2019s surface to make sure its face hasn\u2019t become dirty.","HP":"45","Sp. Atk":"85","Sp. Def":"65","Species":"Kiss Pok\u00e9mon","Speed":"65","Total":"305","Type":["Ice","Psychic"]},"Sneasel":{"#":"215","Attack":"95","Defense":"55","FlavorText":"","HP":"55","Sp. Atk":"35","Sp. Def":"75","Species":"Sharp Claw Pok\u00e9mon","Speed":"115","Total":"430","Type":["Dark","Ice"]},"Snivy":{"#":"495","Attack":"45","Defense":"55","FlavorText":"","HP":"45","Sp. Atk":"45","Sp. Def":"55","Species":"Grass Snake Pok\u00e9mon","Speed":"63","Total":"308","Type":["Grass"]},"Snorlax":{"#":"143","Attack":"110","Defense":"65","FlavorText":"","HP":"160","Sp. Atk":"65","Sp. Def":"110","Species":"Sleeping Pok\u00e9mon","Speed":"30","Total":"540","Type":["Normal"]},"Snorunt":{"#":"361","Attack":"50","Defense":"50","FlavorText":"They tend to move about in groups of around five SNORUNT. In snowy regions, it is said that when they are seen late at night, snowfall will arrive by morning.","HP":"50","Sp. Atk":"50","Sp. Def":"50","Species":"Snow Hat Pok\u00e9mon","Speed":"50","Total":"300","Type":["Ice"]},"Snover":{"#":"459","Attack":"62","Defense":"50","FlavorText":"","HP":"60","Sp. Atk":"62","Sp. Def":"60","Species":"Frost Tree Pok\u00e9mon","Speed":"40","Total":"334","Type":["Grass","Ice"]},"Snubbull":{"#":"209","Attack":"80","Defense":"50","FlavorText":"By baring its fangs and making a scary face, it sends smaller POK\u00e9MON scurrying in terror. The SNUBBULL does seem a little sad at making its foes flee.","HP":"60","Sp. Atk":"40","Sp. Def":"40","Species":"Fairy Pok\u00e9mon","Speed":"30","Total":"300","Type":["Fairy"]},"Solosis":{"#":"577","Attack":"30","Defense":"40","FlavorText":"They drive away attackers by unleashing psychic power. They can use telepathy to talk with others.","HP":"45","Sp. Atk":"105","Sp. Def":"50","Species":"Cell Pok\u00e9mon","Speed":"20","Total":"290","Type":["Psychic"]},"Solrock":{"#":"338","Attack":"95","Defense":"85","FlavorText":"","HP":"70","Sp. Atk":"55","Sp. Def":"65","Species":"Meteorite Pok\u00e9mon","Speed":"70","Total":"440","Type":["Rock","Psychic"]},"Spearow":{"#":"021","Attack":"60","Defense":"30","FlavorText":"To protect its territory, it flies around ceaselessly, making high-pitched cries.","HP":"40","Sp. Atk":"31","Sp. Def":"31","Species":"Tiny Bird Pok\u00e9mon","Speed":"70","Total":"262","Type":["Normal","Flying"]},"Spewpa":{"#":"665","Attack":"22","Defense":"60","FlavorText":"","HP":"45","Sp. Atk":"27","Sp. Def":"30","Species":"Scatterdust Pok\u00e9mon","Speed":"29","Total":"213","Type":["Bug"]},"Spheal":{"#":"363","Attack":"40","Defense":"50","FlavorText":"It is completely covered with plushy fur. As a result, it never feels the cold even when it is rolling about on ice floes or diving in the sea.","HP":"70","Sp. Atk":"55","Sp. Def":"50","Species":"Clap Pok\u00e9mon","Speed":"25","Total":"290","Type":["Ice","Water"]},"Spinarak":{"#":"167","Attack":"60","Defense":"40","FlavorText":"The web it spins can be considered its second nervous system. It is said that a SPINARAK determines its prey by the tiny vibrations it feels through the web.","HP":"40","Sp. Atk":"40","Sp. Def":"40","Species":"String Spit Pok\u00e9mon","Speed":"30","Total":"250","Type":["Bug","Poison"]},"Spinda":{"#":"327","Attack":"60","Defense":"60","FlavorText":"It is distinguished by a pattern of spots that is always different. Its unsteady, tottering walk has the effect of fouling its foe\u2019s aim.","HP":"60","Sp. Atk":"60","Sp. Def":"60","Species":"Spot Panda Pok\u00e9mon","Speed":"60","Total":"360","Type":["Normal"]},"Spiritomb":{"#":"442","Attack":"92","Defense":"108","FlavorText":"","HP":"50","Sp. Atk":"92","Sp. Def":"108","Species":"Forbidden Pok\u00e9mon","Speed":"35","Total":"485","Type":["Ghost","Dark"]},"Spoink":{"#":"325","Attack":"25","Defense":"35","FlavorText":"","HP":"60","Sp. Atk":"70","Sp. Def":"80","Species":"Bounce Pok\u00e9mon","Speed":"60","Total":"330","Type":["Psychic"]},"Spritzee":{"#":"682","Attack":"52","Defense":"60","FlavorText":"","HP":"78","Sp. Atk":"63","Sp. Def":"65","Species":"Perfume Pok\u00e9mon","Speed":"23","Total":"341","Type":["Fairy"]},"Squirtle":{"#":"007","Attack":"48","Defense":"65","FlavorText":"When it feels threatened, it draws its legs inside its shell and sprays water from its mouth.","HP":"44","Sp. Atk":"50","Sp. Def":"64","Species":"Tiny Turtle Pok\u00e9mon","Speed":"43","Total":"314","Type":["Water"]},"Stantler":{"#":"234","Attack":"95","Defense":"62","FlavorText":"","HP":"73","Sp. Atk":"85","Sp. Def":"65","Species":"Big Horn Pok\u00e9mon","Speed":"85","Total":"465","Type":["Normal"]},"Staraptor":{"#":"398","Attack":"120","Defense":"70","FlavorText":"","HP":"85","Sp. Atk":"50","Sp. Def":"60","Species":"Predator Pok\u00e9mon","Speed":"100","Total":"485","Type":["Normal","Flying"]},"Staravia":{"#":"397","Attack":"75","Defense":"50","FlavorText":"","HP":"55","Sp. Atk":"40","Sp. Def":"40","Species":"Starling Pok\u00e9mon","Speed":"80","Total":"340","Type":["Normal","Flying"]},"Starly":{"#":"396","Attack":"55","Defense":"30","FlavorText":"","HP":"40","Sp. Atk":"30","Sp. Def":"30","Species":"Starling Pok\u00e9mon","Speed":"60","Total":"245","Type":["Normal","Flying"]},"Starmie":{"#":"121","Attack":"75","Defense":"85","FlavorText":"","HP":"60","Sp. Atk":"100","Sp. Def":"85","Species":"Mysterious Pok\u00e9mon","Speed":"115","Total":"520","Type":["Water","Psychic"]},"Staryu":{"#":"120","Attack":"45","Defense":"55","FlavorText":"","HP":"30","Sp. Atk":"70","Sp. Def":"55","Species":"Star Shape Pok\u00e9mon","Speed":"85","Total":"340","Type":["Water"]},"Steelix":{"#":"208","Attack":"85","Defense":"200","FlavorText":"","HP":"75","Sp. Atk":"55","Sp. Def":"65","Species":"Iron Snake Pok\u00e9mon","Speed":"30","Total":"510","Type":["Steel","Ground"]},"Steelix ( Mega Steelix )":{"#":"208","Attack":"125","Defense":"230","FlavorText":"","HP":"75","Sp. Atk":"55","Sp. Def":"95","Species":"","Speed":"30","Total":"610","Type":["Steel","Ground"]},"Stoutland":{"#":"508","Attack":"110","Defense":"90","FlavorText":"","HP":"85","Sp. Atk":"45","Sp. Def":"90","Species":"Big-Hearted Pok\u00e9mon","Speed":"80","Total":"500","Type":["Normal"]},"Stunfisk":{"#":"618","Attack":"66","Defense":"84","FlavorText":"It conceals itself in the mud of the seashore. Then it waits. When prey touch it, it delivers a jolt of electricity.","HP":"109","Sp. Atk":"81","Sp. Def":"99","Species":"Trap Pok\u00e9mon","Speed":"32","Total":"471","Type":["Ground","Electric"]},"Stunky":{"#":"434","Attack":"63","Defense":"47","FlavorText":"","HP":"63","Sp. Atk":"41","Sp. Def":"41","Species":"Skunk Pok\u00e9mon","Speed":"74","Total":"329","Type":["Poison","Dark"]},"Sudowoodo":{"#":"185","Attack":"100","Defense":"115","FlavorText":"","HP":"70","Sp. Atk":"30","Sp. Def":"65","Species":"Imitation Pok\u00e9mon","Speed":"30","Total":"410","Type":["Rock"]},"Suicune":{"#":"245","Attack":"75","Defense":"115","FlavorText":"","HP":"100","Sp. Atk":"90","Sp. Def":"115","Species":"Aurora Pok\u00e9mon","Speed":"85","Total":"580","Type":["Water"]},"Sunflora":{"#":"192","Attack":"75","Defense":"55","FlavorText":"SUNFLORA convert solar energy into nutrition. They are highly active in the warm daytime but suddenly stop moving as soon as the sun sets.","HP":"75","Sp. Atk":"105","Sp. Def":"85","Species":"Sun Pok\u00e9mon","Speed":"30","Total":"425","Type":["Grass"]},"Sunkern":{"#":"191","Attack":"30","Defense":"30","FlavorText":"SUNKERN try to minimize movement to conserve the nutrients they have stored in their bodies for evolution. They will not eat, subsisting only on morning dew.","HP":"30","Sp. Atk":"30","Sp. Def":"30","Species":"Seed Pok\u00e9mon","Speed":"30","Total":"180","Type":["Grass"]},"Surskit":{"#":"283","Attack":"30","Defense":"32","FlavorText":"","HP":"40","Sp. Atk":"50","Sp. Def":"52","Species":"Pond Skater Pok\u00e9mon","Speed":"65","Total":"269","Type":["Bug","Water"]},"Swablu":{"#":"333","Attack":"40","Defense":"60","FlavorText":"","HP":"45","Sp. Atk":"40","Sp. Def":"75","Species":"Cotton Bird Pok\u00e9mon","Speed":"50","Total":"310","Type":["Normal","Flying"]},"Swadloon":{"#":"541","Attack":"63","Defense":"90","FlavorText":"","HP":"55","Sp. Atk":"50","Sp. Def":"80","Species":"Leaf-Wrapped Pok\u00e9mon","Speed":"42","Total":"380","Type":["Bug","Grass"]},"Swalot":{"#":"317","Attack":"73","Defense":"83","FlavorText":"Its powerful stomach acid is capable of digesting almost anything. The one thing in the whole world a SWALOT can\u2019t digest is its own stomach.","HP":"100","Sp. Atk":"73","Sp. Def":"83","Species":"Poison Bag Pok\u00e9mon","Speed":"55","Total":"467","Type":["Poison"]},"Swampert":{"#":"260","Attack":"110","Defense":"90","FlavorText":"","HP":"100","Sp. Atk":"85","Sp. Def":"90","Species":"Mud Fish Pok\u00e9mon","Speed":"60","Total":"535","Type":["Water","Ground"]},"Swampert ( Mega Swampert )":{"#":"260","Attack":"150","Defense":"110","FlavorText":"","HP":"100","Sp. Atk":"95","Sp. Def":"110","Species":"","Speed":"70","Total":"635","Type":["Water","Ground"]},"Swanna":{"#":"581","Attack":"87","Defense":"63","FlavorText":"Swanna start to dance at dusk. The one dancing in the middle is the leader of the flock.","HP":"75","Sp. Atk":"87","Sp. Def":"63","Species":"White Bird Pok\u00e9mon","Speed":"98","Total":"473","Type":["Water","Flying"]},"Swellow":{"#":"277","Attack":"85","Defense":"60","FlavorText":"","HP":"60","Sp. Atk":"50","Sp. Def":"50","Species":"Swallow Pok\u00e9mon","Speed":"125","Total":"430","Type":["Normal","Flying"]},"Swinub":{"#":"220","Attack":"50","Defense":"40","FlavorText":"","HP":"50","Sp. Atk":"30","Sp. Def":"30","Species":"Pig Pok\u00e9mon","Speed":"50","Total":"250","Type":["Ice","Ground"]},"Swirlix":{"#":"684","Attack":"48","Defense":"66","FlavorText":"","HP":"62","Sp. Atk":"59","Sp. Def":"57","Species":"Cotton Candy Pok\u00e9mon","Speed":"49","Total":"341","Type":["Fairy"]},"Swoobat":{"#":"528","Attack":"57","Defense":"55","FlavorText":"Anyone who comes into contact with the ultrasonic waves emitted by a courting male experiences a positive mood shift.","HP":"67","Sp. Atk":"77","Sp. Def":"55","Species":"Courting Pok\u00e9mon","Speed":"114","Total":"425","Type":["Psychic","Flying"]},"Sylveon":{"#":"700","Attack":"65","Defense":"65","FlavorText":"","HP":"95","Sp. Atk":"110","Sp. Def":"130","Species":"Intertwining Pok\u00e9mon","Speed":"60","Total":"525","Type":["Fairy"]},"Taillow":{"#":"276","Attack":"55","Defense":"30","FlavorText":"","HP":"40","Sp. Atk":"30","Sp. Def":"30","Species":"TinySwallow Pok\u00e9mon","Speed":"85","Total":"270","Type":["Normal","Flying"]},"Talonflame":{"#":"663","Attack":"81","Defense":"71","FlavorText":"","HP":"78","Sp. Atk":"74","Sp. Def":"69","Species":"Scorching Pok\u00e9mon","Speed":"126","Total":"499","Type":["Fire","Flying"]},"Tangela":{"#":"114","Attack":"55","Defense":"115","FlavorText":"","HP":"65","Sp. Atk":"100","Sp. Def":"40","Species":"Vine Pok\u00e9mon","Speed":"60","Total":"435","Type":["Grass"]},"Tangrowth":{"#":"465","Attack":"100","Defense":"125","FlavorText":"Its vines grow so profusely that, in the warm season, you can\u2019t even see its eyes.","HP":"100","Sp. Atk":"110","Sp. Def":"50","Species":"Vine Pok\u00e9mon","Speed":"50","Total":"535","Type":["Grass"]},"Tauros":{"#":"128","Attack":"100","Defense":"95","FlavorText":"","HP":"75","Sp. Atk":"40","Sp. Def":"70","Species":"Wild Bull Pok\u00e9mon","Speed":"110","Total":"490","Type":["Normal"]},"Teddiursa":{"#":"216","Attack":"80","Defense":"50","FlavorText":"It licks its palms that are sweetened by being soaked in honey. A TEDDIURSA makes its own honey by blending fruits and pollen collected by BEEDRILL.","HP":"60","Sp. Atk":"50","Sp. Def":"50","Species":"Little Bear Pok\u00e9mon","Speed":"40","Total":"330","Type":["Normal"]},"Tentacool":{"#":"072","Attack":"40","Defense":"35","FlavorText":"","HP":"40","Sp. Atk":"50","Sp. Def":"100","Species":"Jellyfish Pok\u00e9mon","Speed":"70","Total":"335","Type":["Water","Poison"]},"Tentacruel":{"#":"073","Attack":"70","Defense":"65","FlavorText":"","HP":"80","Sp. Atk":"80","Sp. Def":"120","Species":"Jellyfish Pok\u00e9mon","Speed":"100","Total":"515","Type":["Water","Poison"]},"Tepig":{"#":"498","Attack":"63","Defense":"45","FlavorText":"","HP":"65","Sp. Atk":"45","Sp. Def":"45","Species":"Fire Pig Pok\u00e9mon","Speed":"45","Total":"308","Type":["Fire"]},"Terrakion":{"#":"639","Attack":"129","Defense":"90","FlavorText":"","HP":"91","Sp. Atk":"72","Sp. Def":"90","Species":"Cavern Pok\u00e9mon","Speed":"108","Total":"580","Type":["Rock","Fighting"]},"Throh":{"#":"538","Attack":"100","Defense":"85","FlavorText":"When it encounters a foe bigger than itself, it wants to throw it. It changes belts as it gets stronger.","HP":"120","Sp. Atk":"30","Sp. Def":"85","Species":"Judo Pok\u00e9mon","Speed":"45","Total":"465","Type":["Fighting"]},"Thundurus ( Incarnate Forme )":{"#":"642","Attack":"115","Defense":"70","FlavorText":"","HP":"79","Sp. Atk":"125","Sp. Def":"80","Species":"","Speed":"111","Total":"580","Type":["Electric","Flying"]},"Thundurus ( Therian Forme )":{"#":"642","Attack":"105","Defense":"70","FlavorText":"","HP":"79","Sp. Atk":"145","Sp. Def":"80","Species":"","Speed":"101","Total":"580","Type":["Electric","Flying"]},"Timburr":{"#":"532","Attack":"80","Defense":"55","FlavorText":"Always carrying squared logs, they help out with construction. As they grow, they carry bigger logs.","HP":"75","Sp. Atk":"25","Sp. Def":"35","Species":"Muscular Pok\u00e9mon","Speed":"35","Total":"305","Type":["Fighting"]},"Tirtouga":{"#":"564","Attack":"78","Defense":"103","FlavorText":"","HP":"54","Sp. Atk":"53","Sp. Def":"45","Species":"Prototurtle Pok\u00e9mon","Speed":"22","Total":"355","Type":["Water","Rock"]},"Togekiss":{"#":"468","Attack":"50","Defense":"95","FlavorText":"","HP":"85","Sp. Atk":"120","Sp. Def":"115","Species":"Jubilee Pok\u00e9mon","Speed":"80","Total":"545","Type":["Fairy","Flying"]},"Togepi":{"#":"175","Attack":"20","Defense":"65","FlavorText":"As its energy, it uses the feelings of compassion and pleasure exuded by people and POK\u00e9MON. It stores up happy feelings in its shell, then shares them out.","HP":"35","Sp. Atk":"40","Sp. Def":"65","Species":"Spike Ball Pok\u00e9mon","Speed":"20","Total":"245","Type":["Fairy"]},"Togetic":{"#":"176","Attack":"40","Defense":"85","FlavorText":"It is said to be a POK\u00e9MON that brings good fortune. When it spots someone who is pure of heart, a TOGETIC appears and shares its happiness with that person.","HP":"55","Sp. Atk":"80","Sp. Def":"105","Species":"Happiness Pok\u00e9mon","Speed":"40","Total":"405","Type":["Fairy","Flying"]},"Torchic":{"#":"255","Attack":"60","Defense":"40","FlavorText":"","HP":"45","Sp. Atk":"70","Sp. Def":"50","Species":"Chick Pok\u00e9mon","Speed":"45","Total":"310","Type":["Fire"]},"Torkoal":{"#":"324","Attack":"85","Defense":"140","FlavorText":"","HP":"70","Sp. Atk":"85","Sp. Def":"70","Species":"Coal Pok\u00e9mon","Speed":"20","Total":"470","Type":["Fire"]},"Tornadus ( Incarnate Forme )":{"#":"641","Attack":"115","Defense":"70","FlavorText":"","HP":"79","Sp. Atk":"125","Sp. Def":"80","Species":"","Speed":"111","Total":"580","Type":["Flying"]},"Tornadus ( Therian Forme )":{"#":"641","Attack":"100","Defense":"80","FlavorText":"","HP":"79","Sp. Atk":"110","Sp. Def":"90","Species":"","Speed":"121","Total":"580","Type":["Flying"]},"Torterra":{"#":"389","Attack":"109","Defense":"105","FlavorText":"","HP":"95","Sp. Atk":"75","Sp. Def":"85","Species":"Continent Pok\u00e9mon","Speed":"56","Total":"525","Type":["Grass","Ground"]},"Totodile":{"#":"158","Attack":"65","Defense":"64","FlavorText":"","HP":"50","Sp. Atk":"44","Sp. Def":"48","Species":"Big Jaw Pok\u00e9mon","Speed":"43","Total":"314","Type":["Water"]},"Toxicroak":{"#":"454","Attack":"106","Defense":"65","FlavorText":"","HP":"83","Sp. Atk":"86","Sp. Def":"65","Species":"Toxic Mouth Pok\u00e9mon","Speed":"85","Total":"490","Type":["Poison","Fighting"]},"Tranquill":{"#":"520","Attack":"77","Defense":"62","FlavorText":"","HP":"62","Sp. Atk":"50","Sp. Def":"42","Species":"Wild Pigeon Pok\u00e9mon","Speed":"65","Total":"358","Type":["Normal","Flying"]},"Trapinch":{"#":"328","Attack":"100","Defense":"45","FlavorText":"","HP":"45","Sp. Atk":"45","Sp. Def":"45","Species":"Ant Pit Pok\u00e9mon","Speed":"10","Total":"290","Type":["Ground"]},"Treecko":{"#":"252","Attack":"45","Defense":"35","FlavorText":"","HP":"40","Sp. Atk":"65","Sp. Def":"55","Species":"Wood Gecko Pok\u00e9mon","Speed":"70","Total":"310","Type":["Grass"]},"Trevenant":{"#":"709","Attack":"110","Defense":"76","FlavorText":"","HP":"85","Sp. Atk":"65","Sp. Def":"82","Species":"Elder Tree Pok\u00e9mon","Speed":"56","Total":"474","Type":["Ghost","Grass"]},"Tropius":{"#":"357","Attack":"68","Defense":"83","FlavorText":"","HP":"99","Sp. Atk":"72","Sp. Def":"87","Species":"Fruit Pok\u00e9mon","Speed":"51","Total":"460","Type":["Grass","Flying"]},"Trubbish":{"#":"568","Attack":"50","Defense":"62","FlavorText":"Inhaling the gas they belch will make you sleep for a week. They prefer unsanitary places.","HP":"50","Sp. Atk":"40","Sp. Def":"62","Species":"Trash Bag Pok\u00e9mon","Speed":"65","Total":"329","Type":["Poison"]},"Turtwig":{"#":"387","Attack":"68","Defense":"64","FlavorText":"","HP":"55","Sp. Atk":"45","Sp. Def":"55","Species":"Tiny Leaf Pok\u00e9mon","Speed":"31","Total":"318","Type":["Grass"]},"Tympole":{"#":"535","Attack":"50","Defense":"40","FlavorText":"","HP":"50","Sp. Atk":"50","Sp. Def":"40","Species":"Tadpole Pok\u00e9mon","Speed":"64","Total":"294","Type":["Water"]},"Tynamo":{"#":"602","Attack":"55","Defense":"40","FlavorText":"","HP":"35","Sp. Atk":"45","Sp. Def":"40","Species":"EleFish Pok\u00e9mon","Speed":"60","Total":"275","Type":["Electric"]},"Typhlosion":{"#":"157","Attack":"84","Defense":"78","FlavorText":"","HP":"78","Sp. Atk":"109","Sp. Def":"85","Species":"Volcano Pok\u00e9mon","Speed":"100","Total":"534","Type":["Fire"]},"Tyranitar":{"#":"248","Attack":"134","Defense":"110","FlavorText":"","HP":"100","Sp. Atk":"95","Sp. Def":"100","Species":"Armor Pok\u00e9mon","Speed":"61","Total":"600","Type":["Rock","Dark"]},"Tyranitar ( Mega Tyranitar )":{"#":"248","Attack":"164","Defense":"150","FlavorText":"","HP":"100","Sp. Atk":"95","Sp. Def":"120","Species":"","Speed":"71","Total":"700","Type":["Rock","Dark"]},"Tyrantrum":{"#":"697","Attack":"121","Defense":"119","FlavorText":"","HP":"82","Sp. Atk":"69","Sp. Def":"59","Species":"Despot Pok\u00e9mon","Speed":"71","Total":"521","Type":["Rock","Dragon"]},"Tyrogue":{"#":"236","Attack":"35","Defense":"35","FlavorText":"","HP":"35","Sp. Atk":"35","Sp. Def":"35","Species":"Scuffle Pok\u00e9mon","Speed":"35","Total":"210","Type":["Fighting"]},"Tyrunt":{"#":"696","Attack":"89","Defense":"77","FlavorText":"","HP":"58","Sp. Atk":"45","Sp. Def":"45","Species":"Royal Heir Pok\u00e9mon","Speed":"48","Total":"362","Type":["Rock","Dragon"]},"Umbreon":{"#":"197","Attack":"65","Defense":"110","FlavorText":"","HP":"95","Sp. Atk":"60","Sp. Def":"130","Species":"Moonlight Pok\u00e9mon","Speed":"65","Total":"525","Type":["Dark"]},"Unfezant":{"#":"521","Attack":"115","Defense":"80","FlavorText":"","HP":"80","Sp. Atk":"65","Sp. Def":"55","Species":"Proud Pok\u00e9mon","Speed":"93","Total":"488","Type":["Normal","Flying"]},"Unown":{"#":"201","Attack":"72","Defense":"48","FlavorText":"","HP":"48","Sp. Atk":"72","Sp. Def":"48","Species":"Symbol Pok\u00e9mon","Speed":"48","Total":"336","Type":["Psychic"]},"Ursaring":{"#":"217","Attack":"130","Defense":"75","FlavorText":"In forests, it is said that there are many streams and towering trees where an URSARING gathers food. It walks through its forest collecting food every day.","HP":"90","Sp. Atk":"75","Sp. Def":"75","Species":"Hibernator Pok\u00e9mon","Speed":"55","Total":"500","Type":["Normal"]},"Uxie":{"#":"480","Attack":"75","Defense":"130","FlavorText":"","HP":"75","Sp. Atk":"75","Sp. Def":"130","Species":"Knowledge Pok\u00e9mon","Speed":"95","Total":"580","Type":["Psychic"]},"Vanillish":{"#":"583","Attack":"65","Defense":"65","FlavorText":"","HP":"51","Sp. Atk":"80","Sp. Def":"75","Species":"Icy Snow Pok\u00e9mon","Speed":"59","Total":"395","Type":["Ice"]},"Vanillite":{"#":"582","Attack":"50","Defense":"50","FlavorText":"","HP":"36","Sp. Atk":"65","Sp. Def":"60","Species":"Fresh Snow Pok\u00e9mon","Speed":"44","Total":"305","Type":["Ice"]},"Vanilluxe":{"#":"584","Attack":"95","Defense":"85","FlavorText":"","HP":"71","Sp. Atk":"110","Sp. Def":"95","Species":"Snowstorm Pok\u00e9mon","Speed":"79","Total":"535","Type":["Ice"]},"Vaporeon":{"#":"134","Attack":"65","Defense":"60","FlavorText":"","HP":"130","Sp. Atk":"110","Sp. Def":"95","Species":"Bubble Jet Pok\u00e9mon","Speed":"65","Total":"525","Type":["Water"]},"Venipede":{"#":"543","Attack":"45","Defense":"59","FlavorText":"Its bite injects a potent poison, enough to paralyze large bird Pok\u00e9mon that try to prey on it.","HP":"30","Sp. Atk":"30","Sp. Def":"39","Species":"Centipede Pok\u00e9mon","Speed":"57","Total":"260","Type":["Bug","Poison"]},"Venomoth":{"#":"049","Attack":"65","Defense":"60","FlavorText":"The scales it scatters will paralyze anyone who touches them, making that person unable to stand.","HP":"70","Sp. Atk":"90","Sp. Def":"75","Species":"Poison Moth Pok\u00e9mon","Speed":"90","Total":"450","Type":["Bug","Poison"]},"Venonat":{"#":"048","Attack":"55","Defense":"50","FlavorText":"The small bugs it eats appear only at night, so it sleeps in a hole in a tree until night falls.","HP":"60","Sp. Atk":"40","Sp. Def":"55","Species":"Insect Pok\u00e9mon","Speed":"45","Total":"305","Type":["Bug","Poison"]},"Venusaur":{"#":"003","Attack":"82","Defense":"83","FlavorText":"","HP":"80","Sp. Atk":"100","Sp. Def":"100","Species":"Seed Pok\u00e9mon","Speed":"80","Total":"525","Type":["Grass","Poison"]},"Venusaur ( Mega Venusaur )":{"#":"003","Attack":"100","Defense":"123","FlavorText":"","HP":"80","Sp. Atk":"122","Sp. Def":"120","Species":"","Speed":"80","Total":"625","Type":["Grass","Poison"]},"Vespiquen":{"#":"416","Attack":"80","Defense":"102","FlavorText":"","HP":"70","Sp. Atk":"80","Sp. Def":"102","Species":"Beehive Pok\u00e9mon","Speed":"40","Total":"474","Type":["Bug","Flying"]},"Vibrava":{"#":"329","Attack":"70","Defense":"50","FlavorText":"","HP":"50","Sp. Atk":"50","Sp. Def":"50","Species":"Vibration Pok\u00e9mon","Speed":"70","Total":"340","Type":["Ground","Dragon"]},"Victini":{"#":"494","Attack":"100","Defense":"100","FlavorText":"","HP":"100","Sp. Atk":"100","Sp. Def":"100","Species":"Victory Pok\u00e9mon","Speed":"100","Total":"600","Type":["Psychic","Fire"]},"Victreebel":{"#":"071","Attack":"105","Defense":"65","FlavorText":"Once ingested into this POK\u00e9MON's body, even the hardest object will melt into nothing.","HP":"80","Sp. Atk":"100","Sp. Def":"70","Species":"Flycatcher Pok\u00e9mon","Speed":"70","Total":"490","Type":["Grass","Poison"]},"Vigoroth":{"#":"288","Attack":"80","Defense":"80","FlavorText":"","HP":"80","Sp. Atk":"55","Sp. Def":"55","Species":"Wild Monkey Pok\u00e9mon","Speed":"90","Total":"440","Type":["Normal"]},"Vileplume":{"#":"045","Attack":"80","Defense":"85","FlavorText":"","HP":"75","Sp. Atk":"110","Sp. Def":"90","Species":"Flower Pok\u00e9mon","Speed":"50","Total":"490","Type":["Grass","Poison"]},"Virizion":{"#":"640","Attack":"90","Defense":"72","FlavorText":"","HP":"91","Sp. Atk":"90","Sp. Def":"129","Species":"Grassland Pok\u00e9mon","Speed":"108","Total":"580","Type":["Grass","Fighting"]},"Vivillon":{"#":"666","Attack":"52","Defense":"50","FlavorText":"","HP":"80","Sp. Atk":"90","Sp. Def":"50","Species":"Scale Pok\u00e9mon","Speed":"89","Total":"411","Type":["Bug","Flying"]},"Volbeat":{"#":"313","Attack":"73","Defense":"55","FlavorText":"With their taillights lit, VOLBEAT fly in a swarm, drawing geometric designs in the night sky. They move their nests if their pond water becomes dirty.","HP":"65","Sp. Atk":"47","Sp. Def":"75","Species":"Firefly Pok\u00e9mon","Speed":"85","Total":"400","Type":["Bug"]},"Volcanion":{"#":"721","Attack":"110","Defense":"120","FlavorText":"","HP":"80","Sp. Atk":"130","Sp. Def":"90","Species":"Steam Pok\u00e9mon","Speed":"70","Total":"600","Type":["Fire","Water"]},"Volcarona":{"#":"637","Attack":"60","Defense":"65","FlavorText":"","HP":"85","Sp. Atk":"135","Sp. Def":"105","Species":"Sun Pok\u00e9mon","Speed":"100","Total":"550","Type":["Bug","Fire"]},"Voltorb":{"#":"100","Attack":"30","Defense":"50","FlavorText":"","HP":"40","Sp. Atk":"55","Sp. Def":"55","Species":"Ball Pok\u00e9mon","Speed":"100","Total":"330","Type":["Electric"]},"Vullaby":{"#":"629","Attack":"55","Defense":"75","FlavorText":"","HP":"70","Sp. Atk":"45","Sp. Def":"65","Species":"Diapered Pok\u00e9mon","Speed":"60","Total":"370","Type":["Dark","Flying"]},"Vulpix":{"#":"037","Attack":"41","Defense":"40","FlavorText":"","HP":"38","Sp. Atk":"50","Sp. Def":"65","Species":"Fox Pok\u00e9mon","Speed":"65","Total":"299","Type":["Fire"]},"Wailmer":{"#":"320","Attack":"70","Defense":"35","FlavorText":"","HP":"130","Sp. Atk":"70","Sp. Def":"35","Species":"Ball Whale Pok\u00e9mon","Speed":"60","Total":"400","Type":["Water"]},"Wailord":{"#":"321","Attack":"90","Defense":"45","FlavorText":"","HP":"170","Sp. Atk":"90","Sp. Def":"45","Species":"Float Whale Pok\u00e9mon","Speed":"60","Total":"500","Type":["Water"]},"Walrein":{"#":"365","Attack":"80","Defense":"90","FlavorText":"To protect its herd, the leader battles anything that invades its territory, even at the cost of its life. Its tusks may snap off in battle.","HP":"110","Sp. Atk":"95","Sp. Def":"90","Species":"Ice Break Pok\u00e9mon","Speed":"65","Total":"530","Type":["Ice","Water"]},"Wartortle":{"#":"008","Attack":"63","Defense":"80","FlavorText":"Its long, furry tail is a symbol of longevity, making it quite popular among older people.","HP":"59","Sp. Atk":"65","Sp. Def":"80","Species":"Turtle Pok\u00e9mon","Speed":"58","Total":"405","Type":["Water"]},"Watchog":{"#":"505","Attack":"85","Defense":"69","FlavorText":"When they see an enemy, their tails stand high, and they spit the seeds of berries stored in their cheek pouches.","HP":"60","Sp. Atk":"60","Sp. Def":"69","Species":"Lookout Pok\u00e9mon","Speed":"77","Total":"420","Type":["Normal"]},"Weavile":{"#":"461","Attack":"120","Defense":"65","FlavorText":"","HP":"70","Sp. Atk":"45","Sp. Def":"85","Species":"Sharp Claw Pok\u00e9mon","Speed":"125","Total":"510","Type":["Dark","Ice"]},"Weedle":{"#":"013","Attack":"35","Defense":"30","FlavorText":"The barb on top of its head secretes a strong poison. It uses this toxic barb to protect itself.","HP":"40","Sp. Atk":"20","Sp. Def":"20","Species":"Hairy Bug Pok\u00e9mon","Speed":"50","Total":"195","Type":["Bug","Poison"]},"Weepinbell":{"#":"070","Attack":"90","Defense":"50","FlavorText":"When it's hungry, it swings its razor-sharp leaves, slicing up any unlucky object nearby for food.","HP":"65","Sp. Atk":"85","Sp. Def":"45","Species":"Flycatcher Pok\u00e9mon","Speed":"55","Total":"390","Type":["Grass","Poison"]},"Weezing":{"#":"110","Attack":"90","Defense":"120","FlavorText":"","HP":"65","Sp. Atk":"85","Sp. Def":"70","Species":"Poison Gas Pok\u00e9mon","Speed":"60","Total":"490","Type":["Poison"]},"Whimsicott":{"#":"547","Attack":"67","Defense":"85","FlavorText":"","HP":"60","Sp. Atk":"77","Sp. Def":"75","Species":"Windveiled Pok\u00e9mon","Speed":"116","Total":"480","Type":["Grass","Fairy"]},"Whirlipede":{"#":"544","Attack":"55","Defense":"99","FlavorText":"It is usually motionless, but when attacked, it rotates at high speed and then crashes into its opponent.","HP":"40","Sp. Atk":"40","Sp. Def":"79","Species":"Curlipede Pok\u00e9mon","Speed":"47","Total":"360","Type":["Bug","Poison"]},"Whiscash":{"#":"340","Attack":"78","Defense":"73","FlavorText":"","HP":"110","Sp. Atk":"76","Sp. Def":"71","Species":"Whiskers Pok\u00e9mon","Speed":"60","Total":"468","Type":["Water","Ground"]},"Whismur":{"#":"293","Attack":"51","Defense":"23","FlavorText":"","HP":"64","Sp. Atk":"51","Sp. Def":"23","Species":"Whisper Pok\u00e9mon","Speed":"28","Total":"240","Type":["Normal"]},"Wigglytuff":{"#":"040","Attack":"70","Defense":"45","FlavorText":"","HP":"140","Sp. Atk":"85","Sp. Def":"50","Species":"Balloon Pok\u00e9mon","Speed":"45","Total":"435","Type":["Normal","Fairy"]},"Wingull":{"#":"278","Attack":"30","Defense":"30","FlavorText":"","HP":"40","Sp. Atk":"55","Sp. Def":"30","Species":"Seagull Pok\u00e9mon","Speed":"85","Total":"270","Type":["Water","Flying"]},"Wobbuffet":{"#":"202","Attack":"33","Defense":"58","FlavorText":"","HP":"190","Sp. Atk":"33","Sp. Def":"58","Species":"Patient Pok\u00e9mon","Speed":"33","Total":"405","Type":["Psychic"]},"Woobat":{"#":"527","Attack":"45","Defense":"43","FlavorText":"The heart-shaped mark left on a body after a Woobat has been attached to it is said to bring good fortune.","HP":"55","Sp. Atk":"55","Sp. Def":"43","Species":"Bat Pok\u00e9mon","Speed":"72","Total":"313","Type":["Psychic","Flying"]},"Wooper":{"#":"194","Attack":"45","Defense":"45","FlavorText":"","HP":"55","Sp. Atk":"25","Sp. Def":"25","Species":"Water Fish Pok\u00e9mon","Speed":"15","Total":"210","Type":["Water","Ground"]},"Wormadam ( Plant Cloak )":{"#":"413","Attack":"59","Defense":"85","FlavorText":"","HP":"60","Sp. Atk":"79","Sp. Def":"105","Species":"","Speed":"36","Total":"424","Type":["Bug","Grass"]},"Wormadam ( Sandy Cloak )":{"#":"413","Attack":"79","Defense":"105","FlavorText":"","HP":"60","Sp. Atk":"59","Sp. Def":"85","Species":"","Speed":"36","Total":"424","Type":["Bug","Ground"]},"Wormadam ( Trash Cloak )":{"#":"413","Attack":"69","Defense":"95","FlavorText":"","HP":"60","Sp. Atk":"69","Sp. Def":"95","Species":"","Speed":"36","Total":"424","Type":["Bug","Steel"]},"Wurmple":{"#":"265","Attack":"45","Defense":"35","FlavorText":"Often targeted by bird Pok\u00e9mon, it desperately resists by releasing poison from its tail spikes.","HP":"45","Sp. Atk":"20","Sp. Def":"30","Species":"Worm Pok\u00e9mon","Speed":"20","Total":"195","Type":["Bug"]},"Wynaut":{"#":"360","Attack":"23","Defense":"48","FlavorText":"","HP":"95","Sp. Atk":"23","Sp. Def":"48","Species":"Bright Pok\u00e9mon","Speed":"23","Total":"260","Type":["Psychic"]},"Xatu":{"#":"178","Attack":"75","Defense":"70","FlavorText":"","HP":"65","Sp. Atk":"95","Sp. Def":"70","Species":"Mystic Pok\u00e9mon","Speed":"95","Total":"470","Type":["Psychic","Flying"]},"Xerneas":{"#":"716","Attack":"131","Defense":"95","FlavorText":"","HP":"126","Sp. Atk":"131","Sp. Def":"98","Species":"Life Pok\u00e9mon","Speed":"99","Total":"680","Type":["Fairy"]},"Yamask":{"#":"562","Attack":"30","Defense":"85","FlavorText":"","HP":"38","Sp. Atk":"55","Sp. Def":"65","Species":"Spirit Pok\u00e9mon","Speed":"30","Total":"303","Type":["Ghost"]},"Yanma":{"#":"193","Attack":"65","Defense":"45","FlavorText":"","HP":"65","Sp. Atk":"75","Sp. Def":"45","Species":"Clear Wing Pok\u00e9mon","Speed":"95","Total":"390","Type":["Bug","Flying"]},"Yanmega":{"#":"469","Attack":"76","Defense":"86","FlavorText":"","HP":"86","Sp. Atk":"116","Sp. Def":"56","Species":"Ogre Darner Pok\u00e9mon","Speed":"95","Total":"515","Type":["Bug","Flying"]},"Yveltal":{"#":"717","Attack":"131","Defense":"95","FlavorText":"","HP":"126","Sp. Atk":"131","Sp. Def":"98","Species":"Destruction Pok\u00e9mon","Speed":"99","Total":"680","Type":["Dark","Flying"]},"Zangoose":{"#":"335","Attack":"115","Defense":"60","FlavorText":"When it battles, it stands on its hind legs and attacks with its sharply clawed forelegs. Its fur bristles if it encounters any SEVIPER.","HP":"73","Sp. Atk":"60","Sp. Def":"60","Species":"Cat Ferret Pok\u00e9mon","Speed":"90","Total":"458","Type":["Normal"]},"Zapdos":{"#":"145","Attack":"90","Defense":"85","FlavorText":"Legendary bird POK\u00e9MON. They say lightning caused by the flapping of its wings causes summer storms.","HP":"90","Sp. Atk":"125","Sp. Def":"90","Species":"Electric Pok\u00e9mon","Speed":"100","Total":"580","Type":["Electric","Flying"]},"Zebstrika":{"#":"523","Attack":"100","Defense":"63","FlavorText":"","HP":"75","Sp. Atk":"80","Sp. Def":"63","Species":"Thunderbolt Pok\u00e9mon","Speed":"116","Total":"497","Type":["Electric"]},"Zekrom":{"#":"644","Attack":"150","Defense":"120","FlavorText":"","HP":"100","Sp. Atk":"120","Sp. Def":"100","Species":"Deep Black Pok\u00e9mon","Speed":"90","Total":"680","Type":["Dragon","Electric"]},"Zigzagoon":{"#":"263","Attack":"30","Defense":"41","FlavorText":"Rubbing its nose against the ground, it always wanders about back and forth in search of something. It is distinguished by the zigzag footprints it leaves.","HP":"38","Sp. Atk":"30","Sp. Def":"41","Species":"TinyRaccoon Pok\u00e9mon","Speed":"60","Total":"240","Type":["Normal"]},"Zoroark":{"#":"571","Attack":"105","Defense":"60","FlavorText":"","HP":"60","Sp. Atk":"120","Sp. Def":"60","Species":"Illusion Fox Pok\u00e9mon","Speed":"105","Total":"510","Type":["Dark"]},"Zorua":{"#":"570","Attack":"65","Defense":"40","FlavorText":"","HP":"40","Sp. Atk":"80","Sp. Def":"40","Species":"Tricky Fox Pok\u00e9mon","Speed":"65","Total":"330","Type":["Dark"]},"Zubat":{"#":"041","Attack":"45","Defense":"35","FlavorText":"","HP":"40","Sp. Atk":"30","Sp. Def":"40","Species":"Bat Pok\u00e9mon","Speed":"55","Total":"245","Type":["Poison","Flying"]},"Zweilous":{"#":"634","Attack":"85","Defense":"70","FlavorText":"","HP":"72","Sp. Atk":"65","Sp. Def":"70","Species":"Hostile Pok\u00e9mon","Speed":"58","Total":"420","Type":["Dark","Dragon"]},"Zygarde50% ( Forme )":{"#":"718","Attack":"100","Defense":"121","FlavorText":"","HP":"108","Sp. Atk":"81","Sp. Def":"95","Species":"","Speed":"95","Total":"600","Type":["Dragon","Ground"]}} diff --git a/PokedexTests/Info.plist b/PokedexTests/Info.plist new file mode 100644 index 0000000..6c6c23c --- /dev/null +++ b/PokedexTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/PokedexTests/PokedexTests.swift b/PokedexTests/PokedexTests.swift new file mode 100644 index 0000000..06b8be3 --- /dev/null +++ b/PokedexTests/PokedexTests.swift @@ -0,0 +1,36 @@ +// +// PokedexTests.swift +// PokedexTests +// +// Created by SAMEER SURESH on 9/25/16. +// Copyright © 2016 trainingprogram. All rights reserved. +// + +import XCTest +@testable import Pokedex + +class PokedexTests: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testPerformanceExample() { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +} diff --git a/PokedexUITests/Info.plist b/PokedexUITests/Info.plist new file mode 100644 index 0000000..6c6c23c --- /dev/null +++ b/PokedexUITests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/PokedexUITests/PokedexUITests.swift b/PokedexUITests/PokedexUITests.swift new file mode 100644 index 0000000..763b9e0 --- /dev/null +++ b/PokedexUITests/PokedexUITests.swift @@ -0,0 +1,36 @@ +// +// PokedexUITests.swift +// PokedexUITests +// +// Created by SAMEER SURESH on 9/25/16. +// Copyright © 2016 trainingprogram. All rights reserved. +// + +import XCTest + +class PokedexUITests: XCTestCase { + + override func setUp() { + super.setUp() + + // Put setup code here. This method is called before the invocation of each test method in the class. + + // In UI tests it is usually best to stop immediately when a failure occurs. + continueAfterFailure = false + // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. + XCUIApplication().launch() + + // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // Use recording to get started writing UI tests. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + +} diff --git a/README.md b/README.md index 94139a4..3cdfa9e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1 @@ -# proj2FA17iOS -Repository for Fall 2017 MDB iOS Training Program Mini-Project 2 Submissions - -Finalized mini-projects should be stored in personal portfolios, but this repository will be used for providing feedback on code quality using the GitHub code review features. - -When pushing code to this repo, DO NOT push to master. Create a new branch and open a pull request. +# pokedex \ No newline at end of file