tag:blogger.com,1999:blog-80972453546024876052024-03-16T02:10:22.705+01:00The Joobik BlogBlog of the Developer of Joobik Player - iTunes Video Playlists on iPhone and iPad.
Blogs about iOS, Software Development, Contract and DAPP programming on the Ethereum Blockchainjoobikhttp://www.blogger.com/profile/09390437095051380351noreply@blogger.comBlogger25125tag:blogger.com,1999:blog-8097245354602487605.post-38461956829776952262017-11-18T16:35:00.004+01:002017-11-21T13:21:37.621+01:00Getting started with a private Ethereum Blockchain and Solidity Contract Development on geth 1.6 or higherIn order to take this tutorial it is assumed that you have set up your development environment as explained in the first part <a href="http://www.joobik.com/2017/11/installing-solidity-development.html" target="_blank">Installing a Solidity Development Environment for Ethereum Contract programming</a>.<br />
<br />
In the second part of our Ethereum programming tutorial we will set up a private Ethereum development network, and implement our first smart contract.<br />
<br />
This tutorial is based on a geth version later than 1.6, namely 1.7.2. What makes worth mentioning it is the fact that in version 1.6 the inline Solidity compiler support was removed from geth. For whatever <a href="https://github.com/ethereum/EIPs/issues/209" target="_blank">reason</a>. But by the time of writing these lines (end of 2017) there is no ramp-up tutorial to be found out there which reflects this fact. Even the official <a href="https://ethereum.org/greeter" target="_blank">Ethereum "Hello world" tutorial</a> still refers to the Solidity compiler being included with geth!<br />
<br />
But no worry: I'll do that for you! Here comes the first rookie walkthrough for creating, compiling, deploying, and running a Solidity Ethereum contract utilizing the command line Solidity compiler!<br />
<br />
<h2>
1. Setup the private Ethereum Development Node</h2>
First create a new data directory for your private blockchain. We do this right beneath our home directory:<br />
<br />
<div style="background-color: black; color: white; font-family: "courier new" , "courier" , monospace; width: 100%;">
<span style="font-size: x-small;">$ mkdir ~/privatechain</span></div>
<br />
Then start a geth development network pointing to this data directory:<br />
<br />
<div style="background-color: black; color: white; font-family: "courier new", courier, monospace; width: 653px;">
<span style="font-size: x-small;">$ geth --rpc --rpcaddr 127.0.0.1 --rpcport 8545 --dev --datadir ~/privatechain</span></div>
<br />
If everything went right the last terminal output should read something like:<br />
<br />
<div class="p1">
<span class="s1">IPC endpoint opened: /Users/as/privatechain/geth.ipc<span class="Apple-converted-space"> </span></span></div>
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000; background-color: #ffffff}
span.s1 {font-variant-ligatures: no-common-ligatures}
span.s2 {font-variant-ligatures: no-common-ligatures; color: #34bc26}
</style>
<br />
<div class="p1">
<span class="s1">HTTP endpoint opened: http://127.0.0.1:8545<span class="Apple-converted-space"> </span></span></div>
<br />
But what do these <a href="https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options" target="_blank">options</a> mean:<br />
<ul>
<li><b>rpc:</b> Enable remote procedure calls via http on this geth instance, so we can connect to it from another node (i.e. terminal window)</li>
<li><b>rpcaddr:</b> The IP address where RPC shall be accessible. In this case it's the local host since we are on the same machine.</li>
<li><b>rpcport:</b> The port to access RPC. As 8545 is the standard port, we also could have left out this option.</li>
<li><b>dev:</b> This flag creates a development network, so we do not connect to the "real" Ethereum network where we would have to spend real Ether (meaning real money) to execute our contracts. It also conveniently preconfigures the first block (the Genesis) of our network. We will cover creating our own Genesis Block in a later tutorial.</li>
<li><b>datadir:</b> Guess what? It points to our private chain's data directory just created!</li>
</ul>
Just take a look into your <i>privatechain</i> directory. You should find the subdirs <i>geth</i> and <i>keystore</i> there!<br />
<br />
<h2>
2. Connect a geth console to the Development Node</h2>
<div>
You will have recognized that our running geth node is quite busy with its own affairs. It's not being impressed by typing commands into its terminal window. Not even by poems! So we have to get in contact:</div>
<div>
<br /></div>
<div>
Open another macOS terminal window. I'd suggest using a different color for it so you never mix up the terminals later on. We will use the grass style terminal throughout this tutorial - as it comes preconfigured with macOS - to reference the remote command line interface (CLI) geth console.</div>
<div>
<br /></div>
<div>
So just execute this in the new console window replacing the "<span style="color: red;">as</span>" with your user name:</div>
<div>
<br /></div>
<div>
<div style="background-color: #1c793d; width: 653px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">geth attach ipc://Users/</span><span style="color: red; font-family: "courier new" , "courier" , monospace; font-size: x-small;">as</span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">/privatechain/geth.ipc </span></div>
</div>
<div>
<br /></div>
Congratulations! You just opened a remote console to our Ethereum node!<br />
<br />
But what about the "ipc" thing when we where talking about "rpc" earlier? Just that simple: IPC or <a href="https://en.wikipedia.org/wiki/Inter-process_communication" target="_blank">Inter Process Communication</a> can be used when separate processes need to interact on the same machine while <a href="https://en.wikipedia.org/wiki/Remote_procedure_call" target="_blank">RPC</a> must be used when the processes run on different machines.<br />
<br />
<h2>
3. Create the first account</h2>
Now we have to create an external <a href="http://solidity.readthedocs.io/en/develop/introduction-to-smart-contracts.html#accounts" target="_blank">account</a> on our Ethereum network. An account enables us to perform <a href="http://solidity.readthedocs.io/en/develop/introduction-to-smart-contracts.html#index-8" target="_blank">transactions</a> on the network (i.e. make use of it). To do so we utilize geth's <a href="https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal" target="_blank">Management API</a>:<br />
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
</div>
<br />
<div style="orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; widows: 2;">
<div style="background-color: #1c793d; width: 653px;">
<div style="margin: 0px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small; font-style: normal; font-weight: 400; letter-spacing: normal; text-transform: none; white-space: normal; word-spacing: 0px;">> </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">personal.newAccount('password')</span></div>
</div>
</div>
<br />
'password' literarily is the password here. So feel free to use your own! This command will output the address of the account created. It's a good idea to write it down somewhere!<br />
<br />
Now check the account really exists:<br />
<br />
<div>
<div style="background-color: #1c793d; width: 653px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace;">> </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">personal.listAccounts</span></div>
</div>
<br />
This should output an array containing the account just created. So in my case it's:<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">["0x839d4ed149062e6e2e7ab772167f366282c600ce"]</span><br />
<br />
This first account automatically is set as the coinbase in our network. This is where all the mining rewards will got to. You can check it using the <a href="https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethcoinbase" target="_blank">web3 API</a>:<br />
<br />
<div>
<div style="background-color: #1c793d; width: 653px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace;">> </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">eth.coinbase</span></div>
</div>
<br />
This should output the same account just created.<br />
<br />
<h2>
4. Create the Contract Source Code</h2>
<div>
Now it's time to write our first Ethereum contract definition. If you are familiar with object oriented programming languages it helps to think of a contract definition as a class definition.</div>
<div>
<br /></div>
<div>
For better maintainability we will store the contract files in a separate directory. So just go ahead an create a folder <i>~/ethcontracts</i>!</div>
<div>
<br /></div>
<div>
Right inside this folder create a new text file named MyFirstContract.sol. This is your first Solidity source code file! Feeling great?<br />
<br />
Now paste this code into the file and save:</div>
<div>
<br /></div>
<div>
<div style="background-color: lightgrey; width: 653px;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">pragma solidity ^0.4.8;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">contract MyFirstContract { </span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> function reflect(string yourself) public returns(string){</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> return yourself;</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> </span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span></div>
</div>
<br />
I think there isn't a detailed walkthrough required. You will have noticed that in the first line we define the smallest Solidity version supported by this contract. Then we create a contract named <i>MyFirstContract</i> which has one method that simply reflects its input.<br />
<br />
But now comes the challenging part:<br />
<br />
<h2>
5. Compile the Contract</h2>
As told earlier in this tutoriel, calling the Solidity compiler right from the geth console has been removed from geth 1.6. So we have to compile our source file outside the running Ethereum network, and import it into it. In order to do so we need to have the Solidity compiler installed as explained in the <a href="http://www.joobik.com/2017/11/installing-solidity-development.html" target="_blank">first part of this tutorial</a>.<br />
<br />
As we have two instances of macOS terminal already running, we will need a third one. Believe it or not! So please open another terminal instance. We will use the ocean theme to identify it in this tutorial.<br />
<br />
First we'll do a test run to check if the Solidity compiler is working as expected. So please issue:<br />
<br />
<div style="background-color: #2b66c9; color: white; width: 100%;">
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ solc --optimize --combined-json abi,bin,interface ~/ethcontracts/MyFirstContract.sol </span></div>
<br />
We should get something like this:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">{"contracts":{"/Users/as/ethcontracts/MyFirstContract.sol:MyFirstContract":{"abi":"[{\"constant\":false,\"inputs\":[{\"name\":\"yourself\",\"type\":\"string\"}],\"name\":\"reflect\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]","bin":"6060604052341561000f57600080fd5b6101578061001e6000396000f3006060604052600436106100405763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663c1ce53fc8114610045575b600080fd5b341561005057600080fd5b61009660046024813581810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284375094965061010d95505050505050565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156100d25780820151838201526020016100ba565b50505050905090810190601f1680156100ff5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610115610119565b5090565b602060405190810160405260008152905600a165627a7a723058207e8ac985f99f507869c23d1d1457c38e5aace7b1eafa9f31eff3e02d9aecfd450029"}},"version":"0.4.18+commit.9cf6e910.Darwin.appleclang"}</span><br />
<br />
If there are some warnings ahead of this output we just can ignore them! The important thing to notice is that we have our contract source code compiled into an <i><a href="https://solidity.readthedocs.io/en/develop/abi-spec.html" target="_blank">abi</a></i> and a <i>bin</i> section.<br />
<br />
Now let's use this for real!<br />
<br />
In order to be able to deploy the compiled contract into our Ethereum dev network, we have to create a compiled file from the source code. We do it using good old terminal commands:<br />
<br />
<div style="background-color: #2b66c9; width: 653px;">
<span style="color: white; font-family: "courier new" , "courier" , monospace; font-size: x-small;">echo "var MyFirstContractCompiled=`solc --optimize --combined-json abi,bin,interface ~/ethcontracts/MyFirstContract.sol`" > ~/ethcontracts/MyFirstContract.js</span></div>
<br />
What happens here is that we create an actual JavaScript file <i>MyFirstContract.js</i> where we assign the output JSON object of the Solidity compiler to a variable called <i>MyFirstContractCompiled</i>.<br />
<br />
Now we're ready for the next step:<br />
<h2>
6. Import the contract </h2>
<div>
We want to get the precompiled contract from the compiled JavaScript file into our Ethereum node and prepare it for deployment to our development network.</div>
<div>
<br /></div>
<div>
So we return to our geth console and load the JavaScript file just compiled (Note: We assume that the geth console was started from your user's home directory. If not, you have to specify the absolute path to the <i>MyFirstContract.js</i> file):</div>
<div>
<br /></div>
<div>
<div>
<div style="background-color: #1c793d; width: 653px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace;">> </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">loadScript("./ethcontracts/MyFirstContract.js")</span></div>
</div>
</div>
<div>
<br /></div>
<div>
The resulting output should be:</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">true</span></div>
<div>
<br /></div>
<div>
So let's check if everything went right by outputting the value of the <i>MyFirstContractCompiled</i> variable:</div>
<div>
<br /></div>
<div>
<div>
<div style="background-color: #1c793d; width: 653px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace;">> </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">MyFirstContractCompiled</span></div>
</div>
</div>
<div>
<br /></div>
<div>
Should give you an output like this:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">{</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> contracts: {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> /Users/as/ethcontracts/MyFirstContract.sol:MyFirstContract: {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> abi: "[{\"constant\":false,\"inputs\":[{\"name\":\"yourself\",\"type\":\"string\"}],\"name\":\"reflect\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> bin: "6060604052341561000f57600080fd5b6101578061001e6000396000f3006060604052600436106100405763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663c1ce53fc8114610045575b600080fd5b341561005057600080fd5b61009660046024813581810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284375094965061010d95505050505050565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156100d25780820151838201526020016100ba565b50505050905090810190601f1680156100ff5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610115610119565b5090565b602060405190810160405260008152905600a165627a7a723058207e8ac985f99f507869c23d1d1457c38e5aace7b1eafa9f31eff3e02d9aecfd450029"</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> },</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> version: "0.4.18+commit.9cf6e910.Darwin.appleclang"</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span></div>
</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
Now we have to create an actual contract object from the compiled contract definition, which we can instantiate on our Ethereum network later. To achieve this, we have to select the <i>abi</i> part of our <i>MyFirstContract</i> stored in the <i>MyFirstContractCompiled</i> variable and pass it to the <a href="https://web3js.readthedocs.io/en/1.0/web3-eth-contract.html" target="_blank"><i>web3.eth.contract</i></a><i> </i>function:</div>
<div>
<br />
<br />
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
</div>
<br />
<div style="-webkit-text-stroke-width: 0px; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
<div>
<div style="background-color: #1c793d; width: 653px;">
<div style="margin: 0px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace;">> </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">MyContract = web3.eth.contract(JSON.parse(MyFirstContractCompiled.contracts["/Users/</span><span style="color: red; font-family: "courier new" , "courier" , monospace; font-size: x-small;">as</span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">/ethcontracts/MyFirstContract.sol:MyFirstContract"].abi))</span></div>
</div>
</div>
</div>
<br /></div>
<div>
Make sure to replace the "<span style="color: red;">as</span>" with your actual user name!<br />
It is important to not forget the <span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><a href="https://www.w3schools.com/js/js_json_parse.asp" target="_blank">JSON.parse</a></span> part! This will parse the string representation of our abi into an actual JavaScript object.<br />
<br />
You should get an output like this:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">{</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> abi: [{</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> constant: false,</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> inputs: [{...}],</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> name: "reflect",</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> outputs: [{...}],</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> payable: false,</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> stateMutability: "nonpayable",</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> type: "function"</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }],</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> eth: {</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> accounts: ["0x839d4ed149062e6e2e7ab772167f366282c600ce"],</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> blockNumber: 0,</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> coinbase: "0x839d4ed149062e6e2e7ab772167f366282c600ce",</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> compile: {</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> lll: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> serpent: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> solidity: function()</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> },</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> defaultAccount: undefined,</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> defaultBlock: "latest",</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> gasPrice: 0,</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> hashrate: 0,</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> mining: false,</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> pendingTransactions: [],</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> protocolVersion: "0x3f",</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> syncing: false,</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> call: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> contract: function(abi),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> estimateGas: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> filter: function(options, callback, filterCreationErrorCallback),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getAccounts: function(callback),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getBalance: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getBlock: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getBlockNumber: function(callback),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getBlockTransactionCount: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getBlockUncleCount: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getCode: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getCoinbase: function(callback),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getCompilers: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getGasPrice: function(callback),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getHashrate: function(callback),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getMining: function(callback),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getPendingTransactions: function(callback),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getProtocolVersion: function(callback),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getRawTransaction: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getRawTransactionFromBlock: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getStorageAt: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getSyncing: function(callback),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getTransaction: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getTransactionCount: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getTransactionFromBlock: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getTransactionReceipt: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getUncle: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getWork: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> iban: function(iban),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> icapNamereg: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> isSyncing: function(callback),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> namereg: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> resend: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> sendIBANTransaction: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> sendRawTransaction: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> sendTransaction: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> sign: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> signTransaction: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> submitTransaction: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> submitWork: function()</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> },</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> at: function(address, callback),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> getData: function(),</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> new: function()</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<br />
<h2>
7. Deploy the contract</h2>
Now that we have our <i>MyContract</i> object, we want to deploy it to our Ethereum development network.<br />
<br />
As you know: There's no free lunch! Especially not on the Ethereum network. Every transaction has its cost. And contract deployment is a transaction! So we have to check first if we have enough Ether to actually do the deployment.<br />
<br />
For convenience we define a neat variable pointing to our coinbase account (where all the mined ether goes to)..<br />
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
</div>
<br />
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
<div>
<div style="background-color: #1c793d; width: 653px;">
<div style="margin: 0px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace;">> </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">MyAccount = eth.coinbase</span></div>
</div>
</div>
</div>
<br />
..and check the funds:<br />
<br />
<div>
<div style="background-color: #1c793d; width: 653px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace;">> </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">eth.getBalance(MyAccount)</span></div>
</div>
<br />
If this returns 0, we have to mine some Ether:<br />
<br />
<div>
<div style="background-color: #1c793d; width: 653px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace;">> </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">miner.start()</span></div>
</div>
<br />
This will start the mining process on our initial geth development node. Just check your first terminal window (the one that is black in this tutorial, but is likely to be white on your Mac).<br />
<br />
Meanwhile, we want to know the expenses of deploying our contract. The deployment itself is a Ethereum <a href="http://solidity.readthedocs.io/en/develop/introduction-to-smart-contracts.html#index-8" target="_blank">transaction</a> with the compiled binary contract data as payload. We can use the <span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><a href="https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethestimategas" target="_blank">web3.eth.estimateGas</a></span> function to simulate this transaction and estimate the <a href="http://solidity.readthedocs.io/en/develop/introduction-to-smart-contracts.html#gas" target="_blank">gas</a> required to execute it.<br />
<br />
First we create a hex string from the bin section of <i>MyFirstContractCompiled</i> and store it in a variable for later use. This is done by suffixing the bin string with "<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">0x</span>":<br />
<br />
<div>
<div style="background-color: #1c793d; width: 653px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace;">> </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">MyContractBin = "0x" + MyFirstContractCompiled.contracts["/Users/as/ethcontracts/MyFirstContract.sol:MyFirstContract"].bin</span></div>
</div>
<br />
Then we can estimate the costs of contract deployment:<br />
<br />
<div>
<div style="background-color: #1c793d; width: 653px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace;">> </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">eth.estimateGas({data: MyContractBin })</span></div>
</div>
<br />
This will output a number to which we will refer a little later when actually deploying the contract.<br />
<br />
For now it's time to stop mining:<br />
<br />
<div>
<div style="background-color: #1c793d; width: 653px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace;">> </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">miner.stop()</span></div>
</div>
<br />
Prior to be able to deploy the contract we have to authorize (or unlock) our account with our password, so nobody else than you can spend your ether for this deployment:<br />
<br />
<div>
<div style="background-color: #1c793d; width: 653px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace;">> </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">personal.unlockAccount(MyAccount, "password")</span></div>
</div>
<br />
And now we create the contract:<br />
<br />
<div>
<div style="background-color: #1c793d; width: 653px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace;">> </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">MyContractInstance = MyContract.new({data: MyContractBin gas: 143940, from: MyAccount})</span></div>
</div>
<br />
Supply at least as much gas as we estimated a few steps earlier!<br />
<br />
You should get an output like this:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">{</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> abi: [{</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> constant: false,</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> inputs: [{...}],</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> name: "reflect",</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> outputs: [{...}],</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> payable: false,</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> stateMutability: "nonpayable",</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> type: "function"</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> }],</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> address: undefined,</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> transactionHash: "0x42878f04878dd33dbb6969d72ff48385ed2c050e867def4b2b1c3536d8ec9f85"</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">}</span><br />
<div>
<br /></div>
Now our contract is deployed to the Ethereum development network. But it's not alive yet: Its address is still undefined!<br />
<h2>
8. Activate and test the Contract</h2>
<div>
What we've done in the step before is telling the Ethereum network that we want to execute a transaction which creates our contract as an executable unit of code in the network. Now it's up to the miners to decide when and where this transaction will be executed. In real life they would take this decision based on the amount of gas we provided. But since we are in the test net, and we currently have only one miner, our transaction will be executed anyway! So let's start mining again:</div>
<div>
<br /></div>
<div>
<div>
<div style="background-color: #1c793d; width: 653px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace;">> </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">miner.start()</span></div>
</div>
</div>
<br />
After a few seconds check the contract instance again:<br />
<br />
<div>
<div style="background-color: #1c793d; width: 653px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace;">> </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">MyContractInstance</span></div>
</div>
<br />
It should have an address set now! So our contract is alive and we can test it.<br />
But first let's stop mining:<br />
<br />
<div>
<div style="background-color: #1c793d; width: 653px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace;">> </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">miner.stop()</span></div>
</div>
<br />
Then we call the <span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">reflect</span> method of our contract:<br />
<br />
<div>
<div style="background-color: #1c793d; width: 653px;">
<span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace;">> </span><span style="color: #fff2a3; font-family: "courier new" , "courier" , monospace; font-size: x-small;">MyContractInstance.reflect.call("I'm alive!")</span></div>
</div>
<br />
And voilĂ : Your contract tells you that it is alive!<br />
<br />
If you wonder why we had to add <span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">call</span> to the actual method name, you will find the answer <a href="https://ethereum.gitbooks.io/frontier-guide/content/interacting_contract.html" target="_blank">here</a>.<br />
<br />
Congratulations! You just implemented your first Ethereum contract!<br />
<br />
<br />
<br /></div>
Anonymoushttp://www.blogger.com/profile/09420743738560302691noreply@blogger.com15tag:blogger.com,1999:blog-8097245354602487605.post-19936797421804657612017-11-17T20:02:00.001+01:002017-11-18T16:38:28.754+01:00Installing a Solidity Development Environment for Ethereum Contract programmingThis is a step by step tutorial to prepare your Mac for the development of Ethereum Smart Contracts in Solidity.<br />
<br />
We assume you have a fresh macOS installation, with no development tools and no Ethereum software (like a wallet app) installed. It is always a good idea to do development in an isolated environment which is not used for any other purpose.<br />
<br />
<h2>
1. Install homebrew</h2>
<div>
<a href="https://brew.sh/" target="_blank">Homebrew</a> is the packet manager for macOS you will need for installation of the most tools we use throughout this tutorial.</div>
<div>
<br /></div>
<div>
To install homebrew issue this command in terminal:</div>
<div>
<br /></div>
<div>
<div style="background-color: black; color: white; font-family: "courier new" , "courier" , monospace; width: 100%;">
<span style="font-size: x-small;">$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"</span></div>
<br />
The installation requires some interaction from you. So watch progress and enter the information requested!<br />
<br />
<h2>
2. Install Ethereum</h2>
Now that homebrew is installed, we will use it to <a href="https://github.com/ethereum/go-ethereum/wiki/Installation-Instructions-for-Mac" target="_blank">install the latest version of Ethereum</a>:<br />
<br />
<div style="background-color: black; width: 653px;">
<div>
<span style="color: white; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ brew tap ethereum/ethereum</span></div>
</div>
<br />
and then:<br />
<br />
<div>
<div style="background-color: black; width: 653px;">
<span style="color: white; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ brew tap ethereum/ethereum</span></div>
</div>
<div>
<span style="color: white; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
This will as well install one of the most important tools for our development plans: <a href="https://github.com/ethereum/go-ethereum/wiki/geth" target="_blank">geth</a>, the <a href="https://golang.org/" target="_blank">go</a> command line interface for Ethereum.<br />
<br />
Just check it by issuing<br />
<br />
<div>
<div style="background-color: black; width: 653px;">
<span style="color: white; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ geth</span></div>
</div>
</div>
<div>
<span style="color: white; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
If everything went right, geth will start up and begin synchronizing the Ethereum blockchain to your Mac. As we don't want this by now, enter [CTRL]+[C] in the terminal window running geth. Just ignore the errors popping up, if any!</div>
<h2>
3. Install the Solidity Compiler</h2>
<div>
<a href="http://solidity.readthedocs.io/en/develop/index.html" target="_blank">Solidity</a> is the programming language of choice for implementing smart contracts on the Ethereum network. In order to be able to run our contracts, we have to compile them. So we need the compiler:</div>
<div>
<br /></div>
<div>
<div>
<div style="background-color: black; width: 653px;">
<span style="color: white; font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ brew install solidity</span></div>
</div>
</div>
<div>
<span style="color: white; font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
Depending on the power of your Mac it might take a while for the installation to complete. Even if it lingers around an installation step (e.g. installing "boost") for several minutes (or even hours): Just be patient and wait! It will finish! I suggest spending your time watching the CPU load in Activity Monitor.</div>
<div>
<br /></div>
<div>
Congratulations! Now you're up and running to start your own Ethereum development network and start implementing your first smart contract!<br />
<br />
So please proceed to the next part of this tutorial: <a href="http://www.joobik.com/2017/11/getting-started-with-private-ethereum.html">Getting started with a private Ethereum Blockchain and Solidity Contract Development on geth 1.6 or higher </a></div>
<div>
<br /></div>
<div>
</div>
<div>
<br /></div>
Anonymoushttp://www.blogger.com/profile/09420743738560302691noreply@blogger.com74tag:blogger.com,1999:blog-8097245354602487605.post-14076565907675906952015-07-07T08:35:00.000+02:002015-07-07T08:35:02.790+02:00How to enable JetBrains WebStorm Web Development Features in IntelliJ Idea<br />
JetBrains offer a rich variety of Integrated Development Environment targeted towards several different development languages and platforms, such as PHP, Python, .NET, iOS / OS X, and more.<br />
<br />
Their <a href="https://www.jetbrains.com/webstorm/" target="_blank">WebStorm</a> IDE is one of the most popular, <a href="http://www.oio.de/public/opensource/ide-html5-css3-js/IDE-Vergleich_hell.png" target="_blank">feature-rich</a> commercial Web IDEs on the market, supporting HTML, CSS, Client-Side JavaScript, node.js, and much more.<br />
<div style="-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; margin: 0px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px;">
<br /></div>
On the other hand, JetBrains <a href="https://www.jetbrains.com/idea/" target="_blank">IntelliJ Idea</a> is one of the most popular, feature-rich commercial Java IDEs on the market, supporting Scala and Groovy as well. It is the base, for instance, of <a href="https://developer.android.com/tools/studio/index.html" target="_blank">Android Studio</a> - The official Android Development Platform.<br />
<br />
Most (if not all) of JetBrain's IDEs are based on the same core, featured by different sets of installed plugins. This makes it easy to put all the WebStorm functionality into IntelliJ IDEA by just installing the appropriate plugins. To do so, just open IDEAs preferences and select the plugins pane:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCUlU38WJ8TsjmuzImfP3SP19CQUeQf0ENHfNZAZJsqLNYLGrds8fQ18pTc-ubOFP0V6HPrUCsrVe2u8c859FxasokjLbWVK2H20tNFsVj5UOBKUTx4zLalZpnDmNKNtll8BTUmphaNA_H/s1600/intellij+prefs.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="412" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCUlU38WJ8TsjmuzImfP3SP19CQUeQf0ENHfNZAZJsqLNYLGrds8fQ18pTc-ubOFP0V6HPrUCsrVe2u8c859FxasokjLbWVK2H20tNFsVj5UOBKUTx4zLalZpnDmNKNtll8BTUmphaNA_H/s640/intellij+prefs.png" width="640" /></a></div>
<br />
Click <i>Install JetBrains plugin</i> and type the plugin name to find it. If a specific plugin is not available in the JetBrains repository, use the <i>Browse repositories</i> button to find it.<br />
<br />
Based on a full IntelliJ IDEA Ultimate 14 installation you just need to load these few plugins:<br />
<br />
<br />
<ul>
<li>AngularJS</li>
<li>Cucumber.js</li>
<li>Dart</li>
<li>EJS</li>
<li>File Watchers</li>
<li>Handlebars/Mustache</li>
<li>Jade</li>
<li>JSTestDriver Plugin</li>
<li>Karma</li>
<li>Meteor</li>
<li>PhoneGap/Cordova Plugin</li>
<li>Polymer & Web Components</li>
<li>TextMate bundles support</li>
</ul>
<br />
<div>
Just in case you missed something, here's the complete list of all plugins installed in WebStorm:</div>
<br />
<div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2Rers8oLxO2WQqKELtslwykXpMTXpDF82dz7ufvxYA3F2jvIv-frxKvk2Qv1swphQhxdwmAm3kipLRD7blhDUb3H8DxXwY4NwIZsJNC53cnuu1jdtIHueVkOlfJqXHrcFicdenWuhqSud/s1600/WebStorm+Plugins.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2Rers8oLxO2WQqKELtslwykXpMTXpDF82dz7ufvxYA3F2jvIv-frxKvk2Qv1swphQhxdwmAm3kipLRD7blhDUb3H8DxXwY4NwIZsJNC53cnuu1jdtIHueVkOlfJqXHrcFicdenWuhqSud/s1600/WebStorm+Plugins.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">All Plugins enabled in JetBrains WebStorm</td></tr>
</tbody></table>
<br /></div>
Anonymoushttp://www.blogger.com/profile/09420743738560302691noreply@blogger.com215tag:blogger.com,1999:blog-8097245354602487605.post-87732954784768255132015-06-30T20:05:00.001+02:002015-06-30T22:02:17.663+02:00How to fix: Mozilla Firefox opens Bing instead of Homepage every time a new Tab is openedIf you find Firefox suddenly opening Bing (or probably another unwanted web site) whenever you open a new tab, it is very likely that you became a victim of some kind of malware. The very popular PDFCreator software and printer driver, for example, changes Firefox settings during install, and installs additional "tools", if you do not opt-out explicitly:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXWkgZyT2BEWkxV0L076Vhf19naRkAJl4cxIRydgJRujlZLrgYdDWQQ5lekyRQHqFkcjYvbDHzxUAq73okSq9AYc5zzAVi4tgp9wdZhS9AKJIO2a7r81Um3fwwTyGvjgpepqX31S58ddp2/s1600/PDF+Creator+Setup+Options.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="311" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXWkgZyT2BEWkxV0L076Vhf19naRkAJl4cxIRydgJRujlZLrgYdDWQQ5lekyRQHqFkcjYvbDHzxUAq73okSq9AYc5zzAVi4tgp9wdZhS9AKJIO2a7r81Um3fwwTyGvjgpepqX31S58ddp2/s400/PDF+Creator+Setup+Options.png" width="400" /></a></div>
<br />
So make sure you uncheck the <i>Block dangerous websites by installing Ad-Aware Web Companion </i>and <i>Set Search powered by Bing as my homepage, newtabs and default search engine on Internet Explorer, Firefox</i> check boxes in PDFCReator's installation wizard!<br />
<br />
But even if you let the installer hijack you browser, everything is not lost! It is not too hard to get rid of all the programs and settings PDFCreator kindly installed for you!<br />
<br />
Ad-Aware Web Companion can simply be uninstalled from Window's Programs and Features Control Panel:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEje_sz9SVSukVS7FCnTMBVqhMeYaOzcZ6v15X1WWvJhse3KTLTer6JeeMe7OSlcAm1NKO0_OTpiSStrKInwFdB8gQKCLO8Dc47enVbsU1hyxWXtDj1D6cT3isGiW4UuuBnx-F8tQ5c-X6j0/s1600/Web+Companion+Uninstall.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="249" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEje_sz9SVSukVS7FCnTMBVqhMeYaOzcZ6v15X1WWvJhse3KTLTer6JeeMe7OSlcAm1NKO0_OTpiSStrKInwFdB8gQKCLO8Dc47enVbsU1hyxWXtDj1D6cT3isGiW4UuuBnx-F8tQ5c-X6j0/s400/Web+Companion+Uninstall.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
During uninstall Web Companion kindly asks you whether you would like it to undo all the damage it did to your system during installation:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPMQ4_qErDjykZlN5zN0swtIj-ma7RHHkZRa1JfoCU5pPiom_m8w2pTe3o1XJiLspW33w14-cRWr1cDFZaFXivP2SWytewfap4yYxMgoR1YsyMNaKNQbupImdwYwL_rQq3sFv2UANofWvx/s1600/Web+Companion+Uninstaller.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="310" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPMQ4_qErDjykZlN5zN0swtIj-ma7RHHkZRa1JfoCU5pPiom_m8w2pTe3o1XJiLspW33w14-cRWr1cDFZaFXivP2SWytewfap4yYxMgoR1YsyMNaKNQbupImdwYwL_rQq3sFv2UANofWvx/s400/Web+Companion+Uninstaller.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
So you should check both <i>Restore</i> check boxes and click the <i>Remove</i> button. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
What you will find is, that the new tab in Firefox will work as usual again. But your search settings remain hijacked to Bing! So lets fix them manually.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Open Firefox Options and select the <i>Search</i> page:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVoPXVYbDBSuq2O6EJsnnSfiT4iNvS8hRRJnxlT0FhsKmOqNH8Ic50Je810k3_t1hPU9hBYvDHUqpk4MSAn1RJ49tINpIFMZeI6YkMfzLrzOxlrVOnWoCDJvlPR-fTUI5fGzmvtlEkf000/s1600/FF-Options-Search.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="387" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVoPXVYbDBSuq2O6EJsnnSfiT4iNvS8hRRJnxlT0FhsKmOqNH8Ic50Je810k3_t1hPU9hBYvDHUqpk4MSAn1RJ49tINpIFMZeI6YkMfzLrzOxlrVOnWoCDJvlPR-fTUI5fGzmvtlEkf000/s640/FF-Options-Search.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
As you can see, the only search engine available is Bing! </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now go an click the <i>Add more search engines</i> link at the bottom. This will take you to the Mozilla Firefox Add-Ons page where you can select additional search engines. We will install DuckDuckGo Plus, so we type the word "duck" into the search field:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9jslcleJJ9eKFb7m2hmEUlfRDco64AXulQtvqe6d7FEK1ZJ2r9smFkBVdlD24r_GpkmeL04kvW-4KhTmcpQcNVYNZ4P3cZSwiwWMPFAjblfV33FqpCYYoRcmIOhxT-krLb8Oau4V6qDA3/s1600/Duck+Search+Addon.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9jslcleJJ9eKFb7m2hmEUlfRDco64AXulQtvqe6d7FEK1ZJ2r9smFkBVdlD24r_GpkmeL04kvW-4KhTmcpQcNVYNZ4P3cZSwiwWMPFAjblfV33FqpCYYoRcmIOhxT-krLb8Oau4V6qDA3/s640/Duck+Search+Addon.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
After selecting <i>DuckDuckGo Plus</i> from the dropdown, we are taken to the download page:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvErM_i3GhQOm1pVmQtw0rCPhto0Szaop6_VyZPqvF-eCuHATkpGb4gFm1QqsEsOLwgxSTtqVeWG2y8f5byBqP_58_cTUsO6ptn_oU0JB-7ay46TElYIgTDLIY0UXEJMpqPcsLvOLuajH4/s1600/DuckDuckGoPlus+Addon.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvErM_i3GhQOm1pVmQtw0rCPhto0Szaop6_VyZPqvF-eCuHATkpGb4gFm1QqsEsOLwgxSTtqVeWG2y8f5byBqP_58_cTUsO6ptn_oU0JB-7ay46TElYIgTDLIY0UXEJMpqPcsLvOLuajH4/s640/DuckDuckGoPlus+Addon.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now click <i>Add to Firefox, </i>follow the instructions, and then open Firefox options again. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHilspj07JL3MxErV68KcOxsRrczA9nTD0HjCwgXsH-VxVpSRZ-diHKOXxDOfshyZz2p5efIfJqU9nC9zbFJmfWesJhzjV6YdnSxoOFUKebwVMehy4J2d2fioOMy6IHmp9ZECNEhxPc8Dw/s1600/Search+Prefs+Duck.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="432" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHilspj07JL3MxErV68KcOxsRrczA9nTD0HjCwgXsH-VxVpSRZ-diHKOXxDOfshyZz2p5efIfJqU9nC9zbFJmfWesJhzjV6YdnSxoOFUKebwVMehy4J2d2fioOMy6IHmp9ZECNEhxPc8Dw/s640/Search+Prefs+Duck.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now select DuckDuckGo as your preferred search engine. That's it!</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Last but not least: Just in case you need to fix the hijacked newtab manually, open Firefox and type "about:config" in its address bar.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTIyTThF97EonYZZz4lXHZIhHiH-ioFn1ghgwN8nzCG87gTUTMdqRy2DI86QP6BrXZvlQJAAARwzRtFNWUp2qkfE5iCtDYrtotIakbCIZ6Xu2Mn82OVNBGQdQtLOTqze8b3cR1p7W-CSF7/s1600/config-warning.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="339" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTIyTThF97EonYZZz4lXHZIhHiH-ioFn1ghgwN8nzCG87gTUTMdqRy2DI86QP6BrXZvlQJAAARwzRtFNWUp2qkfE5iCtDYrtotIakbCIZ6Xu2Mn82OVNBGQdQtLOTqze8b3cR1p7W-CSF7/s640/config-warning.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
If you see a void warranty warning like the one shown above, just click <i>I'll be careful, I promise!</i></div>
<div class="separator" style="clear: both; text-align: left;">
<i><br /></i></div>
<div class="separator" style="clear: both; text-align: left;">
Now type "browser.newtab.url" into the search field:</div>
<div class="separator" style="clear: both; text-align: left;">
<i><br /></i></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYTQapjuTtLmSMbsMWkVw1uxIX6pWgzbTdhBemMH6M4EV-I4xOSPeTolfL37AKSaiTmtOu1_X8YVl50O8yhlA0TBEEhkfI7Z-ugeSyytDjLRYXLLmPhpQhzi9gAhhImIwha9jat56KUBMW/s1600/about-newtab-bing.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="84" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYTQapjuTtLmSMbsMWkVw1uxIX6pWgzbTdhBemMH6M4EV-I4xOSPeTolfL37AKSaiTmtOu1_X8YVl50O8yhlA0TBEEhkfI7Z-ugeSyytDjLRYXLLmPhpQhzi9gAhhImIwha9jat56KUBMW/s640/about-newtab-bing.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<i><br /></i></div>
As you can see, the url for a new browser tab is set to something at bing.com. Just double-click the entry and change the URL to whatever you want!<br />
<br />
If you want new tabs to show a blank page, enter: "about:blank".<br />
<br />
If you want the standard new tab page with tiles of your favourite sites, enter: "about:newtab".<br />
<br />
If you want to support Joobik Player, enter: "<a href="http://www.joobikplayer.com/" target="_blank">http://www.joobikplayer.com</a>"<br />
<br />
<br />
<br />Anonymoushttp://www.blogger.com/profile/09420743738560302691noreply@blogger.com14tag:blogger.com,1999:blog-8097245354602487605.post-33164936500736639062015-04-14T10:43:00.002+02:002015-06-14T11:20:12.334+02:00Fixing Xcode 6.3 (iOS SDK) Error: Could not load NIB in bundle After the recent update of <a href="https://geo.itunes.apple.com/app/xcode/id497799835?mt=12&uo=6&at=1000l3gk" target="_blank">Xcode</a> to version 6.3 iOS developers reported to encounter exceptions of kind<br />
<br />
<br />
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: Could not load NIB in bundle: ...</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></span></div>
<div class="p1">
followed by the path to the running iPhone or iPad application, and the name of the NIB file the it was trying to load. These exceptions appear to fire at runtime only, not at compile time. So make sure you test your iOS applications completely after building them with <a href="https://geo.itunes.apple.com/app/xcode/id497799835?mt=12&uo=6&at=1000l3gk" target="_blank">Xcode</a> 6.3!</div>
<div class="p1">
<br /></div>
<div class="p1">
The reason for this issue seems to be a bug of <a href="https://geo.itunes.apple.com/app/xcode/id497799835?mt=12&uo=6&at=1000l3gk" target="_blank">Xcode</a> 6.3 when compiling XIB files using <a href="https://developer.apple.com/library/ios/recipes/xcode_help-IB_adaptive_sizes/chapters/EnablingAdaptiveSizeDesign.html" target="_blank">size classes</a>. Size classes is a concept introduced with iOS 8 which enables you to define view layouts for different UI orientations and different iPhone and iPad devices within a single Interface Builder document. A very good introduction to size classes is given at <a href="http://adoptioncurve.net/archives/2014/08/working-with-size-classes-in-interface-builder/" target="_blank">adaptioncurve.net</a>.</div>
<div class="p1">
<br /></div>
<div class="p1">
So let's have a look at a little example to elaborate the problem! </div>
<div class="p1">
<br /></div>
<div class="p1">
We have an <a href="https://geo.itunes.apple.com/app/xcode/id497799835?mt=12&uo=6&at=1000l3gk" target="_blank">Xcode</a> project with the deployment target set to iOS 7 and Universal device support:</div>
<div class="p1">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj00A5TawrIOQzj2ryxwb1Nutk5H6CIem53s8sdRiHGdInp8oBTSXC_3KDulmTjwPquinJmCCLFCYOiJqEKL48J0hPczUQh7xLKo_CWwJVD_m7sWhFzIkBK8YtdTZb6_UgCJkdhf_knB0zZ/s1600/Project+Setup.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="126" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj00A5TawrIOQzj2ryxwb1Nutk5H6CIem53s8sdRiHGdInp8oBTSXC_3KDulmTjwPquinJmCCLFCYOiJqEKL48J0hPczUQh7xLKo_CWwJVD_m7sWhFzIkBK8YtdTZb6_UgCJkdhf_knB0zZ/s1600/Project+Setup.png" width="400" /></a></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
We have two XIB files: TestSizeClasses.xib is targeted to iPhone and iPad. TestSizeClassesIphone~iphone.xib is named according to <a href="https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/LoadingResources/Introduction/Introduction.html#//apple_ref/doc/uid/10000051i-CH1-SW2" target="_blank">Apple's conventions</a> to be targeted to iPhone only:</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5JtC2oT85fLSBQpyfIUFnvueqw0usqFw-rWyiVMx6ZnhUlwHwXuxwbbm3p_u-f91iqRYohoihINZ9H1pWQUZcHZjAxUxVDQ4BjHi4JPhhtZjxV17mqS2JrkhYSS22bY9EwchYV-XJMUl-/s1600/Xcode+6.3+Size+Classes+Project.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="104" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5JtC2oT85fLSBQpyfIUFnvueqw0usqFw-rWyiVMx6ZnhUlwHwXuxwbbm3p_u-f91iqRYohoihINZ9H1pWQUZcHZjAxUxVDQ4BjHi4JPhhtZjxV17mqS2JrkhYSS22bY9EwchYV-XJMUl-/s1600/Xcode+6.3+Size+Classes+Project.png" width="200" /></a></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
Both XIB files have size classes enabled:</div>
<div class="p1">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwwVv8gRCuifb5leLR6ODPjt7gsIRwvuqf1-guC-YHSP9XALgEiowJv5wZ4Xb2WPtcxSGD_30UBIrynZlCRHIcFEeZewYekUomK5g-196zY3WGGDkBJI9qe9eceeyug8I8ka2IKBMVgR69/s1600/XIB+Config.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwwVv8gRCuifb5leLR6ODPjt7gsIRwvuqf1-guC-YHSP9XALgEiowJv5wZ4Xb2WPtcxSGD_30UBIrynZlCRHIcFEeZewYekUomK5g-196zY3WGGDkBJI9qe9eceeyug8I8ka2IKBMVgR69/s1600/XIB+Config.png" width="191" /></a></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
After compiling these files with <a href="https://geo.itunes.apple.com/app/xcode/id497799835?mt=12&uo=6&at=1000l3gk" target="_blank">XCode</a> 6.2, and running them in Simulator let's have a look at the NIB files created at compile time. You will find these NIBs in your user directory under a path of this structure:</div>
<div class="p1">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">~/Library/Developer/CoreSimulator/Devices/<i><cryptic_device_number></i>/data/Containers/Bundle/Application/<i><cryptic_app_number></i>/<i><app_name></i>.app</span></div>
<div class="p1">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<div class="p1">
<span style="font-family: inherit;">In order to identify the correct cryptic number directory, just sort directories by modification date and choose the last modified one.</span></div>
<div class="p1">
<span style="font-family: inherit;"><br /></span></div>
<div class="p1">
<span style="font-family: inherit;"><a href="https://geo.itunes.apple.com/app/xcode/id497799835?mt=12&uo=6&at=1000l3gk" target="_blank">Xcode</a> 6.2 created these three NIB files:</span></div>
<div class="p1">
<span style="font-family: inherit;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiakN8HEAj3mUwlcIqAnefUfnnFJhXmsX60boMVIjMJVOc9qG47bNVohun-FqPhZPKx-M9M3TQzGKwdPKUYTYSp-g1zJyuBtLfwpASP5UZ3KKDGf-19K1SPC9c-gO8sxHpkmA99kex3Gti2/s1600/Size+Classes+Xcode+6.2+Deployment.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="40" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiakN8HEAj3mUwlcIqAnefUfnnFJhXmsX60boMVIjMJVOc9qG47bNVohun-FqPhZPKx-M9M3TQzGKwdPKUYTYSp-g1zJyuBtLfwpASP5UZ3KKDGf-19K1SPC9c-gO8sxHpkmA99kex3Gti2/s1600/Size+Classes+Xcode+6.2+Deployment.png" width="400" /></a></div>
<div class="p1">
<span style="font-family: inherit;"><br /></span></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
TestSizeClasses.xib was split into two device specific NIB files, but TestSizeClassesIphone~iphone.xib was compiled to a single, iPhone specific NIB file because the '~' - part of the file name signals to the compiler that we care about device specific layouts by ourselfs. So everything is fine!</div>
<div class="p1">
<br /></div>
<div class="p1">
Now lets compile the same files with <a href="https://geo.itunes.apple.com/app/xcode/id497799835?mt=12&uo=6&at=1000l3gk" target="_blank">Xcode</a> 6.3 and have a look at the results:</div>
<div class="p1">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK__OE6_hF_AaWAZtAIh2yznGGBRksNl1rgCr3XgohuY1AzDiD0aTt2dChLOf3-nCXDBfIP7iGgb9qY7-B3rbcF7TM_DvFSpJx-Er285drxJB0-k8qgTJilwP6lbgaiI3LjvHEHACMDnst/s1600/Xcode+6.3+Size+Classes+Deployment.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="42" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK__OE6_hF_AaWAZtAIh2yznGGBRksNl1rgCr3XgohuY1AzDiD0aTt2dChLOf3-nCXDBfIP7iGgb9qY7-B3rbcF7TM_DvFSpJx-Er285drxJB0-k8qgTJilwP6lbgaiI3LjvHEHACMDnst/s1600/Xcode+6.3+Size+Classes+Deployment.png" width="400" /></a></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
As you can see, <a href="https://geo.itunes.apple.com/app/xcode/id497799835?mt=12&uo=6&at=1000l3gk" target="_blank">Xcode</a> appends another '~iphone' part to the name of TestSizeClassesIphone~iphone.nib, although we wanted it to leave our file name alone! So this is the bug in Xcode 6.3 XIB processing which will lead to runtime 'could not load nib' exceptions when your app tries to load the badly named nib file. </div>
<div class="p1">
<br /></div>
<div class="p1">
The bug will haunt you when you have size classes enabled for a XIB file, and the deployment target of your <a href="https://geo.itunes.apple.com/app/xcode/id497799835?mt=12&uo=6&at=1000l3gk" target="_blank">Xcode</a> project is set to something earlier than iOS 8. Because size classes are only supported in iOS 8.0 and later, <a href="https://geo.itunes.apple.com/app/xcode/id497799835?mt=12&uo=6&at=1000l3gk" target="_blank">Xcode</a> will compile the old device specific nib files automatically for older iOS versions. It doesn't matter whether your app is universal or targeted to iPad or iPhone only. As soon as you name a XIB device specific using the '~', your app will crash.</div>
<div class="p1">
<br /></div>
<div class="p1">
Now that we know the reasons for this exception, we have four options to handle it:<br />
<br />
<br /></div>
<div class="p1">
<script language="javascript" type="text/javascript">
amzn_assoc_ad_type = "contextual";
amzn_assoc_tracking_id = "joobikcom-20";
amzn_assoc_marketplace = "amazon";
amzn_assoc_region = "US";
amzn_assoc_placement = "OUMA5OFNJ6UHSOXF";
amzn_assoc_linkid = "OUMA5OFNJ6UHSOXF";
amzn_assoc_emphasize_categories = "13900861, 2335752011, 13900871, 130, 172282, 979455011, 195209011, 301668, 229534, 468642, 377110011";
amzn_assoc_fallback_products = "";
amzn_assoc_width = "300";
amzn_assoc_height = "250";
</script>
<script language="javascript" src="//z-na.amazon-adsystem.com/widgets/q?ServiceVersion=20070822&Operation=GetScript&ID=OneJS&WS=1&MarketPlace=US&source=ac" type="text/javascript"></script>
</div>
<div class="p1">
<br /></div>
<div class="p1">
<b>Option 1: Target to iOS 8.0 or later </b></div>
<div class="p1">
<br /></div>
<div class="p1">
The simplest option would be to target your app to iOS 8 or later, thus the device specific NIB files would just not be created. But if you want to support older iOS versions, this is not an option for you.</div>
<div class="p1">
<br /></div>
<div class="p1">
<b>Option 2: Use storyboards instead of XIB files</b></div>
<div class="p1">
<b><br /></b></div>
<div class="p1">
If you can afford to make the effort, migrate all your XIBs to storyboards. These will be compiled correctly by <a href="https://geo.itunes.apple.com/app/xcode/id497799835?mt=12&uo=6&at=1000l3gk" target="_blank">Xcode</a> 6.3.</div>
<div class="p1">
<br /></div>
<div class="p1">
<b>Option 3: Disable Size Classes</b></div>
<div class="p1">
<br /></div>
<div class="p1">
When you disable size classes for a XIB file, <a href="https://geo.itunes.apple.com/app/xcode/id497799835?mt=12&uo=6&at=1000l3gk" target="_blank">Xcode</a> will force you to target this file to a specific device and will remove all data it thinks will not be of use to represent this device:</div>
<div class="p1">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuWkQ7W1RWlylQKSVZnE8eGv2X1mIa-Jlw6HNM9tQt3skZIPkQRWOa-30ypPMQ_Bl5cIqT-_lL9Pstnrd3M7UZQhTZ8Y8B9fAzansZRjzOUdUBuM4azfE-eQCuMoNoNGuHfcToND1lGFMk/s1600/Disable+Size+Classes.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuWkQ7W1RWlylQKSVZnE8eGv2X1mIa-Jlw6HNM9tQt3skZIPkQRWOa-30ypPMQ_Bl5cIqT-_lL9Pstnrd3M7UZQhTZ8Y8B9fAzansZRjzOUdUBuM4azfE-eQCuMoNoNGuHfcToND1lGFMk/s1600/Disable+Size+Classes.png" width="320" /></a></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
So choose this option only when you absolutely trust in that <a href="https://geo.itunes.apple.com/app/xcode/id497799835?mt=12&uo=6&at=1000l3gk" target="_blank">Xcode</a> will not remove anything you need from your XIB files. As a rule of thump: If all layout constraints in a XIB apply to all size classes, you are safe. If different constraints apply to different size classes, think twice!</div>
<div class="p1">
<br /></div>
<div class="p1">
<b>Option 4: Handle device specific XIBs in code</b></div>
<div class="p1">
<b><br /></b></div>
<div class="p1">
This is the less destructive of all options and it is not as expensive to implement as it might seem! All you have to do is to name your XIB device specific by avoiding Apple's naming conventions (the '~'), and add very few lines of code to load the correct NIBs.</div>
<div class="p1">
<br /></div>
<div class="p1">
So we rename our TestSizeClassesIphone~iphone.xib to TestSizeClasses-Iphone.xib. We create another TestSizeClasses-Ipad.xib to cover all devices. And we create a single TestSizeClassesViewController, which we set the file's owner of both XIB files:</div>
<div class="p1">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNx552TaIMu5Wzl8M749mINj-ktvaluxSr-bg1-Dv1QxNc6Lw094c3_Iwi6JLcqomJNeXC9nlYQen5vDHt8vgzfV04tpxzCmEFEBbiQA5ez3I0V4rH9QILiNWhAVNZ4VY7DJuoe3CKBcZV/s1600/TestSizeClassesViewController.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNx552TaIMu5Wzl8M749mINj-ktvaluxSr-bg1-Dv1QxNc6Lw094c3_Iwi6JLcqomJNeXC9nlYQen5vDHt8vgzfV04tpxzCmEFEBbiQA5ez3I0V4rH9QILiNWhAVNZ4VY7DJuoe3CKBcZV/s1600/TestSizeClassesViewController.png" width="640" /></a></div>
<div style="text-align: left;">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
After compiling the code, we'll find the following NIBs:<br />
<div>
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4nVuKTiw9I6g3WJ7HAFvl2DOVavxT9Fz_SX5dKZVWFkh9BI_NjlqfsfuLmkR-BnHpq3D7xFmcMEYkpyEl1X5YGLqEBb5QTtwIip0BcewHy2nxNhKquZntVzKD77QH5cVkBTejzUXB7Qbu/s1600/New+Size+Classes+Deployment.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="95" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4nVuKTiw9I6g3WJ7HAFvl2DOVavxT9Fz_SX5dKZVWFkh9BI_NjlqfsfuLmkR-BnHpq3D7xFmcMEYkpyEl1X5YGLqEBb5QTtwIip0BcewHy2nxNhKquZntVzKD77QH5cVkBTejzUXB7Qbu/s1600/New+Size+Classes+Deployment.png" width="400" /></a></div>
<br />
<br /></div>
<div class="p1">
<br />
<br />
<br />
<br />
<br />
As you can see, <a href="https://geo.itunes.apple.com/app/xcode/id497799835?mt=12&uo=6&at=1000l3gk" target="_blank">Xcode</a> created both, an ~iphone version and an ~ipad version of all of our NIB files. Now all we have to do is to tweak our Objective-C code to load the correct NIB version per device.<br />
<br />
So open TestSizeClassesViewController and implement its init method to load device specific nib files:<br />
<br />
<div class="p1">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="s1">- (</span><span class="s2">id</span><span class="s1">)init</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span></span></div>
<div class="p2">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="s3"> </span><span class="s2">if</span><span class="s3"> (</span><span class="s1">UI_USER_INTERFACE_IDIOM</span><span class="s3">() == </span><span class="s1">UIUserInterfaceIdiomPad</span><span class="s3">)</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> {</span></span></div>
<div class="p3">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="s3"> </span><span class="s2">return</span><span class="s3"> [</span><span class="s2">self</span><span class="s3"> </span><span class="s4">initWithNibName</span><span class="s3">:</span><span class="s1">@"TestSizeClasses-iPad"</span><span class="s3"> </span><span class="s4">bundle</span><span class="s3">:</span><span class="s2">nil</span><span class="s3">];</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span></span></div>
<div class="p1">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="s1"> </span><span class="s2">else</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> {</span></span></div>
<div class="p4">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="s3"> </span><span class="s2">return</span><span class="s3"> [</span><span class="s2">self</span><span class="s3"> </span><span class="s1">initWithNibName</span><span class="s3">:</span><span class="s5">@"TestSizeClasses-iPhone"</span><span class="s3"> </span><span class="s1">bundle</span><span class="s3">:</span><span class="s2">nil</span><span class="s3">];</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> }</span></span></div>
<br />
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: inherit;">Do the same in all places of your code where the view controller is instantiated directly using initWithNibName:</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: inherit;"><br /></span></span></div>
<div class="p1">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">...</span></div>
<div class="p1">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">TestSizeClassViewController* sizeClassController; </span></div>
<div class="p2">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="s2">if</span><span class="s3"> (</span><span class="s1">UI_USER_INTERFACE_IDIOM</span><span class="s3">() == </span><span class="s1">UIUserInterfaceIdiomPad</span><span class="s3">)</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span></span></div>
<div class="p3">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="s3"> </span></span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">sizeClassController =</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="s3"> [</span><span class="s2">self</span><span class="s3"> </span><span class="s4">initWithNibName</span><span class="s3">:</span></span></div>
<div class="p3">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="s1"> @"TestSizeClasses-iPad"</span><span class="s3"> </span><span class="s4">bundle</span><span class="s3">:</span><span class="s2">nil</span><span class="s3">];</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span></span></div>
<div class="p1">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="s2">else</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">{</span></span></div>
<div class="p4">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="s3"> </span></span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">sizeClassController =</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="s3"> [</span><span class="s2">self</span><span class="s3"> </span><span class="s1">initWithNibName</span><span class="s3">:</span></span></div>
<div class="p4">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><span class="s5"> @"TestSizeClasses-iPhone"</span><span class="s3"> </span><span class="s1">bundle</span><span class="s3">:</span><span class="s2">nil</span><span class="s3">];</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">}</span></span></div>
<br />
<div class="p1">
<span class="s1"></span></div>
<div class="p1">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">...</span></div>
<div class="p1">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<div class="p1">
This way, the app will load the TestSizeClasses-Iphone~iphone.nib and TestSizeClasses-Ipad~ipad.nib only. It will ignore the TestSizeClasses-Iphone~ipad.nib and TestSizeClasses-Ipad~iphone.nib.<br />
<br />
<br />
That's all there is about this <a href="https://geo.itunes.apple.com/app/xcode/id497799835?mt=12&uo=6&at=1000l3gk" target="_blank">Xcode</a> issue. Now it's up to you to decide which of the four options is the best for your needs.</div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.joobikplayer.com/" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;" target="_blank"><img border="0" height="93" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpHfVbuxxjroXAVl38zAvmToPZ5I1CFXgpu_R97H3UJJO_pw9DMm4hR6aAEd4wKdelqt5ytpY6FlLTQbZ4hJeeDxc7jBcfpaTMDgVbLWoXWLaEEd_VNJfSlTuY5FNaqqKgimr4NPBUIBUN/s1600/Joobik-Banner.png" width="400" /></a></div>
<div class="p1">
<br /></div>
<div>
<span class="s1"><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></span></div>
</div>
Anonymoushttp://www.blogger.com/profile/09420743738560302691noreply@blogger.com15tag:blogger.com,1999:blog-8097245354602487605.post-54909492609264791712015-03-09T09:35:00.000+01:002015-04-13T13:21:21.878+02:00One more thing.. - *** The all vintage myWatch!!! ***<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHVeOKdldHiZvYxSD64XQQTFqfCy9nuvdiH9bJ-RCYPVCFtB87CdHWuCkaZoQ1ixmjBiJMffH3x6KOYBfMk2kEFHJ9DpY33YhrH2wtcZINPrpi0fAjYjorcumlrw-STOznYk_-dhGgBM8y/s1600/myWatch.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHVeOKdldHiZvYxSD64XQQTFqfCy9nuvdiH9bJ-RCYPVCFtB87CdHWuCkaZoQ1ixmjBiJMffH3x6KOYBfMk2kEFHJ9DpY33YhrH2wtcZINPrpi0fAjYjorcumlrw-STOznYk_-dhGgBM8y/s1600/myWatch.jpg" height="320" width="240" /></a></div>
<br />
<div style="background-color: white; color: #141823; font-family: Helvetica, Arial, 'lucida grande', tahoma, verdana, arial, sans-serif; font-size: 13.63636302948px; line-height: 17.5636348724365px; margin-bottom: 6px; margin-top: 6px;">
</div>
<div style="background-color: white; color: #141823; font-family: Helvetica, Arial, 'lucida grande', tahoma, verdana, arial, sans-serif; font-size: 13.63636302948px; line-height: 17.5636348724365px; margin-bottom: 6px; margin-top: 6px;">
<span class="text_exposed_show" style="display: inline;"></span></div>
<ul>
<li><span style="font-size: 13.63636302948px; line-height: 17.5636348724365px;">The smart watch that was always there!</span></li>
<li><span style="font-size: 13.63636302948px; line-height: 17.5636348724365px;">Operates without a mobile phone in your pocket!</span></li>
<li><span style="font-size: 13.63636302948px; line-height: 17.5636348724365px;">Displays current time on its 10k++HDSuperDuperDensityRealityViewRetina(TM)-Display!</span></li>
<li><span style="font-size: 13.63636302948px; line-height: 17.5636348724365px;">Comes with pre-installed calendar app to display current date and day of week - all on a distinct tile!</span></li>
<li><span style="font-size: 13.63636302948px; line-height: 17.5636348724365px;">Makes realistic tick-tock noise with it's built-in VintageSound(TM) Signal Processor!</span></li>
<li><span style="font-size: 13.63636302948px; line-height: 17.5636348724365px;">Runs 4+ years without recharging!</span></li>
<li><span style="font-size: 13.63636302948px; line-height: 17.5636348724365px;">DIY replaceable battery pack</span></li>
<li><span style="font-size: 13.63636302948px; line-height: 17.5636348724365px;">Comes with built-in AnalogueCrown technology which lets you adjust time, date, and day of week in real time!</span></li>
<li><span style="font-size: 13.63636302948px; line-height: 17.5636348724365px;">Covered by saphire glass with a single rounded edge!</span></li>
<li><span style="font-size: 13.63636302948px; line-height: 17.5636348724365px;">Features Swipe-To-Clean gesture!</span></li>
<li><span style="font-size: 13.63636302948px; line-height: 17.5636348724365px;">Knows your pulse - but won't tell!</span></li>
</ul>
<br />
<div class="text_exposed_show" style="background-color: white; color: #141823; display: inline; font-family: Helvetica, Arial, 'lucida grande', tahoma, verdana, arial, sans-serif; font-size: 13.63636302948px; line-height: 17.5636348724365px;">
<div style="margin-bottom: 6px;">
<b>This changes nothing - again!</b><br />
<b><br /></b>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.joobikplayer.com/" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;" target="_blank"><img alt="http://www.joobikplayer.com" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0YOn-mWycY4CbxGfFplAX9JP_EnTo5EkX3_SfIE96WHKR3lyST_eKCs7HnjKzY0_z01jjeafGFqT5rE0dOGBlrXW9pSJjXnJVQB2kJAO2vT4cGZNE5Z_PX24S3kJI9gQUSjsNugBcefQk/s1600/Joobik-Banner.png" height="93" width="400" /></a></div>
<b><br /></b></div>
</div>
Anonymoushttp://www.blogger.com/profile/09420743738560302691noreply@blogger.com3tag:blogger.com,1999:blog-8097245354602487605.post-312168002107234972015-03-03T15:39:00.000+01:002015-04-28T09:10:48.169+02:00How iTunes Match does (or does not) sync Video Playlists to iPhone, iPod, and iPad<br />
<br />
When Apple first introduced iTunes Match in 2011, everyone was excited: Eventually there was an easy way of getting all those iTunes media files to synchronize between all your Macs, PCs, iPhones, iPods, and iPads seamlessly via iCloud! But after a few days of using it it became obvious that there were some very annoying drawbacks and restrictions. And many of them do still exist today.<br />
<br />
iTunes Match works best when used with music files (audio and music videos) purchased at Apples iTunes Store. It does not feel quite as comfortable with oder media kinds, especially videos. It works even worse with playlists. And it (almost) refuses to operate on media not available from the iTunes Store.<br />
<br />
So the ultimate challenge for the media enthusiast these days is to get this playlist of home videos synced from iTunes to the iPhone via iCloud! And I will try to show you in this post how this can be achieved.<br />
<br />
So lets start with the facts I found out during my research about playlists and videos in the realm of iTunes Match and iCloud. All these findings are based on iTunes 12.1 on OS X Yosemite and iOS 8.1.3 on iPod Touch 5g. There's no warranty that all or only some of these findings can be reproduced by everyone with the same or different hardware and software configuration:<br />
<div text-align: center>
<br />
<center>
<script type="text/javascript" language="javascript">
amzn_assoc_ad_type = "contextual";
amzn_assoc_tracking_id = "joobikcom-20";
amzn_assoc_marketplace = "amazon";
amzn_assoc_region = "US";
amzn_assoc_placement = "OUMA5OFNJ6UHSOXF";
amzn_assoc_linkid = "OUMA5OFNJ6UHSOXF";
amzn_assoc_emphasize_categories = "13900861, 2335752011, 13900871, 130, 172282, 979455011, 195209011, 301668, 229534, 468642, 377110011";
amzn_assoc_fallback_products = "";
amzn_assoc_width = "300";
amzn_assoc_height = "250";
</script>
<script type="text/javascript" language="javascript" src="//z-na.amazon-adsystem.com/widgets/q?ServiceVersion=20070822&Operation=GetScript&ID=OneJS&WS=1&MarketPlace=US&source=ac"></script>
</center>
</div>
<br />
<b>Finding 1: There's almost no official documentation</b><br />
<b><br /></b>
You can check which <a href="https://support.apple.com/en-en/HT5085" target="_blank">media types iTunes Match will sync in your country</a> at all. And somewhere in the F.A.Q-section of <a href="https://www.apple.com/itunes/itunes-match/" target="_blank">this page</a> you will find the statement, that <i>"playlists with <b>videos</b>, voice memos, or PDF files will not sync."</i><br />
That's it! And it's not even half of the truth, as we will see later.<br />
<br />
<b>Finding 2: iTunes Match behaves different on an iOS device and on iTunes </b><br />
<b><br /></b>
When you turn on iTunes Match in iTunes on your PC or Mac, it is still possible to select videos and playlists for local synchronization to your iOS device. iTunes will even try to tell you that these playlists are there:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixif8eRVe-YpHdZbPk51SOQ_0V3iID-nd429h2zGDgGUWAlG5UjTyNtcni0iE7fEo4kNV7gWIdD3VtcU_ggwjQNKFAJkxcreEoZ8vkvCkmnkGfcUrFFSPp9TFy4_EOmlVB9gjbTQrIAElq/s1600/01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixif8eRVe-YpHdZbPk51SOQ_0V3iID-nd429h2zGDgGUWAlG5UjTyNtcni0iE7fEo4kNV7gWIdD3VtcU_ggwjQNKFAJkxcreEoZ8vkvCkmnkGfcUrFFSPp9TFy4_EOmlVB9gjbTQrIAElq/s1600/01.png" height="340" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
BUT: When you turn on iTunes Match on an iOS device, only the videos are available in the original iOS Video or Music App - The playlists are not! </div>
<div class="separator" style="clear: both; text-align: left;">
The reason: When iTunes Match is turned on on an iOS device, this device will show only playlists available on iCloud. So in order to make some playlists appear on your device at all, you must have iTunes Match enabled on at least one of your desktop computers. Then you can check in iTunes easily if a playlist synced or not:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgc-cy81vr1DzuK57XgnBvCwiT2cFSlFa1j7N-NO6v-3cIX87eZrj1J2j0M8acp1xgr_LN4ba0pfhAth7X6e0LQLUcYbRzAM-silroPV5PnexikFz9gZa8tdMCjVl8p52AHFpS6HETFBY22/s1600/02.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgc-cy81vr1DzuK57XgnBvCwiT2cFSlFa1j7N-NO6v-3cIX87eZrj1J2j0M8acp1xgr_LN4ba0pfhAth7X6e0LQLUcYbRzAM-silroPV5PnexikFz9gZa8tdMCjVl8p52AHFpS6HETFBY22/s1600/02.png" height="135" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
When the cloud symbol is struck through, the item is not on iCloud.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br />
<b>Finding 3: iTunes Match handles Music and Music Videos different from the Rest</b><br />
<br />
Short side note: Everything just said above is not true for Music and Music Videos. These cannot be synced manually when iTunes Match is turned on on your iOS device:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXRtx9hkSK9fPdAGqdoT4ioAjyibKs3RfpSy4SgYMtm7wNtLf9Sn9KCniSCPyKv8EQ_Mdo0zi-0DJ7Pnht69eRtYdaezxHe9g7aHaP3r6VL9m2hyphenhyphenTb5cmaOCsPEPKzR2uluAKlP4chxzp_/s1600/03.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXRtx9hkSK9fPdAGqdoT4ioAjyibKs3RfpSy4SgYMtm7wNtLf9Sn9KCniSCPyKv8EQ_Mdo0zi-0DJ7Pnht69eRtYdaezxHe9g7aHaP3r6VL9m2hyphenhyphenTb5cmaOCsPEPKzR2uluAKlP4chxzp_/s1600/03.png" height="171" width="640" /></a></div>
<br />
<br />
<b>Finding 4: iTunes Match will only sync media available from the iTunes Store</b><br />
<b><br /></b>
You will only get your media files into iCloud, if the iTunes Store offers them for sale in your country. It doesn't matter whether you purchased them from Apple or not. When iTunes Match is turned on, your media library will be scanned and iTunes tries to match each of your media files with the Store. It is Apple's secret how a match would be recognized. But you can definitely say that there is no chance to ever get any of your home made videos into iCloud. You will have to sync all of these files locally from your computer to your iOS device.<br />
Whether a playlist is synced to iCloud depends on the playlist type and sync status of the items it contains. Details will be discussed in Finding 7.<br />
<br />
<b>Finding 5: It's cumbersome to check your iOS device for playlists synced to it</b><br />
<b><br /></b>
While you can use the native iOS Video App to check for all videos available on your device (whether from iCloud or not), this app will not reveal any of your playlists. <br />
The native iOS Music App will show you all playlists available on your device. Remember that - as said in Finding 2 - all of these playlists reside on iCloud. You won't be able to access local playlists with iTunes Match turned on. While all playlists are listed here, only music and music video playlists can be played from the iOS Music App. All other playlists appear to be empty:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgu8aErH9CxmZwNxcnQ-7_D0W2PIGhmWuiXiyIlu1vdsaZg6wLjng85YdQ_pFLWIv5XySTF-EYenJQKOVaRvM7XN_PTfm0Khdxzfw4hYkquj6-1qMFysAUrH5DtUeUVGYy5_RPdzOFuhxPt/s1600/04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgu8aErH9CxmZwNxcnQ-7_D0W2PIGhmWuiXiyIlu1vdsaZg6wLjng85YdQ_pFLWIv5XySTF-EYenJQKOVaRvM7XN_PTfm0Khdxzfw4hYkquj6-1qMFysAUrH5DtUeUVGYy5_RPdzOFuhxPt/s1600/04.png" height="400" width="225" /></a></div>
<br />
<br />
Use <a href="http://www.joobikplayer.com/" target="_blank">Joobik Player</a> to view the content of all playlists and play them on your iPhone, iPod, or iPad:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.joobikplayer.com/" target="_blank"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiT-D2y8pV3WV1nELpYYjbOl8SiU1spUrrJmSLg9mSGMqa0jokvCEoSkDTymoKYfS7A2y5TqQBY6nmMeb56YkS7lwHv5VufgdG-1MHbY1-wF7g2y_MdmyJC0uSSaUmTxoZ9F3xmCgEoG0jC/s1600/05.png" height="400" width="225" /></a></div>
<br />
In order for a playlist to appear in Joobik Player, the playlist itself must be synced to iCloud, but the media files must reside physically on your iOS device. I.e. if a playlist contains items from iCloud, at least one of these items must be downloaded from the cloud to your device using the native iOS Video or Music App. If a playlist contains items not available from iCloud, these items must be synced locally from iTunes to your iOS device. Detailed instructions on how to do this are given at the end of this post.<br />
<br />
<b>Finding 6: iTunes Match might not forget</b><br />
<b><br /></b>
When I turned on again iTunes Match on my iPod after several months of using only local synchronization, I was surprised to see appear several playlist that where not on my iTunes-Match-enabled Mac. The only explanation I see for this behaviour is that these lists must originate from an old computer, which I don't own anymore. So iTunes Match becomes even more confusing, when more than one Computer is involved in the synchronization pool. But this might be a topic for another blog post..<br />
<div text-align: center>
<br />
<center>
<script type="text/javascript" language="javascript">
amzn_assoc_ad_type = "contextual";
amzn_assoc_tracking_id = "joobikcom-20";
amzn_assoc_marketplace = "amazon";
amzn_assoc_region = "US";
amzn_assoc_placement = "OUMA5OFNJ6UHSOXF";
amzn_assoc_linkid = "OUMA5OFNJ6UHSOXF";
amzn_assoc_emphasize_categories = "13900861, 2335752011, 13900871, 130, 172282, 979455011, 195209011, 301668, 229534, 468642, 377110011";
amzn_assoc_fallback_products = "";
amzn_assoc_width = "300";
amzn_assoc_height = "250";
</script>
<script type="text/javascript" language="javascript" src="//z-na.amazon-adsystem.com/widgets/q?ServiceVersion=20070822&Operation=GetScript&ID=OneJS&WS=1&MarketPlace=US&source=ac"></script>
</center>
</div>
<b><br /></b><b>Finding 7: iTunes Match handles Smart Playlists different from ordinary Playlists</b><br />
<b><br /></b>
This is the most important finding because it will lead us to the solution of how to get complete playlists synced to an iOS device with iTunes Match turned on!<br />
An ordinary playlist will sync to iCloud as long as it contains only tracks that sync to iCloud as well. So adding a single home video to an ordinary playlist will remove the whole list from the cloud in iTunes 12.<br />
With Smart Playlists it's different: A Smart Playlist doesn't care about the iCloud status of the items it contains. A Smart Playlist containing only ineligible items will sync to iCloud anyway and, thus, appear on your iOS device as an empty playlist. A Smart Playlist becomes ineligible for iCloud sync only when you add the reference to another playlist to the smart playlist rules:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhp6M2ltqifQk7-brUBXW2OjW5nDUYQabw79dVfk0M7lsA3J_XpaUsY07Tc3RDIXC8fHp_xAJmHE1g3Icjb3eJY8z7Lu33UMVW0bNyFFyR3FYIJ2iImrBjtbhFJLoneBuuzhaWXqnRubC7R/s1600/06.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhp6M2ltqifQk7-brUBXW2OjW5nDUYQabw79dVfk0M7lsA3J_XpaUsY07Tc3RDIXC8fHp_xAJmHE1g3Icjb3eJY8z7Lu33UMVW0bNyFFyR3FYIJ2iImrBjtbhFJLoneBuuzhaWXqnRubC7R/s1600/06.png" height="235" width="640" /></a></div>
<br />
<b><br /></b>
<b>Putting it all toghether</b><br />
<b><br /></b>
When it's about music and music videos, you will depend on Apple's grace: Either they sync to iCloud or they don't. But all other media types can be tweaked by mixing iCloud Smart Playlists with files synchronized locally:<br />
<br />
Create a smart playlist that syncs to iCloud as described in Finding 7. If you cannot find smart rules sufficient to group all desired tracks into one smart list, just create an ordinary playlist containing these tracks and add an unique tag to the comments field (or any other meta data field) of each of the tracks on this list:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhS2OmGUiSVqm1rf2ujhAJ55Eomdqi1jgHSAO7YTSGnYNKRz3THqehxgHh-xhKA9NEzocWM8IvtJ3DFT8Fs-qWn5h8Q72kjHTa0xjozLa5qDjDGdrVtjyzOqdzoGuIJyzE4fLro2jBSBEsy/s1600/07.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhS2OmGUiSVqm1rf2ujhAJ55Eomdqi1jgHSAO7YTSGnYNKRz3THqehxgHh-xhKA9NEzocWM8IvtJ3DFT8Fs-qWn5h8Q72kjHTa0xjozLa5qDjDGdrVtjyzOqdzoGuIJyzE4fLro2jBSBEsy/s1600/07.png" height="400" width="360" /></a></div>
<br />
<br />
Create a Smart Playlist referencing this unique tag:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnfFNeN3ApzmDxfAukAtV41jTlcX1EIEmxamQKAAUPUM9wzWiq34T-WNMEWSg8GLxnLhj3pi5Az6jhewxv9rKNdZ6kOumkuly6kjW3aSpP8lwY0bWbug29H8OHYjV7ARroGyzQHB1X-_vu/s1600/09.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnfFNeN3ApzmDxfAukAtV41jTlcX1EIEmxamQKAAUPUM9wzWiq34T-WNMEWSg8GLxnLhj3pi5Az6jhewxv9rKNdZ6kOumkuly6kjW3aSpP8lwY0bWbug29H8OHYjV7ARroGyzQHB1X-_vu/s1600/09.png" height="212" width="640" /></a></div>
<br />
Now the Smart Playlist itself will sync to iCloud, while the tracks will not:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiQNLkAiJRETDOR6TVtTVnpoqj-P-5BfwlWfHdpjMQfzYQMjSe8pn-nflTkaROGewnB9ao8ovUgzZsujnTP1BJzCqQEgOo8J8NPNm_jSOhmS7nI5iUDD70vWZouSFHHXEb86lBHegvxNV4/s1600/08.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiQNLkAiJRETDOR6TVtTVnpoqj-P-5BfwlWfHdpjMQfzYQMjSe8pn-nflTkaROGewnB9ao8ovUgzZsujnTP1BJzCqQEgOo8J8NPNm_jSOhmS7nI5iUDD70vWZouSFHHXEb86lBHegvxNV4/s1600/08.png" height="152" width="640" /></a></div>
<br />
Sync the Smart Playlist locally from iTunes to your iOS device:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBGmO36dW_jaWobrdmxEbxaRWgyLswthxLLKuSSZzgkerQ_43y5SDCw8XjmPvh05XULVF7WX6TOeSTJBS9cIzOA3JH85P5m9ifYgzGqahOgzqMs_7h8V5GlerxFbVy1FNcC77MlcUnab1M/s1600/10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBGmO36dW_jaWobrdmxEbxaRWgyLswthxLLKuSSZzgkerQ_43y5SDCw8XjmPvh05XULVF7WX6TOeSTJBS9cIzOA3JH85P5m9ifYgzGqahOgzqMs_7h8V5GlerxFbVy1FNcC77MlcUnab1M/s1600/10.png" height="137" width="400" /></a></div>
<br />
Play the playlist with <a href="http://www.joobikplayer.com/" target="_blank">Joobik Player</a>:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.joobikplayer.com/" target="_blank"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiH-kYgTReD_obZ-ue-zZr4KcES1MW__lRPLlAXG2srTKwAt-ViXwwoxlp-tjd7IC-rVpYqB3VZwt5-lF_INE61To-UGurPpl9sKkDXPbM_ZZkJzyP9pCWSBY55Ic8R8ieKK6cS6nrJIVii/s1600/11.png" height="400" width="225" /></a></div>
<br />
<br />
If you want to modify the iTunes Playlist on your iPhone or iPad, just <a href="http://www.joobikplayer.com/tutorial/#copy_to_joobik" target="_blank">copy it to a Joobik Playlist</a>. With Joobik Playlists you can add, remove, and rearrange tracks.<br />
<br />
<br />Anonymoushttp://www.blogger.com/profile/09420743738560302691noreply@blogger.com46tag:blogger.com,1999:blog-8097245354602487605.post-87733415420380285472014-10-29T20:12:00.000+01:002015-04-12T16:28:32.630+02:00Joobik Video Playlist Player for iPad Online Help and F.A.Q. - Frequently Asked Questions and Howtos<div class="post-title entry-title">
<br />
<b><span style="color: #cc0000;">The F.A.Q. has been moved to the new Joobik Player website:</span> <a href="http://www.joobikplayer.com/f-a-q">http://www.joobikplayer.com/f-a-q</a></b><br />
<br />
<br />
<br />
<br />
<br />
<br />
<a href="http://www.joobikplayer.com/tutorial/" target="_blank">Read the tutorial for first steps with Joobik Player</a><br />
<br />
<b><br /></b>
<b>How To:</b><br />
<br />
<a href="http://www.joobik.com/2012/04/how-to-sync-video-playlists-to-ipad.html">How to sync video playlists from iTunes to iPod, iPhone, or iPad</a><br />
<br />
<a href="http://www.joobikplayer.com/f-a-q/#howto_airplay" target="_blank">How to use AirPlay with Joobik Player</a><br />
<br />
<a href="http://www.joobikplayer.com/f-a-q/#track_title_display" target="_blank">How to change the Duration of Track Title Display, or switch it off</a><br />
<br />
<br />
<b>Troubleshooting:</b><br />
<br />
<a href="http://www.joobik.com/2013/01/why-doesnt-joobik-player-show-all-my.html">Why doesn't Joobik Player show all my iTunes videos</a> ?<br />
<br />
<a href="http://www.joobikplayer.com/f-a-q/#drm_no_play" target="_blank">Why does Joobik Player skip some or all of my videos while playing</a>?<br />
<br />
<a href="http://www.joobik.com/2014/08/there-is-no-audio-while-playing-video.html">There is no audio while playing a video with Joobik</a><br />
<br />
<a href="http://www.joobikplayer.com/f-a-q/#not_show_unprotected" target="_blank">Why can't I see my iTunes videos in Joobik Player, even though they are not DRM protected</a>?<br />
<br />
<br />
<b>F.A.Q.</b><br />
<br />
<a href="http://www.joobikplayer.com/f-a-q/#playcount" target="_blank">Could we get play count syncing with iTunes</a>?</div>
<div class="post-title entry-title">
<br /></div>
<div class="post-title entry-title">
<a href="http://www.joobik.com/2013/01/can-joobik-player-show-folders-within.html">Can Joobik Player show folders within folders, like my playlists in itunes</a>?<br />
<br />
<a href="http://www.joobik.com/2013/01/what-does-joobik-mean.html">What does Joobik mean</a>?<br />
<br />
<br />
<a href="http://www.joobikplayer.com/" target="_blank"><b>Get Joobik Video Playlist Player here</b></a><br />
<div>
<br /></div>
</div>
<div class="post-title entry-title">
<br /></div>
<div class="post-title entry-title">
<br /></div>
<div class="post-title entry-title">
<br /></div>
joobikhttp://www.blogger.com/profile/09390437095051380351noreply@blogger.com27tag:blogger.com,1999:blog-8097245354602487605.post-74136067055887594942014-08-13T09:33:00.002+02:002015-02-17T14:10:11.663+01:00There is no audio while playing a video with Joobik<span style="background-color: white; color: #333333; font-family: 'Helvetica Neue Light', HelveticaNeue-Light, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.6000003814697px; text-align: justify;">This article has moved to the new Joobik Player website: </span><a href="http://www.joobikplayer.com/f-a-q/#no_audio" style="-webkit-transition: color 0.3s; background-color: white; color: #009eb8; display: inline; font-family: 'Helvetica Neue Light', HelveticaNeue-Light, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.6000003814697px; outline: none; text-align: justify; text-decoration: none; transition: color 0.3s;" target="_blank">http://www.joobikplayer.com/f-a-q</a>Anonymoushttp://www.blogger.com/profile/09420743738560302691noreply@blogger.com1tag:blogger.com,1999:blog-8097245354602487605.post-22422331707989460432014-07-29T14:48:00.001+02:002015-02-16T14:44:37.273+01:00Why does Joobik Player skip some or all of my videos while playing?This article has moved to the new Joobik Player website: <a href="http://www.joobikplayer.com/f-a-q/#drm_no_play" target="_blank">http://www.joobikplayer.com/f-a-q</a>Anonymoushttp://www.blogger.com/profile/09420743738560302691noreply@blogger.com1tag:blogger.com,1999:blog-8097245354602487605.post-83488303849919546842014-05-02T19:17:00.000+02:002015-02-15T09:42:42.406+01:00Joobik Video Playlist Player Tutorial<div class="separator" style="clear: both; text-align: center;">
<br /></div>
The Joobik Video Playlist Player Tutorial has moved to <a href="http://joobikplayer.com/tutorial" target="_blank">joobikplayer.com/tutorial</a>.Anonymoushttp://www.blogger.com/profile/09420743738560302691noreply@blogger.com0tag:blogger.com,1999:blog-8097245354602487605.post-63663207469819388652014-05-02T13:36:00.003+02:002015-02-16T14:49:58.714+01:00How to change the Duration of Track Title Display, or switch it offThis article has moved to the new Joobik Player website: <a href="http://www.joobikplayer.com/f-a-q/#track_title_display" target="_blank">http://www.joobikplayer.com/f-a-q</a>Anonymoushttp://www.blogger.com/profile/09420743738560302691noreply@blogger.com0tag:blogger.com,1999:blog-8097245354602487605.post-74062475149277991272014-05-02T10:47:00.000+02:002015-02-15T11:09:55.081+01:00How to use AirPlay with Joobik PlayerThis article has moved: <a href="http://www.joobikplayer.com/f-a-q/#howto_airplay" target="_blank">http://www.joobikplayer.com/f-a-q</a><br />
<br />
<br />Anonymoushttp://www.blogger.com/profile/09420743738560302691noreply@blogger.com0tag:blogger.com,1999:blog-8097245354602487605.post-32704604631664599672013-11-07T21:18:00.002+01:002015-02-17T14:00:43.882+01:00I cannot see my iTunes videos in Joobik Player, even though they are not DRM protected<span style="background-color: white; color: #333333; font-family: 'Helvetica Neue Light', HelveticaNeue-Light, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.6000003814697px; text-align: justify;">This article has moved to the new Joobik Player website: </span><a href="http://www.joobikplayer.com/f-a-q/#not_show_unprotected" style="-webkit-transition: color 0.3s; background-color: white; color: #009eb8; display: inline; font-family: 'Helvetica Neue Light', HelveticaNeue-Light, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.6000003814697px; outline: none; text-align: justify; text-decoration: none; transition: color 0.3s;" target="_blank">http://www.joobikplayer.com/f-a-q</a>joobikhttp://www.blogger.com/profile/09390437095051380351noreply@blogger.com2tag:blogger.com,1999:blog-8097245354602487605.post-20674682635534559882013-01-20T13:05:00.000+01:002014-05-02T09:57:10.397+02:00Why doesn't Joobik Player show all my iTunes videos?Apple do sell some of their videos with
Digital Rights Management (DRM), some without. This policy differs from country to country. E.g. in
Germany they usually sell music videos without DRM, but movies and tv
shows are DRM protected. Depending on where you live some of your
purchased videos might be DRM protected. You can check this in iTunes by
inspecting the "Kind" property on a video. If it reads something like
"Protected video file", <a href="http://itunes.apple.com/app/joobik-video-playlist-player/id502325425?mt=8">Joobik Player </a>will not be able to play it.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj072VGXhUNnXoUoiHGNemIChOmFDupUcRFRIqRI1wBCTsd0JdTfMwNySaRCZ1onCPgl57THQlk3ElXp67nEWcceWifqdsDIG2V2kzxWVKFFukmjhl2Upl2CuhLC0c3UyxqsDvPiYuE6epP/s1600/Protected+Video.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj072VGXhUNnXoUoiHGNemIChOmFDupUcRFRIqRI1wBCTsd0JdTfMwNySaRCZ1onCPgl57THQlk3ElXp67nEWcceWifqdsDIG2V2kzxWVKFFukmjhl2Upl2CuhLC0c3UyxqsDvPiYuE6epP/s1600/Protected+Video.png" height="367" width="400" /></a></div>
<br />
<br />
Please check all of the videos not appearing in Joobik Player for the
"Kind" property in iTunes. If all of them are protected, Joobik Player hides them. This is a restriction by Apple. They let only their own apps access DRM protected content.<br />
<br />
If you find any unprotected video not appearing in Joobik Player, <a href="http://www.joobik.com/2013/11/i-cannot-see-my-itunes-videos-in-joobik.html">this</a> blog post might help.joobikhttp://www.blogger.com/profile/09390437095051380351noreply@blogger.com3tag:blogger.com,1999:blog-8097245354602487605.post-39999434161615301422013-01-07T21:07:00.002+01:002015-06-14T11:24:28.396+02:00Can Joobik Player show folders within folders, like my playlists in itunes?Yes, when the Playlist Premium Pack is enabled, <a href="http://itunes.apple.com/app/joobik-video-playlist-player/id502325425?mt=8">Joobik Player</a> will show playlist folders from iTunes!joobikhttp://www.blogger.com/profile/09390437095051380351noreply@blogger.com0tag:blogger.com,1999:blog-8097245354602487605.post-8618996790148856632013-01-06T16:10:00.000+01:002015-03-08T08:20:10.576+01:00Could we get play count syncing with iTunes?<span style="background-color: white; color: #333333; font-family: 'Helvetica Neue Light', HelveticaNeue-Light, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.6000003814697px; text-align: justify;">This article has moved to the new Joobik Player website: </span><a href="http://www.joobikplayer.com/f-a-q/#playcount" style="-webkit-transition: color 0.3s; background-color: white; color: #009eb8; display: inline; font-family: 'Helvetica Neue Light', HelveticaNeue-Light, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 19.6000003814697px; outline: none; text-align: justify; text-decoration: none; transition: color 0.3s;" target="_blank">http://www.joobikplayer.com/f-a-q</a>joobikhttp://www.blogger.com/profile/09390437095051380351noreply@blogger.com0tag:blogger.com,1999:blog-8097245354602487605.post-28958368400784473972013-01-06T16:00:00.001+01:002013-01-06T16:00:21.869+01:00What does Joobik mean?Joobik is a phonetic mixture of "Jukebox" and "ubiquitous". So it means: Your everywhere-jukebox! I thought, it looks a bit better written with "Joo", instead of "Ju".<br />
<br />joobikhttp://www.blogger.com/profile/09390437095051380351noreply@blogger.com0tag:blogger.com,1999:blog-8097245354602487605.post-50758657190776482582012-12-13T20:55:00.001+01:002015-04-28T09:14:14.477+02:00Joobik Video Playlist Player- iTunes App Store Reviews RepliedHere I will answer some of the reviews of <a href="http://itunes.apple.com/app/joobik-video-playlist-player/id502325425?mt=8">Joobik Video Playlist Player</a> I received from iTunes app stores all over the world. Unfortunately the iTunes store doesn't give me the possibility to answer a review directly in the store. So this post is my way of giving feedback.<br />
<br />
First of all, I want to say thank you to anybody who leaves a review comment to one of my apps at the iTunes store - Be it positive or negative! All these comments are valuable input and inspiration to my further app development!<br />
<br />
But now let's start. I'll post the original comments, english translations (if needed), plus my replies, all sorted by date.<br />
<br />
<hr />
<h3>
2012/12/31 Endlich kontinuierlich Videos im Auto abspielen!</h3>
<br />
<b>Germany - McGybrush</b><br />
<b>Joobik Player 2.0</b><br />
<br />
<b>Review (English Translation) - Finally I can play videos continuously in the car</b><br />
There are some players that play videos continuously. But this one uses my existing smart playlists. I don't have to create new playlists or edit existing ones when I load new videos into my smart lists.<br />
To my opinion, the swipe-to-skip-gesture is inverted. I would like to have this changed. <br />
<br />
<b>Review (Original - German)</b><br />
Es gibt einige Player die das gleiche können. Aber dieser nutzt meine vorhandenen Intelligenten Wiedergabelisten und muss wenn ich öfter Videos nachlade nie eine eigene neue Wiedergabeliste erstellen bzw die alten erweitern. Ich kann einfach die nutzen die sowieso schon da sind. Das Titel weiter swipen mit der Gestensteuerung empfinde ich für mich leider als Spiegelverkehrt. In der CarTunes APP die so ähnlich für NICHT Videos ist, fühlt sich das swipen richtig rum an. Die dort enthaltenen Gesten sollten auch hier noch eingeführt werden. Trotzdem 5 Sterne. <br />
<b><br /></b>
<b>Reply</b><br />
Thanks a lot for this feature request, McGybrush! In Joobik Player 2.1 the swipe-to-skip gesture will be configurable in the app settings.<br />
<br />
<hr />
<h3>
2012/12/26 <span class="customerReviewTitle">I can use my playlists again on my Ipad!</span>
</h3>
<br />
<b>United States - Wendy NJ</b><br />
<b>Joobik Player 2.0</b><br />
<br />
<b>Review</b><br />
Thank you so much for making this app. Sadly my video playlists stopped working on my iphone and ipad 10/2012 and I figured out a workaround by changing the media type to music video. It fixed the iphone problem, but the playlists still would not work on my ipad 1 and after some research, I found this app. I liked that this app took my existing playlists and listed them as opposed to another where I had to recreate the playlists. I do wish that it would show folders within folders, like my playlists in itunes, instead of listing all the folders separately by name. Maybe a future version could support that. Also, it is a little slow getting to the videos, but that could be because I have an original ipad 1! I am very happy with this app as it allows me to see my videos easily in an organized fashion! THANK YOU! <br />
<b><br /></b>
<b>Reply</b><br />
I'm very unhappy with the folder-thing, too, because this is how I
do organize my playlists as well. So if there where a way of telling
which playlist is actually a folder, it'd be the first thing I'd
build into Joobik Player. But currently the guys from Apple do not
provide any means to third party developers which would let them
identify a folder hierarchy. A playlist folder on the iPad looks
like a smart playlist to me, which contains only tracks, no other
playlists.<br />
<br />
<hr />
<h3>
2012/12/14 Super App!</h3>
<br />
<b>Germany - Oneo88</b><br />
<b>Joobik Player 2.0</b><br />
<br />
<b>Review (English Translation)</b><br />
I own the App for 3 months and am very happy. Only shortcoming is that after shuffling it never starts playback from position 1, but from somewhere in the middle of the list.<br />
<br />
<b>Review (Original - German)</b><br />
Besitze die APP. Seit 3 Monaten und bin sehr zufrieden. Einzigstes Manko ist das man bei der Shuffle Wiedergabe nie von Position 1 anfängt sondern irgendwo in der liste anfängt . <br />
<b><br /></b>
<b>Reply</b><br />
Thanks a lot for this bug report, Oneo88! In Joobik Player 2.1 it will be fixed!<br />
<br />
<div>
<br />
<center>
<script type="text/javascript" language="javascript">
amzn_assoc_ad_type = "contextual";
amzn_assoc_tracking_id = "joobikcom-20";
amzn_assoc_marketplace = "amazon";
amzn_assoc_region = "US";
amzn_assoc_placement = "OUMA5OFNJ6UHSOXF";
amzn_assoc_linkid = "OUMA5OFNJ6UHSOXF";
amzn_assoc_emphasize_categories = "13900861, 2335752011, 13900871, 130, 172282, 979455011, 195209011, 301668, 229534, 468642, 377110011";
amzn_assoc_fallback_products = "";
amzn_assoc_width = "300";
amzn_assoc_height = "250";
</script>
<script type="text/javascript" language="javascript" src="//z-na.amazon-adsystem.com/widgets/q?ServiceVersion=20070822&Operation=GetScript&ID=OneJS&WS=1&MarketPlace=US&source=ac"></script>
</center>
<br />
</div>
<hr />
<h3>
2012/12/11 Playlists keep vanishing</h3>
<br />
<b>United States - Apple IIc User</b><br />
<b>Joobik Player 1.6</b><br />
<br />
<b>Review</b><br />
This
is a good program … until all my playlists vanish, first from my iPad
Mini, and then upon syncing, from iTunes. The actual videos remain
intact on the iPad, but the lists are gone. This has happened a few
times. <br />
<b><br /></b>
<b>Reply</b><br />
In this case I can take all the fear from all of you: For a third-party-app (like Joobik Player is) it isn't possible to do any modifications to your iPad's, or (even worse) your Mac's or PC's iTunes library. Apple's programming interfaces do prevent this reliably. If you doubt, please inquire the Apple support team!So I guess your problems come either from the new behaviour and UI of iTunes 11, or you simply didn't sync your playlists correctly. Please find some playlist syncing instructions <a href="http://www.joobik.com/2012/04/how-to-sync-video-playlists-to-ipad.html">here</a>. <br />
<br />
<hr />
<h3>
2012/12/02 Movie output</h3>
<b>United States - Sancho2012</b><br />
<b>Joobik Player 1.6</b><br />
<br />
<b>Review</b><br />
Is there a way that you can make it so that videos can play back when its hooked up with a j-link cable or do it through bluetooth?<br />
<b><br /></b>
<b>Reply</b><br />
If by "j-link" you mean <a href="http://www.segger.com/jlink.html">J-Link</a>, then it isn't. Just like it isn't for bluetooth. The current Apple programming interface available to third party developers does only support external screens via AirPlay out of the box. Apple does actively prevent third party apps
from outputting video via cable. I guess the intention
is to push AirPlay. Even if I could find
a way of enabling tv out it could be they would reject my app from
the app store due to their API usage rules.<br />
There seem to be some <a href="http://luminaryapps.com/blog/playing-a-video-with-external-display-support/">workarounds</a> for custom videos which are copied to the iPad via different ways than iTunes (like web videos). But I couldn't get this to work for videos from the iTunes library.<br />
<h3>
</h3>
<br />
<hr />
<h3>
2012/11/17 Fantastic App</h3>
<b>United Kingdom - Kaves17</b><br />
<b>Joobik Player 1.6</b><br />
<br />
<b>Review</b><br />
Great app, allows me to play all my video playlists. Could we get play count syncing to the music/video app?<br />
<b><br /></b>
<b>Reply</b><br />
Unfortunately Apple does not give write access to iTunes meta data to 3rd party apps. So it's currently not possible to modify play count and sync it back to any Apple app or iTunes.joobikhttp://www.blogger.com/profile/09390437095051380351noreply@blogger.com11tag:blogger.com,1999:blog-8097245354602487605.post-65654923402524069522012-04-09T20:29:00.000+02:002015-12-16T11:45:00.585+01:00How to sync video playlists from iTunes to iPod, iPhone, or iPad<span action="/WebObjects/iTunesConnect.woa/wo/6.0.0.9.7.3.1.1.1.11.3.1.1.11.11.2" class="lcAjaxContainer" id="localizationLightboxUpdate"><span class="metadataFieldReadonly"><br />
<a href="http://www.joobikplayer.com/" target="_blank">Joobik Player</a> plays videos from playlists synced to your iPod, iPhone, or iPad. To use it, please create a video playlist in iTunes and then sync the list to your device, not only the videos themselves. <br /><br />
</span></span><br />
<span action="/WebObjects/iTunesConnect.woa/wo/6.0.0.9.7.3.1.1.1.11.3.1.1.11.11.2" class="lcAjaxContainer"><span class="metadataFieldReadonly">For example: To sync a movie playlist, on the tab where you select videos for synchronization in iTunes, you have to either uncheck the "Automatically include" checkbox, or with the checkbox checked you must choose any other option than "All movies" from the drop down list in order to display the playlists for syncing.</span></span><br />
<span action="/WebObjects/iTunesConnect.woa/wo/6.0.0.9.7.3.1.1.1.11.3.1.1.11.11.2" class="lcAjaxContainer"><span class="metadataFieldReadonly"><br /></span></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEis2gCvQcegaH9K4ajn8rAMQgRJh9nKTkgQLAP86R7ebBHXvpeDFMkLFHACxwm-OCMVzbFQc05hGP1HL2TZoy596q4ysWNvGZy3ktHyciaqn7QqcS9g2Lby6nYjdAS54vC2tCN6X-b9xaiB/s1600/Sync+Movies+1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="99" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEis2gCvQcegaH9K4ajn8rAMQgRJh9nKTkgQLAP86R7ebBHXvpeDFMkLFHACxwm-OCMVzbFQc05hGP1HL2TZoy596q4ysWNvGZy3ktHyciaqn7QqcS9g2Lby6nYjdAS54vC2tCN6X-b9xaiB/s1600/Sync+Movies+1.png" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbxsjiUVJVyBJuU6QpOEkY1iI-n3ZM6Ad1dzPq-toxjdTYbb9CtDR1s9j6umytZE5eWru26K7E_vdf0rrSm3p0PyM_8VflErgXdd-ImWeYjiHEWWflB0AV6Tr4mNvNEXeMQzrKKM7_d4Rx/s1600/Sync+Movies+2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="90" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbxsjiUVJVyBJuU6QpOEkY1iI-n3ZM6Ad1dzPq-toxjdTYbb9CtDR1s9j6umytZE5eWru26K7E_vdf0rrSm3p0PyM_8VflErgXdd-ImWeYjiHEWWflB0AV6Tr4mNvNEXeMQzrKKM7_d4Rx/s1600/Sync+Movies+2.png" width="400" /></a></div>
<span action="/WebObjects/iTunesConnect.woa/wo/6.0.0.9.7.3.1.1.1.11.3.1.1.11.11.2" class="lcAjaxContainer"><span class="metadataFieldReadonly"><br /></span></span>
<span action="/WebObjects/iTunesConnect.woa/wo/6.0.0.9.7.3.1.1.1.11.3.1.1.11.11.2" class="lcAjaxContainer"><span class="metadataFieldReadonly"><br /></span></span>
<span action="/WebObjects/iTunesConnect.woa/wo/6.0.0.9.7.3.1.1.1.11.3.1.1.11.11.2" class="lcAjaxContainer"><span class="metadataFieldReadonly"><br /></span></span>
<span action="/WebObjects/iTunesConnect.woa/wo/6.0.0.9.7.3.1.1.1.11.3.1.1.11.11.2" class="lcAjaxContainer"><span class="metadataFieldReadonly">On the "TV-Shows" tab it is the same. </span></span><br />
<span action="/WebObjects/iTunesConnect.woa/wo/6.0.0.9.7.3.1.1.1.11.3.1.1.11.11.2" class="lcAjaxContainer"><span class="metadataFieldReadonly"><br /></span></span>
<span action="/WebObjects/iTunesConnect.woa/wo/6.0.0.9.7.3.1.1.1.11.3.1.1.11.11.2" class="lcAjaxContainer"><span class="metadataFieldReadonly">If you have a mixed playlists, containing movies and tv shows for example, this playlist must be selected under the "Movies" and the "TV Shows" tab for syncing. Otherwise it will only contain either of the video types when synced to your iOS device.</span></span><br />
<span action="/WebObjects/iTunesConnect.woa/wo/6.0.0.9.7.3.1.1.1.11.3.1.1.11.11.2" class="lcAjaxContainer"><span class="metadataFieldReadonly"><br /></span></span>
<span action="/WebObjects/iTunesConnect.woa/wo/6.0.0.9.7.3.1.1.1.11.3.1.1.11.11.2" class="lcAjaxContainer">
<span class="metadataFieldReadonly"><b>iTunes Match Users: </b>If you are using iTunes Match to sync your videos to your iOS device, you must download the videos from iCloud to the device in the first place. Only then they will appear in <a href="http://joobikplayer.com/" target="_blank">Joobik Player</a>. Downloading can be done with the standard Apple iOS Video or Music App.</span></span><br />
<span action="/WebObjects/iTunesConnect.woa/wo/6.0.0.9.7.3.1.1.1.11.3.1.1.11.11.2" class="lcAjaxContainer"><span class="metadataFieldReadonly">When iTunes Match is turned on on your iOS device, Joobik Player will not be able to recognize iTunes Folders.</span></span><br />
<span action="/WebObjects/iTunesConnect.woa/wo/6.0.0.9.7.3.1.1.1.11.3.1.1.11.11.2" class="lcAjaxContainer"><span class="metadataFieldReadonly"><br /></span></span>
<span action="/WebObjects/iTunesConnect.woa/wo/6.0.0.9.7.3.1.1.1.11.3.1.1.11.11.2" class="lcAjaxContainer"><span class="metadataFieldReadonly">Detailed instructions about iTunes Match can be found in <a href="http://www.joobik.com/2015/03/how-itunes-match-does-or-does-not-sync.html">this blog post</a>.</span></span><br />
<span action="/WebObjects/iTunesConnect.woa/wo/6.0.0.9.7.3.1.1.1.11.3.1.1.11.11.2" class="lcAjaxContainer"><span class="metadataFieldReadonly"><br /></span></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.joobikplayer.com/" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;" target="_blank"><img border="0" height="93" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0YOn-mWycY4CbxGfFplAX9JP_EnTo5EkX3_SfIE96WHKR3lyST_eKCs7HnjKzY0_z01jjeafGFqT5rE0dOGBlrXW9pSJjXnJVQB2kJAO2vT4cGZNE5Z_PX24S3kJI9gQUSjsNugBcefQk/s1600/Joobik-Banner.png" width="400" /></a></div>
<span action="/WebObjects/iTunesConnect.woa/wo/6.0.0.9.7.3.1.1.1.11.3.1.1.11.11.2" class="lcAjaxContainer"><span class="metadataFieldReadonly"><br /></span></span>joobikhttp://www.blogger.com/profile/09390437095051380351noreply@blogger.com14tag:blogger.com,1999:blog-8097245354602487605.post-34678676853106108892010-12-08T15:38:00.000+01:002015-04-28T09:18:06.396+02:00Mapping Dates and Time Zones with Hibernate, Part 2: Few Solutions<a href="http://www.joobik.com/2010/11/mapping-dates-and-time-zones-with.html">Go back to Part 1 of this article</a> <br />
<br />
In the <a href="http://dev-metal.blogspot.com/2010/11/mapping-dates-and-time-zones-with.html">first part </a>of this article I was talking about the problems when mapping date/time to a database table using Hibernate. In part two I will talk about the solutions.<br />
<br />
<span style="font-size: small;"><b>The quick Way: Use Property Access Type and implement the Setter</b></span><br />
<br />
Tell Hibernate to use setter and getter methods for field access, instead of using reflection to modify the entity object's fields directly. To do so, you have to put the Hibernate annotations above the getter methods, instead of the class attributes. You MUST move the annotation of the @Id field to the getter to enable property access. But you should do it with all field annotations, for better clarity. You can find a more detailed discussion of Hibernate property access <a href="http://javaprogrammingtips4u.blogspot.com/2010/04/field-versus-property-access-in.html">here</a> and <a href="http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/#entity-mapping-property">here</a>.<br />
Once you did so, you can implement a setter method for the calendar field, which takes the calendar object provided by Hibernate, and creates a new object with the right time zone and date information from it:<br />
<br />
<table border="0" cellpadding="2" cellspacing="2" style="font-family: Courier New,Courier,monospace; text-align: left; width: 100%;"><tbody>
<tr><td style="background-color: #cccccc;"><small>package entity;<br /><br />...<br /><br />public class GMTDateEntity implements Serializable {</small><br />
<small> </small><br />
<small> ...<br /><br /> private Integer pk;<br /><br /> private Calendar calendar;<br /><br /> @Id<br /> @Column(name = "pk", nullable = false)<br /> @GeneratedValue(strategy = GenerationType.IDENTITY)<br /> public Integer getPk() {<br /> return pk;<br /> }</small><br />
<small></small><br />
<small><br /> @Temporal(TemporalType.TIMESTAMP)<br /> @Column(name = "calendartime")<br /> public Calendar getCalendar() {<br /> return calendar;<br /> }<br /><br /> public void setCalendar(Calendar calendar) {<br /> <span style="color: #38761d;">//create new calendar in GMT time zone</span><br /> this.calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT"));<br /> <br /> <span style="color: #38761d;">//set calendar fields</span><br /> this.calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR));<br /> this.calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH));<br /> this.calendar.set(Calendar.DATE, calendar.get(Calendar.DATE));<br /> this.calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY));<br /> this.calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE));<br /> this.calendar.set(Calendar.SECOND, calendar.get(Calendar.SECOND));<br /> this.calendar.set(Calendar.MILLISECOND, calendar.get(Calendar.MILLISECOND));<br /> <br /> <span style="color: #38761d;">//recalculate calendar time millis</span><br /> this.calendar.getTime();<br /> }</small><br />
<br />
<small> ...<br />}</small></td> </tr>
</tbody> </table>
<br />
Because the time zone information is the only thing that is wrong in Hibernate's calendar object, we simply create a new calendar object in the correct time zone, and then copy all required fields from Hibernate's object to our new object. The final call to <span style="font-family: "Courier New",Courier,monospace;">getTime()</span> will recalculate the calendars internal time milliseconds based on the field and time zone information. Unfortunately, the actual recalculation-methods are protected in java.util.Calendar for reasons I just don't know. So we have to use this less elegant workaround.<br />
<br />
<b>The elegant Way: Create a custom Hibernate User Type </b><br />
<br />
If for any reason you cannot use Hibernate property access, you will have to stick to the advanced art of programming and create a custom user type, which does the mapping from DB result set to Java object for you. Explanation of user type implementation would be beyond topic of this article. But you can find a very good introduction <a href="http://blog.xebia.com/2009/11/09/understanding-and-writing-hibernate-user-types/">here</a>. Just be aware, that you have to create a mutable user type, as java.util.Calendars are mutable objects.<br />
To put everything short, here is the user type implementation that will serve our purpose:<br />
<table border="0" cellpadding="2" cellspacing="2" style="font-family: Courier New,Courier,monospace; text-align: left; width: 100%;"><tbody>
<tr><td style="background-color: #cccccc;"><span style="font-size: x-small;">package usertypes;<br /><br />import java.io.Serializable;<br />import java.sql.PreparedStatement;<br />import java.sql.ResultSet;<br />import java.sql.SQLException;<br />import java.sql.Types;<br />import java.text.ParseException;<br />import java.text.SimpleDateFormat;<br />import java.util.Calendar;<br />import java.util.Date;<br />import java.util.GregorianCalendar;<br />import java.util.TimeZone;<br /><br />import org.hibernate.Hibernate;<br />import org.hibernate.HibernateException;<br />import org.hibernate.usertype.UserType;<br /><br />public class GmtCalendarUserType implements UserType, Serializable {<br /><br /> private static final long serialVersionUID = 1L;<br /> <br /> <span style="color: #38761d;">//The interesting methods:</span><br /><br /> @Override<br /> public void nullSafeSet(PreparedStatement statement, Object value, int index)<br /> throws HibernateException, SQLException {</span><br />
<br />
<span style="font-size: x-small;"> </span><span style="font-size: x-small;"><span style="color: #38761d;">// we have to be null-safe</span></span><br />
<span style="font-size: x-small;"><span style="color: #38761d;"> </span></span><span style="font-size: x-small;">if (value == null) {</span><br />
<span style="font-size: x-small;"> Hibernate.CALENDAR.nullSafeSet(statement, null, index);</span><span style="font-size: x-small;"><span style="color: #38761d;"> </span></span><br />
<span style="font-size: x-small;"><span style="color: #38761d;"> <span style="color: black;"> return;</span></span></span><br />
<div style="color: black;">
<span style="font-size: x-small;"> } </span><span style="font-size: x-small;"> </span></div>
<div style="color: black;">
<span style="font-size: x-small;"></span></div>
<span style="font-size: x-small;"> <br /> <span style="color: #38761d;">// we have a Calendar here</span><br /> Calendar cal = (Calendar) value;<br /> <span style="color: #38761d;">// cut millis, as SQL Server uses only 1/300 precision</span><br /> long millis = cal.getTimeInMillis();<br /> millis = millis - (millis % 1000);<br /> cal.setTimeInMillis(millis);<br /> <span style="color: #38761d;">// simply delegate to hibernate's built in method</span><br /> Hibernate.CALENDAR.nullSafeSet(statement, cal, index);<br /> }<br /><br /> @Override<br /> public Object nullSafeGet(ResultSet resultSet, String[] columnNames,<br /> Object owner) throws HibernateException, SQLException {<br /><br /><span style="color: #38761d;"> // we cannot do it like this, because it would initialize the calendar</span><br style="color: #38761d;" /><span style="color: #38761d;"> // in the jvm's default timezone:</span><br style="color: #38761d;" /><span style="color: #38761d;"> // Calendar cal = (Calendar) Hibernate.CALENDAR.nullSafeGet(resultSet,</span><br style="color: #38761d;" /><span style="color: #38761d;"> // columnNames);</span><br style="color: #38761d;" /><span style="color: #38761d;"> // return cal;</span><br style="color: #38761d;" /><br style="color: #38761d;" /><span style="color: #38761d;"> // We have to create the Calendar object from the DB date string</span><br style="color: #38761d;" /> String timeString = (String) Hibernate.STRING.nullSafeGet(resultSet,<br /> columnNames);<br /> if (timeString == null)<br /> return null;<br /><br /> try {<br /> Date date = this.parseDbDateString(timeString);<br /> <span style="color: #38761d;">// Init calendar in GMT</span><br /> Calendar retValue = new GregorianCalendar(<br /> TimeZone.getTimeZone("GMT"));<br /> retValue.setTime(date);<br /> <span style="color: #38761d;">// calculate calendar fields</span><br /> retValue.getTime();<br /> return retValue;<br /> } catch (ParseException e) {<br /> throw new HibernateException("Could not parse datestring from DB.",<br /> e);<br /> }<br /> }<br /><br /> private Date parseDbDateString(String dateString) throws ParseException {<br /> <span style="color: #38761d;">// create gmt time zone</span><br /> TimeZone gmtZone = TimeZone.getTimeZone("GMT");<br /> <span style="color: #38761d;">// create db date format (cut millis)</span><br /> String pattern = "yyyy-MM-dd HH:mm:ss";<br /> SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);<br /> dateFormat.setTimeZone(gmtZone);<br /> return dateFormat.parse(dateString);<br /> }<br /><br /> <span style="color: #38761d;">//The other UserType methods:</span><br /> <br /> @Override<br /> public Object assemble(Serializable cached, Object owner)<br /> throws HibernateException {<br /> return this.deepCopy(cached);<br /> }<br /><br /> @Override<br /> public Object deepCopy(Object object) throws HibernateException {<br /> if (object == null)<br /> return null;<br /> <span style="color: #38761d;">// we have a calendar here</span><br /> Calendar cal = (Calendar) object;<br /> return cal.clone();<br /> }<br /><br /> @Override<br /> public Serializable disassemble(Object value) throws HibernateException {<br /> return (Serializable) this.deepCopy(value);<br /> }<br /><br /> @Override<br /> public boolean equals(Object object1, Object object2)<br /> throws HibernateException {<br /> if (object1 == object2) {<br /> return true;<br /> }<br /> if ((object1 == null) || (object2 == null))<br /> return false;<br /> return object1.equals(object2);<br /> }<br /><br /> @Override<br /> public int hashCode(Object value) throws HibernateException {<br /> return value.hashCode();<br /> }<br /><br /> @Override<br /> public boolean isMutable() {<br /> <span style="color: #38761d;">// Calendar is mutable</span><br /> return true;<br /> }<br /><br /> @Override<br /> public Object replace(Object original, Object target, Object owner)<br /> throws HibernateException {<br /> return this.deepCopy(original);<br /> }<br /><br /> @Override<br /> public Class<zulucalendar> returnedClass() {<br /> return Calendar.class;<br /> }<br /><br /> @Override<br /> public int[] sqlTypes() {<br /> return new int[] { Types.TIMESTAMP };<br /> }<br />}</zulucalendar></span></td></tr>
</tbody></table>
<br />
<div>
<br />
<center>
<script type="text/javascript" language="javascript">
amzn_assoc_ad_type = "contextual";
amzn_assoc_tracking_id = "joobikcom-20";
amzn_assoc_marketplace = "amazon";
amzn_assoc_region = "US";
amzn_assoc_placement = "OUMA5OFNJ6UHSOXF";
amzn_assoc_linkid = "OUMA5OFNJ6UHSOXF";
amzn_assoc_emphasize_categories = "13900861, 2335752011, 13900871, 130, 172282, 979455011, 195209011, 301668, 229534, 468642, 377110011";
amzn_assoc_fallback_products = "";
amzn_assoc_width = "300";
amzn_assoc_height = "250";
</script>
<script type="text/javascript" language="javascript" src="//z-na.amazon-adsystem.com/widgets/q?ServiceVersion=20070822&Operation=GetScript&ID=OneJS&WS=1&MarketPlace=US&source=ac"></script>
</center>
<br />
</div>
The <span style="font-family: "Courier New",Courier,monospace;">nullSafeSet</span> method will inject our Java object into the SQL statement. As Hibernate handles Calendars correctly when persisting, you simply delegate this task to Hibernate here. But since I'm using MS SQL Server in this example, I have to deal with the different precisions of Java dates (1 millisecond prec.) and SQL Server datetime types (1/300 second prec.). I choose the simple way here and simply cut the millis.<br />
<br />
The <span style="font-family: "Courier New",Courier,monospace;">nullSafeGet </span>method does a little more of tweaking. This is where the result set is mapped to our Java Calendar object. If we would use Hibernate's built in mapping here (as in the commented block in this method), we would get the Calendar with the JVM time zone set. So we have to treat the datetime from the SQL result set as a string, and parse the date in GMT from it and create a new GMT GregorianCalendar.<br />
<br />
Once we've finished our UsertType, all we have to do is to annotate our GMTDateEntity object to use it:<br />
<table border="0" cellpadding="2" cellspacing="2" style="font-family: Courier New,Courier,monospace; text-align: left; width: 100%;"><tbody>
<tr><td style="background-color: #cccccc;"><small>package entity;<br /><br />...</small><br />
<small><br /></small>
<small>@Entity<br />@Table(name = "datetestgmt")</small><br />
<small><span style="color: #38761d;">//Declare the UserType on the class </span><br />@TypeDef(name = "gmtCalendar", typeClass = GmtCalendarUserType.class)<br />public class GMTDateEntity implements Serializable {</small><br />
<small></small><br />
<br />
<small>...</small><br />
<small></small><br />
<small></small><br />
<small></small><br />
<small></small><br />
<small> </small><br />
<small> <span style="color: #38761d;">//Use the UserType on the attribute</span></small><br />
<small> @Type(type = "gmtCalendar")<br /> @Column(name = "calendartime")<br /> private Calendar calendar;<br /> </small><br />
<br />
<small></small><br />
<small>...</small><br />
<small> </small><br />
<small>}</small></td></tr>
</tbody></table>
<br />
<a href="http://www.joobik.com/2010/11/mapping-dates-and-time-zones-with.html">Go back to Part 1 of this article</a><br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.joobikplayer.com/" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;" target="_blank"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0YOn-mWycY4CbxGfFplAX9JP_EnTo5EkX3_SfIE96WHKR3lyST_eKCs7HnjKzY0_z01jjeafGFqT5rE0dOGBlrXW9pSJjXnJVQB2kJAO2vT4cGZNE5Z_PX24S3kJI9gQUSjsNugBcefQk/s1600/Joobik-Banner.png" height="93" width="400" /></a><span id="goog_1895463022"></span><span id="goog_1895463023"></span><a href="https://www.blogger.com/"></a></div>
<br />Anonymoushttp://www.blogger.com/profile/09420743738560302691noreply@blogger.com796tag:blogger.com,1999:blog-8097245354602487605.post-7857521673997994122010-11-23T10:05:00.000+01:002015-04-13T13:26:14.687+02:00Valuable Tools for DevelopersThis is a list of useful tools to support Java and Objective-C development. It will be updated continuously.<br />
<br />
<b>HermesJMS (Java)</b><br />
JMS Console to browse, read from, and write to JMS queues and topics.<b></b><br />
<a href="http://www.hermesjms.com/">http://www.hermesjms.com</a><b><br /></b><br />
<br />
<b> </b><br />
<b>JarFinder (Java)</b><br />
Java Application that lets you search local folders and JAR files for specific classes.<br />
<a href="http://sourceforge.net/projects/jarfinder/">http://sourceforge.net/projects/jarfinder/ </a><br />
<br />
<b>Opacity (Mac OS X)</b><br />
Easy to use program to create buttons and screen graphics for web, iOS, and any other applications.<br />
<a href="http://likethought.com/opacity/">http://likethought.com/opacity/</a><b><br /></b><br />
<br />
<b>StartExplorer (Java/Eclipse)</b><br />
Eclipse plugin that opens the location of a file or folder from within an Eclipse project in the system's file explorer.<br />
<a href="http://startexplorer.sourceforge.net/">http://startexplorer.sourceforge.net/</a><br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.joobikplayer.com/" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;" target="_blank"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0YOn-mWycY4CbxGfFplAX9JP_EnTo5EkX3_SfIE96WHKR3lyST_eKCs7HnjKzY0_z01jjeafGFqT5rE0dOGBlrXW9pSJjXnJVQB2kJAO2vT4cGZNE5Z_PX24S3kJI9gQUSjsNugBcefQk/s1600/Joobik-Banner.png" height="93" width="400" /></a></div>
<br />Anonymoushttp://www.blogger.com/profile/09420743738560302691noreply@blogger.com1tag:blogger.com,1999:blog-8097245354602487605.post-212983482927406052010-11-19T10:52:00.000+01:002015-04-28T09:25:39.473+02:00Mapping Dates and Time Zones with Hibernate, Part 1: Plenty of Obstacles<span style="font-family: Arial,Helvetica,sans-serif;"><a href="http://www.joobik.com/2010/12/mapping-dates-and-time-zones-with.html">Go ahead to part 2 of this article</a></span><br />
<span style="font-family: Helvetica,Arial,sans-serif;"> </span><br />
<span style="font-family: Helvetica,Arial,sans-serif;">Have you ever tried to persist a date with Hibernate, which is supposed to<br />be in a different time zone from the one of the system your application<br />is running on? I'm pretty sure that you will get into trouble while<br />trying this. There's a number of obstacles to pass. Let's get them on<br />one by one and figure out appropriate solutions.</span><br />
<br />
<span style="font-family: Helvetica,Arial,sans-serif; font-weight: bold;">The Setup</span><br />
<span style="font-family: Helvetica,Arial,sans-serif; font-weight: bold;"><br /></span><span style="font-family: Arial,Helvetica,sans-serif;">I'm using JBoss 5.1 with Hibernate 3 and JPA for this tutorial. The data base is<br />Microsoft SQL Server Express 2008 with the JDBC driver from<br />sqljdbc4.jar. Both, JBoss and SQL Server are running on the same<br />machine in time zone Europe/Berlin with Central European Time (CET) as<br />active time schedule. We want to persist a Date to the data base wich shows up there in GMT time.</span><br />
<span style="font-family: Arial,Helvetica,sans-serif;"><br />We will need two Java classes. First there's the entity data object to be<br />persisted to the DB. As we want to persist GMT date records, it is called<br />GMTDateEntity:</span><br />
<table border="0" cellpadding="2" cellspacing="2" style="font-family: Courier New,Courier,monospace; text-align: left; width: 100%;"><tbody>
<tr><td style="background-color: #cccccc;"><small>package entity;<br /><br />import java.io.Serializable;<br />import java.util.Date;<br />import javax.persistence.Column;<br />import javax.persistence.GeneratedValue;<br />import javax.persistence.GenerationType;<br />import javax.persistence.Id;<br />import javax.persistence.Temporal;<br />import javax.persistence.TemporalType;<br /><br />public class GMTDateEntity implements Serializable {<br /><br /> private static final long serialVersionUID = 1L;<br /><br /> <span style="color: #009900;">//DB primary key.</span><br /> @Id<br /> @Column(name = "pk", nullable = false)<br /> @GeneratedValue(strategy = GenerationType.IDENTITY)<br /> private Integer pk;<br /><br /> <span style="color: #009900;">//The actual Date record.</span><br /> @Temporal(TemporalType.TIMESTAMP)<br /> @Column(name = "datetime")<br /> private Date date;<br /><br /> public Integer getPk() {<br /> return pk;<br /> }<br /><br /> public Date getDate() {<br /> return this.date;<br /> }<br /><br /> public void setDate(Date date) {<br /> this.date = date;<br /> }<br /><br /> public void setPk(Integer pk) {<br /> this.pk = pk;<br /> }<br />}</small></td> </tr>
</tbody> </table>
<small><b style="font-family: Courier New,Courier,monospace;"><br /></b></small><span style="font-family: Arial,Helvetica,sans-serif;"><small><big><span style="font-family: Helvetica,Arial,sans-serif;">The second class is the Data Access Object used to persist and retrieve our data object:</span></big></small> <table border="0" cellpadding="2" cellspacing="2" style="text-align: left; width: 100%;"><tbody>
<tr> <td style="background-color: #cccccc;"><small style="font-family: Courier New,Courier,monospace;">package dao;<br /><br />import javax.ejb.Remote;<br />import javax.ejb.Stateless;<br />import javax.persistence.EntityManager;<br />import javax.persistence.PersistenceContext;<br />import entity.GMTDateEntity;<br /><br />@Stateless<br />@Remote(IDateTestDao.class)<br /><br />public class DateTestDao implements IDateTestDao {<br /><br /> <span style="color: #009900;">//References section in hibernate config persistence.xml</span><br /> @PersistenceContext(unitName = "hibernate-date-test")<br /> private EntityManager entityManager;<br /><br /> @Override<br /> public GMTDateEntity retrieveGMTDateEntity(Integer pk) {<br /> return this.entityManager.find(GMTDateEntity.class, pk);<br /> }<br /><br /> @Override<br /> public GMTDateEntity persistGMTDateEntity(GMTDateEntity entity) {<br /> return this.entityManager.merge(entity);<br /> }<br />}</small><br />
<br /></td> </tr>
</tbody> </table>
</span><b><span style="font-family: Arial,Helvetica,sans-serif;"> 1. Obstacle: Hibernate uses system's time zone</span></b><br />
<br />
<span style="font-family: Arial,Helvetica,sans-serif;">Now</span><span style="font-family: Arial,Helvetica,sans-serif;"> let's persist a date object to the DB using our two classes. For this example I will create a java.util.Date representing the 9. November 2010, 12:00h GMT which we want to store to the DB.</span><span style="font-family: Arial,Helvetica,sans-serif;"> Now we do something like this:</span><br />
<br />
<span style="color: #666666; font-family: Arial,Helvetica,sans-serif; font-size: x-small;">String dateStringGMT = "2010-11-09T12:00:00";</span><br />
<span style="color: #666666; font-family: Arial,Helvetica,sans-serif; font-size: x-small;"><span style="color: #38761d;">//Parse the String using GMT time zone</span><br />SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");<br />dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));</span><br />
<span style="color: #666666; font-family: Arial,Helvetica,sans-serif; font-size: x-small;">Date date = dateFormat.parse(dateStringGMT);<br />GMTDateEntity entity = new GMTDateEntity();<br />entity.setDate(date);<br />dateTestDao.persistGMTDateEntity(entity);</span><br />
<b><span style="font-family: Arial,Helvetica,sans-serif;"></span></b><br />
<b><span style="font-family: Arial,Helvetica,sans-serif;"><br /></span></b>
<div>
<br />
<center>
<script type="text/javascript" language="javascript">
amzn_assoc_ad_type = "contextual";
amzn_assoc_tracking_id = "joobikcom-20";
amzn_assoc_marketplace = "amazon";
amzn_assoc_region = "US";
amzn_assoc_placement = "OUMA5OFNJ6UHSOXF";
amzn_assoc_linkid = "OUMA5OFNJ6UHSOXF";
amzn_assoc_emphasize_categories = "13900861, 2335752011, 13900871, 130, 172282, 979455011, 195209011, 301668, 229534, 468642, 377110011";
amzn_assoc_fallback_products = "";
amzn_assoc_width = "300";
amzn_assoc_height = "250";
</script>
<script type="text/javascript" language="javascript" src="//z-na.amazon-adsystem.com/widgets/q?ServiceVersion=20070822&Operation=GetScript&ID=OneJS&WS=1&MarketPlace=US&source=ac"></script>
</center>
<br />
</div>
<span style="font-family: Arial,Helvetica,sans-serif;">After executing the code we will have a new record in our DB:</span><br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2zXZJAAAQ0mR2r0r-Q0TMJ3y0s3P2pbIi116fb_j8gKQN2vprYCDxupAeueG-pIKyhAkSCnCTGJh7Qm6p4POSM8n0hZxWfRw6DChkW7g4zwIXYRC2nX9macetQigw09HdneFiKaa_NhnN/s1600/01.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2zXZJAAAQ0mR2r0r-Q0TMJ3y0s3P2pbIi116fb_j8gKQN2vprYCDxupAeueG-pIKyhAkSCnCTGJh7Qm6p4POSM8n0hZxWfRw6DChkW7g4zwIXYRC2nX9macetQigw09HdneFiKaa_NhnN/s1600/01.png" /></a></div>
<span style="font-family: Arial,Helvetica,sans-serif;"> </span><b><span style="font-family: Arial,Helvetica,sans-serif;"><br /></span></b><br />
<b><span style="font-family: Arial,Helvetica,sans-serif;"><br /></span></b>
<span style="font-family: Arial,Helvetica,sans-serif;">
<br />What happened? The time is shifted by an hour! </span><span style="font-family: Arial,Helvetica,sans-serif;">This is because java.util.Date stores dates in a time zone independent fashion, but for SQL data bases there dosn't exists the notion of time zone independent dates. You can store date records to a SQL DBMS only with a specific time zone. So what Hibernate does, is using the time zone schedule of its JVM (which runs in CET) to convert the time zone independent java.util.Date to the time zone specific date string in our DB record. Because CET is one hour ahead of GMT, one hour has been added to our DB date.</span><br />
<span style="font-family: Arial,Helvetica,sans-serif;">Unfortunately, there exists neither an Hibernate or JPA annotation nor any other simple way to tell Hibernate in which time zone to persist java.util.Date objects. So if we cannot set the time zone schedule of our JVM to GMT, we must figure out other ways to tell Hibernate what we want.</span><br />
<br />
<b><span style="font-family: Arial,Helvetica,sans-serif;"> </span></b><br />
<span style="font-family: Arial,Helvetica,sans-serif;"><b>2. Obstacle: Hibernate doesn't use Calendar's time zone for reading</b></span><br />
<span style="font-family: Arial,Helvetica,sans-serif;"><b> </b></span><span style="font-family: Arial,Helvetica,sans-serif;"><br />The sensible way for attaching time zone information to dates in Java is the use of java.util.Calendar. So let's tweak our entity class a bit and add a Calendar field:</span><br />
<table border="0" cellpadding="2" cellspacing="2" style="font-family: Courier New,Courier,monospace; text-align: left; width: 100%;"><tbody>
<tr><td style="background-color: #cccccc;"><span style="font-size: x-small;">@Temporal(TemporalType.TIMESTAMP)<br />@Column(name = "calendartime")<br />private Calendar calendar;</span></td></tr>
</tbody></table>
<br />
<span style="font-family: Arial,Helvetica,sans-serif;">And now we extend our testing code to persist the calendar field, too:</span><br />
<span style="font-family: Arial,Helvetica,sans-serif;"></span><span style="color: #666666; font-family: Arial,Helvetica,sans-serif; font-size: x-small;">String dateStringGMT = "2010-11-09T12:00:00";</span><br />
<span style="color: #666666; font-family: Arial,Helvetica,sans-serif; font-size: x-small;"><span style="color: #38761d;">//Parse the String using GMT time <span style="color: #666666;">schedule</span></span><br />SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");<br />dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));</span><br />
<span style="color: #666666; font-family: Arial,Helvetica,sans-serif; font-size: x-small;">Date date = dateFormat.parse(dateStringGMT);<br />GMTDateEntity entity = new GMTDateEntity();<br />entity.setDate(date);</span><br />
<span style="color: #666666; font-family: Arial,Helvetica,sans-serif; font-size: x-small;"><span style="color: #38761d;">//Create Calendar object in GMT </span></span><br />
<div style="color: #0b5394;">
<span style="font-family: Arial,Helvetica,sans-serif; font-size: x-small;">Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));</span></div>
<span style="color: #666666; font-family: Arial,Helvetica,sans-serif; font-size: x-small;"><span style="color: #0b5394;">cal.setTime(date);</span><br style="color: #0b5394;" /><span style="color: #0b5394;">entity.setCalendar(cal);</span><br />dateTestDao.persistGMTDateEntity(entity);</span><br />
<span style="font-family: Arial,Helvetica,sans-serif;"> </span><br />
<span style="font-family: Arial,Helvetica,sans-serif;">After code execution our DB will look like this:</span><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimOyJ6zN4iorBNeNhboKIDUhysoi_TTfrYPa99ED6ZZn54LPDi1yBE-Mh-MDcLaw1gnmI-F_EMzf1_acgDo2-69NjeB_WxFoi7EOH4P0-A3VkQxpqmi6CMkQPxlJv2Pkhq7kDv6hM526Gz/s1600/02.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimOyJ6zN4iorBNeNhboKIDUhysoi_TTfrYPa99ED6ZZn54LPDi1yBE-Mh-MDcLaw1gnmI-F_EMzf1_acgDo2-69NjeB_WxFoi7EOH4P0-A3VkQxpqmi6CMkQPxlJv2Pkhq7kDv6hM526Gz/s320/02.png" height="39" width="320" /></a></div>
<span style="font-family: Arial,Helvetica,sans-serif;"><br /></span>
<br />
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
As you can see, the <span style="font-family: "Courier New",Courier,monospace;">calendartime </span>column perfectly displays our date in GMT! But still we're not satisfied. To be a little bitchy, we add the following lines to our testing code:<br />
<br />
<span style="color: #666666; font-family: Arial,Helvetica,sans-serif; font-size: x-small;">String dateStringGMT = "2010-11-09T12:00:00";</span><br />
<span style="color: #666666; font-family: Arial,Helvetica,sans-serif; font-size: x-small;"><span style="color: #38761d;">//Parse the String using GMT time <span style="color: #666666;">schedule</span></span><br />SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");<br />dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));</span><br />
<span style="color: #666666; font-family: Arial,Helvetica,sans-serif; font-size: x-small;">Date date = dateFormat.parse(dateStringGMT);<br />GMTDateEntity entity = new GMTDateEntity();<br />entity.setDate(date);</span><br />
<span style="color: #666666; font-family: Arial,Helvetica,sans-serif; font-size: x-small;"><span style="color: #38761d;">//Create Calendar object in GMT </span></span><br />
<div style="color: #666666;">
<span style="font-family: Arial,Helvetica,sans-serif; font-size: x-small;">Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));</span></div>
<span style="color: #666666; font-family: Arial,Helvetica,sans-serif; font-size: x-small;"><span style="background-color: white; color: #0b5394;"></span>cal.setTime(date); </span><br />
<span style="color: #666666; font-family: Arial,Helvetica,sans-serif; font-size: x-small;">entity.setCalendar(cal); <br style="color: #666666;" /> dateTestDao.persistGMTDateEntity(entity);</span><br />
<span style="color: #666666; font-family: Arial,Helvetica,sans-serif; font-size: x-small;"><span style="color: #38761d;">//Now read back what we persisted, and store it again</span> </span><br />
<span style="color: #666666; font-family: Arial,Helvetica,sans-serif; font-size: x-small;"><span style="color: #0b5394;">GMTDateEntity readEntity = dateTestDao.retrieveGMTDateEntity(entity.getPk());</span><br style="color: #0b5394;" /><span style="color: #0b5394;">GMTDateEntity newEntity = new GMTDateEntity();</span><br style="color: #0b5394;" /><span style="color: #38761d;">//just to be sure we set the time zone to GMT again</span><br /><span style="color: #0b5394;">readEntity.getCalendar().setTimeZone(TimeZone.getTimeZone("GMT"));</span><br style="color: #0b5394;" /><span style="color: #0b5394;">newEntity.setCalendar(readEntity.getCalendar());</span><br style="color: #0b5394;" /><span style="color: #0b5394;">newEntity.setDate(readEntity.getCalendar().getTime());</span><br style="color: #0b5394;" /><span style="color: #0b5394;">dateTestDao.persistGMTDateEntity(newEntity);</span><br /> </span><br />
The DB now looks like this:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYSXDTfGxq9HCgYexg-LGH1Ymfd0uVHIoylvDFZ9QA-CYtRXNS9MRy888LyWgm4HWGoyf3IMeX8tZFXSuEz7ObwRILoilYwNj3QO2238x7kO1wybFWTgXPegibaim4q4JFsK0OfShvKjVn/s1600/03.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYSXDTfGxq9HCgYexg-LGH1Ymfd0uVHIoylvDFZ9QA-CYtRXNS9MRy888LyWgm4HWGoyf3IMeX8tZFXSuEz7ObwRILoilYwNj3QO2238x7kO1wybFWTgXPegibaim4q4JFsK0OfShvKjVn/s320/03.png" height="57" width="320" /></a></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br />
<br />
<br />
<br />
<br />
What the hell?! Obviously we got a Calendar out of the DB which is different from the one we previously stored to it! And that's true. When reading from DB, HIbernate creates a completely new Calendar object, and uses the system's time zone again for converting the date.<br />
<br />
<b>3. Obstacle: There are solutions, but it won't be easy! </b><br />
<br />
Well, if you're as naive as I am, you might just shout out: "Of cause it didn't work! We didn't tell HIbernate about the target time zone of our entity class!" And then you would go and tweak the <span style="font-family: "Courier New",Courier,monospace;">GMTDateEntity </span>like this:<br />
<br />
<table border="0" cellpadding="2" cellspacing="2" style="font-family: Courier New,Courier,monospace; text-align: left; width: 100%;"><tbody>
<tr><td style="background-color: #cccccc;"><span style="font-size: x-small;">@Temporal(TemporalType.TIMESTAMP)<br />@Column(name = "calendartime")<br />private Calendar calendar<span style="color: #0b5394;"> = new GregorianCalendar(TimeZone.getTimeZone("GMT"))</span>;</span></td></tr>
</tbody></table>
<br />
<span style="font-family: Arial,Helvetica,sans-serif;">Just to shorten this: It will not work! Hibernate uses Reflection to set the entity's fields, and when it comes to do so, the date conversion is already done. So instead of asking yout entity's field: "What kind of time zone would be welcome, Sir?", it just creates a new Calendar instance in system's time zone and squeezes the DB date into it.</span><br />
<span style="font-family: Arial,Helvetica,sans-serif;"><br /></span>
<span style="font-family: Arial,Helvetica,sans-serif;">However, there are some more complex solutions to this problem, which I will explain in the <a href="http://www.joobik.com/2010/12/mapping-dates-and-time-zones-with.html">second part </a>of this article.</span><br />
<br />
<span style="font-family: Arial,Helvetica,sans-serif;"><a href="http://www.joobik.com/2010/12/mapping-dates-and-time-zones-with.html">Go ahead to part 2 of this article</a> </span><br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.joobikplayer.com/" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;" target="_blank"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0YOn-mWycY4CbxGfFplAX9JP_EnTo5EkX3_SfIE96WHKR3lyST_eKCs7HnjKzY0_z01jjeafGFqT5rE0dOGBlrXW9pSJjXnJVQB2kJAO2vT4cGZNE5Z_PX24S3kJI9gQUSjsNugBcefQk/s1600/Joobik-Banner.png" height="93" width="400" /></a></div>
<br /></div>Anonymoushttp://www.blogger.com/profile/09420743738560302691noreply@blogger.com0tag:blogger.com,1999:blog-8097245354602487605.post-46801116359276022492010-09-18T20:33:00.000+02:002015-04-13T13:28:54.538+02:00PicUpp User Manual<table border="0" cellpadding="2" cellspacing="2" style="margin-left: auto; margin-right: auto; text-align: left; width: 100%;"><tbody>
<tr style="font-family: Helvetica,Arial,sans-serif;">
<td colspan="2" rowspan="1" style="vertical-align: top;"><br />
<h2>
Add new Picasa Account</h2>
</td>
</tr>
<tr>
<td style="font-family: Helvetica,Arial,sans-serif; vertical-align: top;"><img alt="Add Picasa Account" src="http://lh5.ggpht.com/_LocCSiFQhdU/TLSQwFxAfNI/AAAAAAAAAFc/URGLnMwFwi8/01.PNG" style="border: 0px solid; height: 321px; width: 214px;" /></td>
<td style="font-family: Helvetica,Arial,sans-serif; vertical-align: top;">Tap<br />
the [+] button in the upper right corner to open the <i>Add Account</i><br />
view. If no accounts are added, yet, you can even simply tap anywhere<br />
on the screen to bring up this view.</td>
</tr>
<tr>
<td style="vertical-align: top;"><img alt="Enter Picasa Login Name" src="http://lh4.ggpht.com/_LocCSiFQhdU/TLSSn9iIjoI/AAAAAAAAAFk/6ab3YVgZqzs/02.PNG" style="height: 320px; width: 213px;" /></td>
<td style="font-family: Helvetica,Arial,sans-serif; vertical-align: top;">Enter<br />
your Picasa login name. If you want to save your password permanently,<br />
switch on the <i>Save Password</i> switch.</td>
</tr>
<tr>
<td style="vertical-align: top;"><img alt="Enter Picasa Password" src="http://lh4.ggpht.com/_LocCSiFQhdU/TLSSoOJHkdI/AAAAAAAAAFo/sVwZep_a3ro/03.PNG" style="height: 320px; width: 213px;" /></td>
<td style="font-family: Helvetica,Arial,sans-serif; vertical-align: top;">Enter<br />
your password and tap the [Save] button. Your password is saved<br />
securely in the iPhone keychain.</td>
</tr>
<tr style="font-family: Helvetica,Arial,sans-serif;">
<td colspan="2" rowspan="1" style="vertical-align: top;"><br />
<h2>
Delete Picasa Account</h2>
</td>
</tr>
<tr>
<td style="vertical-align: top;"><img alt="Delete Picasa Account" src="http://lh4.ggpht.com/_LocCSiFQhdU/TLSSodYOOvI/AAAAAAAAAFs/dni6R1xyn2Y/04.PNG" style="height: 320px; width: 213px;" /></td>
<td style="font-family: Helvetica,Arial,sans-serif; vertical-align: top;">Tap<br />
the [Edit] button or swipe over an account horizontally to delete it.</td>
</tr>
<tr style="font-family: Helvetica,Arial,sans-serif;">
<td colspan="2" rowspan="1" style="vertical-align: top;"><br />
<h2>
Edit Picasa Account</h2>
</td>
</tr>
<tr>
<td style="vertical-align: top;"><img alt="Edit Picasa Account" src="http://lh4.ggpht.com/_LocCSiFQhdU/TLSSoiqN3II/AAAAAAAAAFw/vdAlMbm5vV0/05.png" style="height: 320px; width: 213px;" /></td>
<td style="font-family: Helvetica,Arial,sans-serif; vertical-align: top;">Tap<br />
the disclosure button to the right of an account to open the<i> Edit<br />
Account </i>view.</td>
</tr>
<tr style="font-family: Helvetica,Arial,sans-serif;">
<td colspan="2" rowspan="1" style="vertical-align: top;"><br />
<h2>
Use Picasa Account for Upload</h2>
</td>
</tr>
<tr>
<td style="vertical-align: top;"><img alt="Use Picasa Account for Upload" src="http://lh4.ggpht.com/_LocCSiFQhdU/TLSSo0qA5zI/AAAAAAAAAF0/lh88TOG3bFg/06.png" style="height: 320px; width: 213px;" /></td>
<td style="font-family: Helvetica,Arial,sans-serif; vertical-align: top;">Tap<br />
somewhere on the account name to select it for upload and open the <i>Upload<br />
Queue</i> view.</td>
</tr>
<tr style="font-family: Helvetica,Arial,sans-serif;">
<td colspan="2" rowspan="1" style="vertical-align: top;"><br />
<h2>
Add Photos to Upload Queue</h2>
</td>
</tr>
<tr>
<td style="vertical-align: top;"><img alt="Add photos" src="http://lh4.ggpht.com/_LocCSiFQhdU/TLSViRbe7rI/AAAAAAAAAF8/FtQ2yF2FyOk/07.PNG" style="height: 320px; width: 213px;" /></td>
<td style="vertical-align: top;"><span style="font-family: Helvetica,Arial,sans-serif;">Tap the [+] button in<br />
upper right corner to bring up the image selector. If there are no<br />
images in the upload queue, yet, you can even simply tap somewhere on<br />
the screen to bring up the<br />
photo picker.</span></td>
</tr>
<tr>
<td style="vertical-align: top;"><img alt="Choose photo ot image" src="http://lh5.ggpht.com/_LocCSiFQhdU/TLSVih2SDMI/AAAAAAAAAGA/pFdE2yh-ocs/08.PNG" style="height: 320px; width: 213px;" /><br />
<br /></td>
<td style="vertical-align: top;"><span style="font-family: Helvetica,Arial,sans-serif;">Choose the<br />
photo/image you want to upload from the photo picker.</span><br />
<br /></td>
</tr>
<tr>
<td style="vertical-align: top;"><img alt="Enter photo caption" src="http://lh4.ggpht.com/_LocCSiFQhdU/TLSVjd32ApI/AAAAAAAAAGE/YIpBhKAEz94/09.PNG" style="height: 320px; width: 213px;" /></td>
<td style="vertical-align: top;"><span style="font-family: Helvetica,Arial,sans-serif;">Once you selected a<br />
photo from the photo picker, you can enter a photo caption and then tap<br />
the [Add to upload Queue] button. </span><span style="font-family: Helvetica,Arial,sans-serif;"></span><span style="font-family: Helvetica,Arial,sans-serif;"></span></td>
</tr>
<tr>
<td style="vertical-align: top;"><img alt="Finished adding photos to PicUpp queue" src="http://lh5.ggpht.com/_LocCSiFQhdU/TLSVj1EZeNI/AAAAAAAAAGI/Pey0on2qKyk/10.PNG" style="height: 320px; width: 213px;" /><br />
<br /></td>
<td style="vertical-align: top;"><span style="font-family: Helvetica,Arial,sans-serif;">When<br />
you're finished adding all desired photos to the upload queue, tap the<br />
[Done]<br />
button in the upper right corner of the photo picker.</span> <span style="font-family: Helvetica,Arial,sans-serif;">You can<br />
add a maximum of 20 photos to the upload queue.</span></td>
</tr>
<tr style="font-family: Helvetica,Arial,sans-serif;">
<td colspan="2" rowspan="1" style="vertical-align: top;"><br />
<h2>
Remove a Photo from Upload Queue</h2>
</td>
</tr>
<tr>
<td style="vertical-align: top;"><img alt="Remove a photo from PicUpp queue" src="http://lh6.ggpht.com/_LocCSiFQhdU/TLSVkWZk2JI/AAAAAAAAAGM/eFvSL_6dMeI/11.PNG" style="height: 321px; width: 214px;" /></td>
<td style="vertical-align: top;"><span style="font-family: Helvetica,Arial,sans-serif;">Swipe over a photo </span><span style="font-family: Helvetica,Arial,sans-serif;">horizontally </span><span style="font-family: Helvetica,Arial,sans-serif;">to reveal the<br />
[Delete] button.</span></td>
</tr>
<tr style="font-family: Helvetica,Arial,sans-serif;">
<td colspan="2" rowspan="1" style="vertical-align: top;"><br />
<h2>
Select Picasa Album to upload to</h2>
</td>
</tr>
<tr>
<td style="vertical-align: top;"><img alt="Tap select album button" src="http://lh5.ggpht.com/_LocCSiFQhdU/TLSYD49VReI/AAAAAAAAAGU/TFKk_Ao_YF0/12.PNG" style="height: 320px; width: 213px;" /></td>
<td style="vertical-align: top;"><span style="font-family: Helvetica,Arial,sans-serif;">Tap the [Select<br />
Album] button to bring up the Picasa Albums Selector. This is the time<br />
when the app connects to Picasa and tries to log you in. All previous<br />
steps you could even execute without an internet connection. </span></td>
</tr>
<tr>
<td style="vertical-align: top;"><img alt="Enter Picasa password" src="http://lh5.ggpht.com/_LocCSiFQhdU/TLSYEITAgmI/AAAAAAAAAGY/t_p6ck9ckYM/13.PNG" style="height: 320px; width: 213px;" /><br />
<br /></td>
<td style="vertical-align: top;"><span style="font-family: Helvetica,Arial,sans-serif;">If you did not<br />
save your account password, PicUpp will ask you to enter it here.</span></td>
</tr>
<tr>
<td style="vertical-align: top;"><img alt="Select Picasa album" src="http://lh3.ggpht.com/_LocCSiFQhdU/TLSYEQfdGII/AAAAAAAAAGc/IGGs-YgAGX0/14.PNG" style="height: 320px; width: 213px;" /></td>
<td style="font-family: Helvetica,Arial,sans-serif; vertical-align: top;">On<br />
the Picasa Album Selector, use the picker wheel to select the album you<br />
want to upload your photos to. If you'd like to use a new album<br />
instead, enter the new album name in the textfield at the bottom. The<br />
new album will be created as a private album.<br />
To confirm album selection or creation, tap the [Select Album] button. </td>
</tr>
<tr style="font-family: Helvetica,Arial,sans-serif;">
<td colspan="2" rowspan="1" style="vertical-align: top;"><br />
<h2>
Upload your photos </h2>
</td>
</tr>
<tr>
<td style="vertical-align: top;"><img alt="Tap Launch Upload button" src="http://lh3.ggpht.com/_LocCSiFQhdU/TLSYEmWESDI/AAAAAAAAAGg/FJxZ45gHZuI/15.PNG" style="height: 320px; width: 213px;" /></td>
<td style="vertical-align: top;"><span style="font-family: Helvetica,Arial,sans-serif;">Once you added<br />
photos, and selected the Picasa album, the [Launch Uppload!] button<br />
appears. Tap it to start uploading the photos.</span></td>
</tr>
<tr>
<td style="vertical-align: top;"><img alt="Photo uploading to Picasa" src="http://lh3.ggpht.com/_LocCSiFQhdU/TLSYFM_iRqI/AAAAAAAAAGk/YigEKiX2VuE/16.PNG" style="height: 320px; width: 213px;" /></td>
<td style="vertical-align: top;"><span style="font-family: Helvetica,Arial,sans-serif;">The photo currently<br />
uploading is displayed on the upload screen. If you want to cancel the<br />
upload, tap the [Cancel Uppload] button.</span></td></tr>
</tbody>
</table>
<br />
<br />
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.joobikplayer.com/" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;" target="_blank"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0YOn-mWycY4CbxGfFplAX9JP_EnTo5EkX3_SfIE96WHKR3lyST_eKCs7HnjKzY0_z01jjeafGFqT5rE0dOGBlrXW9pSJjXnJVQB2kJAO2vT4cGZNE5Z_PX24S3kJI9gQUSjsNugBcefQk/s1600/Joobik-Banner.png" height="93" width="400" /></a></div>
<br />joobikhttp://www.blogger.com/profile/09390437095051380351noreply@blogger.com2tag:blogger.com,1999:blog-8097245354602487605.post-88108932008255654122010-08-14T22:01:00.000+02:002015-04-28T09:28:14.153+02:00Howto use the Keychain in iPhone SDK to store and retrieve secure Data<div style="font-family: Arial,Helvetica,sans-serif;">
When you need to store data securely from within your iPhone application, sooner or later you will step over the iPhone keychain. This is the super-duper built-in iPhone safe, kindly provided to you by the fruit company.</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
Now - take your time to praise Apple for being so wise and foresighted to supply you with the cooked equipment for secure data storage...</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
..did you do well? Did you rag on some dump Windows users? Fine, then here is one more thing: The stuff ain't that simple to use. Of course, as a blessed Apple user you would expect a simple interface in the fashion of "[keychain getMySecretData] [keychain storeMySecretData]". But when you take a closer look at it you will find that it is rather half-baked - and implementing keychain access might take a little more than a one-buttoned mouse.</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
First of all, there ain't an easy-to-use keychain API in any of the frameworks delivered with the iPhone SDK. You would have to deal with weird C function calls. For instance, to retrieve data from the keychain you have to invoke something called <span style="font-family: 'Courier New', Courier, monospace;">SecItemCopyMatching</span>, passing in a dictionary as parameter. Completely self explanatory, isn't it? If you're getting curious, you can dive into the secrets of keychain services <a href="http://developer.apple.com/iphone/library/documentation/Security/Conceptual/keychainServConcepts/01introduction/introduction.html">here</a>. Though in this programming guide the Apple guys are not getting bored emphasizing the straightforwardness and ease of use of the keychain API - there seems to be a little doubt, though. Cause in the code examples accompanying the guidelines, they build an object-oriented wrapper class around all this cute C-function magic. And this is where we join the game..</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
The complete example application provided by Apple can be found <a href="http://developer.apple.com/iphone/library/samplecode/GenericKeychain/Introduction/Intro.html">here</a>. But the only thing of interest to us is the <a href="http://developer.apple.com/iphone/library/samplecode/GenericKeychain/Listings/Classes_KeychainItemWrapper_m.html#//apple_ref/doc/uid/DTS40007797-Classes_KeychainItemWrapper_m-DontLinkElementID_10" style="font-family: "Courier New",Courier,monospace;">KeyChainItemWrapper</a>. You can think of a keychain item as a record stored in the keychain database. Each keychain item consists of unencrypted attributes, and the actual data, which is encrypted. For instance, a password keychain item could have the account name set as one of its attributes, and the password itself be stored as keychain item data. Apple defines these types (aka classes) of keychain items:</div>
<ul style="font-family: Arial,Helvetica,sans-serif;">
<li>Generic Password</li>
<li>Internet Password</li>
<li>Certificate</li>
<li>Cryptographic Key</li>
<li>Digital Identity</li>
</ul>
<div style="font-family: Arial,Helvetica,sans-serif;">
Keychain item classes differ in the attributes and structure of item data.</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
The <span style="font-family: 'Courier New', Courier, monospace;">KeyChainItemWrapper</span> is a kind of object-oriented wrapper around a Generic Password keychain item, providing methods for item creation and modification:</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: "Courier New",Courier,monospace;">
<b>- (id)initWithIdentifier: (NSString *)identifier accessGroup:(NSString *) accessGroup</b><br />
<br />
<div style="font-family: Arial,Helvetica,sans-serif;">
Creates a Generic Password keychain item. If an item with provided identifier is already stored in the keychain data base, it will load its data. If not, it will create a new one and initialize it with empty strings. The identifier should be a string identifying the account the password stored in the keychain item belongs to.</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
The access group can be used to share the keychain item among different applications. So in most cases, you will not need it, and it can be set to <span style="font-family: 'Courier New', Courier, monospace;">nil</span>.</div>
<div style="font-family: "Courier New",Courier,monospace;">
<b><br /></b></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<b><span style="font-family: 'Courier New', Courier, monospace;">- (void)setObject:(id)inObject forKey:(id)key</span></b></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-family: Arial, Helvetica, sans-serif;">Depending on the value you provide for <span style="font-family: 'Courier New', Courier, monospace;">key</span>, it stores the</span></span><span style="font-family: 'Courier New', Courier, monospace;"><span style="font-family: Arial, Helvetica, sans-serif;"> <span style="font-family: 'Courier New', Courier, monospace;">inObject</span> as keychain item attribute, or encrypted keychain item data.</span></span><span style="font-family: Arial, Helvetica, sans-serif;"> To gain reasonable results, you MUST use the <a href="http://developer.apple.com/iphone/library/documentation/Security/Reference/keychainservices/Reference/reference.html#//apple_ref/doc/uid/TP30000898-CH4g-TPXREF119">constants defined in the keychain services API</a> for the <span style="font-family: 'Courier New', Courier, monospace;">key</span>. For example, to store an ecrypted password, <a href="http://developer.apple.com/iphone/library/documentation/Security/Reference/keychainservices/Reference/reference.html#//apple_ref/doc/c_ref/kSecValueData" style="font-family: "Courier New",Courier,monospace;">kSecValueData</a> must be the key, and the actual password must be the <span style="font-family: 'Courier New', Courier, monospace;">inObject</span>. To store a login name as keychain item attribute, use <span style="font-family: 'Courier New', Courier, monospace;">kSecAttrAccount</span> for key, and the login name for <span style="font-family: 'Courier New', Courier, monospace;">inObject</span>.</span></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<span style="font-family: Arial, Helvetica, sans-serif;">No later than here you recognize, that even the "object-oriented" </span><span style="font-family: 'Courier New', Courier, monospace;">KeyChainItemWrapper<span style="font-family: Arial, Helvetica, sans-serif;"> is not object-oriented, but at most "objective". In a serious object-oriented language, they would have given us methods like [keyChainItem setPassword] and [keyChainItem setAccount]. In reality, we have to tell what we want by passing cryptic constants to generic methods. Well, you will have to get used to it: It's the Apple guys - they don't care about user requirements, they define them themselves.</span></span></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<span style="font-family: 'Courier New', Courier, monospace;"><b style="font-family: "Courier New",Courier,monospace;">- (id)objectForKey:(id)key </b></span></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<span style="font-family: Arial, Helvetica, sans-serif;">Get an attribute or data out of the keychain. Just as mentioned in the previous section, you will have to use the pre-defined keychain services API <a href="http://developer.apple.com/iphone/library/documentation/Security/Reference/keychainservices/Reference/reference.html#//apple_ref/doc/uid/TP30000898-CH4g-TPXREF119">constants</a> for </span><span style="font-family: 'Courier New', Courier, monospace;">key</span>.</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<b><span style="font-family: 'Courier New', Courier, monospace;">- (void)resetKeychainItem</span></b></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<span style="font-family: Arial, Helvetica, sans-serif;">Delete all attributes and data of the keychain item, and initialize them with empty strings. Note: This does not delete the keychain item itself! Deleting a keychain item is not implemented in the Apple example.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"> </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">Here is a small code example of how to write to and read from the keychain:</span><br />
<br />
<table border="0" cellpadding="2" cellspacing="2" style="background-color: #cccccc; font-family: "Courier New",Courier,monospace; margin-left: auto; margin-right: auto; text-align: left; width: 100%;"><tbody>
<tr> <td style="background-color: #cccccc; vertical-align: top;">- (void) savePassword: (NSString*) password {<br />
[self.keychainItemWrapper setObject:password forKey:<br />
(id)kSecValueData];<br />
}<br />
<br />
<div style="font-family: "Courier New",Courier,monospace;">
- (void) retrievePassword {</div>
<span style="font-family: 'Courier New', Courier, monospace;"> return (NSString*) [self.keychainItemWrapper objectForKey:</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> (id)kSecValueData];</span><br />
}</td> </tr>
</tbody> </table>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: #999999; font-family: 'Courier New', Courier, monospace;"></span><br /></span></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div>
<br />
<center>
<script type="text/javascript" language="javascript">
amzn_assoc_ad_type = "contextual";
amzn_assoc_tracking_id = "joobikcom-20";
amzn_assoc_marketplace = "amazon";
amzn_assoc_region = "US";
amzn_assoc_placement = "OUMA5OFNJ6UHSOXF";
amzn_assoc_linkid = "OUMA5OFNJ6UHSOXF";
amzn_assoc_emphasize_categories = "13900861, 2335752011, 13900871, 130, 172282, 979455011, 195209011, 301668, 229534, 468642, 377110011";
amzn_assoc_fallback_products = "";
amzn_assoc_width = "300";
amzn_assoc_height = "250";
</script>
<script type="text/javascript" language="javascript" src="//z-na.amazon-adsystem.com/widgets/q?ServiceVersion=20070822&Operation=GetScript&ID=OneJS&WS=1&MarketPlace=US&source=ac"></script>
</center>
<br />
</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<span style="font-family: Arial, Helvetica, sans-serif;">Well, now you should be equipped with the basic knowledge to integrate a secure, keychain-based password storage into your iPhone application. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"></span><br />
<b><span style="font-family: Arial, Helvetica, sans-serif;">Don't forget to add the </span><i>Security.framework</i> to your Xcode project if you want to use the <span style="font-family: 'Courier New', Courier, monospace;">KeyChainItemWrapper!</span></b><br />
<br />
<span style="font-family: Arial, Helvetica, sans-serif;">One important thing to mention is, that with the latest version 1.2, the </span><span style="font-family: 'Courier New', Courier, monospace;">KeyChainItemWrapper<span style="font-family: Arial, Helvetica, sans-serif;"> also works on the iPhone simulator. In prior versions it did not.</span></span><span style="font-family: 'Courier New', Courier, monospace;"><span style="font-family: Arial, Helvetica, sans-serif;"> The programmers just forgot to mention this in the <a href="http://developer.apple.com/iphone/library/samplecode/GenericKeychain/History/History.html#//apple_ref/doc/uid/DTS40007797-RevisionHistory-DontLinkElementID_1">revision history</a>. </span></span><span style="font-family: 'Courier New', Courier, monospace;"><span style="font-family: Arial, Helvetica, sans-serif;"> The only thing you cannot use on the simulator is the ability to share keychain items among different applications using an accessGroup. </span></span></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<span style="font-family: 'Courier New', Courier, monospace;"><span style="font-family: Arial, Helvetica, sans-serif;">I think, you'll get over it..</span></span><span style="font-family: Arial, Helvetica, sans-serif;"> </span></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br />
You can find a very good, more detailed overview of the keychain API in <a href="http://useyourloaf.com/blog/2010/3/29/simple-iphone-keychain-access.html">this</a> blog post.</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
</div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<br /></div>
<div style="font-family: Arial,Helvetica,sans-serif;">
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.joobikplayer.com/" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;" target="_blank"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0YOn-mWycY4CbxGfFplAX9JP_EnTo5EkX3_SfIE96WHKR3lyST_eKCs7HnjKzY0_z01jjeafGFqT5rE0dOGBlrXW9pSJjXnJVQB2kJAO2vT4cGZNE5Z_PX24S3kJI9gQUSjsNugBcefQk/s1600/Joobik-Banner.png" height="93" width="400" /></a></div>
<br /></div>Anonymoushttp://www.blogger.com/profile/09420743738560302691noreply@blogger.com4